[
  {
    "path": ".agent/rules/coding.md",
    "content": "---\ntrigger: always_on\n---\n\n# Instructions\n\n- Use only scripts from `package.json` to run commands.\n- Use `npm run build` to run tsc and test build.\n- Use `npm run test` to build and run tests, run all tests to verify correctness.\n- Use `npm run test path-to-test.ts` to build and run a single test file, for example, `npm run test tests/McpContext.test.ts`.\n- Use `npm run format` to fix formatting and get linting errors.\n\n## Rules for TypeScript\n\n- Do not use `any` type.\n- Do not use `as` keyword for type casting.\n- Do not use `!` operator for type assertion.\n- Do not use `// @ts-ignore` comments.\n- Do not use `// @ts-nocheck` comments.\n- Do not use `// @ts-expect-error` comments.\n- Prefer `for..of` instead of `forEach`.\n"
  },
  {
    "path": ".claude-plugin/marketplace.json",
    "content": "{\n  \"name\": \"chrome-devtools-plugins\",\n  \"version\": \"1.0.0\",\n  \"description\": \"Bundled plugins for actuating and debugging the Chrome browser.\",\n  \"owner\": {\n    \"name\": \"Chrome DevTools Team\",\n    \"email\": \"devtools-dev@chromium.org\"\n  },\n  \"plugins\": [\n    {\n      \"name\": \"chrome-devtools-mcp\",\n      \"source\": \"./\",\n      \"description\": \"Reliable automation, in-depth debugging, and performance analysis in Chrome using Chrome DevTools and Puppeteer\"\n    }\n  ]\n}\n"
  },
  {
    "path": ".claude-plugin/plugin.json",
    "content": "{\n  \"name\": \"chrome-devtools-mcp\",\n  \"version\": \"latest\",\n  \"description\": \"Reliable automation, in-depth debugging, and performance analysis in Chrome using Chrome DevTools and Puppeteer\",\n  \"mcpServers\": {\n    \"chrome-devtools\": {\n      \"command\": \"npx\",\n      \"args\": [\"chrome-devtools-mcp@latest\"]\n    }\n  }\n}\n"
  },
  {
    "path": ".gitattributes",
    "content": "* text=auto eol=lf\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/01-bug.yml",
    "content": "name: Bug report\ndescription: File a bug report for chrome-devtools-mcp\ntitle: '<short description of the bug>'\ntype: 'Bug'\nbody:\n  - id: description\n    type: textarea\n    attributes:\n      label: Description of the bug\n      description: >\n        A clear and concise description of what the bug is.\n      placeholder:\n    validations:\n      required: true\n\n  - id: reproduce\n    type: textarea\n    attributes:\n      label: Reproduction\n      description: >\n        Steps to reproduce the behavior:\n      placeholder: |\n        1. Use tool '...'\n        2. Then use tool '...'\n\n  - id: expectation\n    type: textarea\n    attributes:\n      label: Expectation\n      description: A clear and concise description of what you expected to happen.\n\n  - id: mcp-configuration\n    type: textarea\n    attributes:\n      label: MCP configuration\n\n  - id: chrome-devtools-mcp-version\n    type: input\n    attributes:\n      label: Chrome DevTools MCP version\n    validations:\n      required: true\n\n  - id: chrome-version\n    type: input\n    attributes:\n      label: Chrome version\n\n  - id: coding-agent-version\n    type: input\n    attributes:\n      label: Coding agent version\n\n  - id: model-version\n    type: input\n    attributes:\n      label: Model version\n\n  - id: chat-log\n    type: input\n    attributes:\n      label: Chat log\n\n  - id: node-version\n    type: input\n    attributes:\n      label: Node version\n      description: >\n        Please verify you have the minimal supported version listed in the README.md\n\n  - id: operating-system\n    type: dropdown\n    attributes:\n      label: Operating system\n      description: What supported operating system are you running?\n      options:\n        - Windows\n        - Windows Subsystem for Linux (WSL)\n        - macOS\n        - Linux\n\n  - type: checkboxes\n    id: provide-pr\n    attributes:\n      label: Extra checklist\n      options:\n        - label: I want to provide a PR to fix this bug\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/02-feature.yml",
    "content": "name: Feature\ndescription: Suggest an idea for for chrome-devtools-mcp\ntitle: '<short description of the feature request>'\ntype: 'Feature'\nlabels:\n  - feature\nbody:\n  - id: description\n    type: textarea\n    attributes:\n      label: Is your feature request related to a problem? Please describe.\n      description: >\n        A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]\n      placeholder:\n    validations:\n      required: true\n\n  - id: solution\n    type: textarea\n    attributes:\n      label: Describe the solution you'd like\n      description: >\n        A clear and concise description of what you want to happen.\n      placeholder:\n    validations:\n      required: true\n\n  - id: alternatives\n    type: textarea\n    attributes:\n      label: Describe alternatives you've considered\n      description: >\n        A clear and concise description of any alternative solutions or features you've considered.\n      placeholder:\n    validations:\n      required: true\n\n  - id: additional-context\n    type: textarea\n    attributes:\n      label: Additional context\n      description: >\n        Add any other context or screenshots about the feature request here.\n      placeholder:\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/03-task.yml",
    "content": "name: Task\ndescription: Work tracking for mainainers only!\ntitle: '[Task]:'\ntype: 'Task'\nbody:\n  - type: markdown\n    attributes:\n      value: |\n        ### This issue type should be used only by mainainers!\n        Task are to track small non user facing issue or improvements. \n        The issue will be closed if it does not follow those rules.\n  - type: textarea\n    attributes:\n      label: 'Task to do:'\n    id: task\n    validations:\n      required: true\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/config.yml",
    "content": "blank_issues_enabled: false\n"
  },
  {
    "path": ".github/dependabot.yml",
    "content": "version: 2\nupdates:\n  - package-ecosystem: npm\n    directory: /\n    schedule:\n      interval: weekly\n      day: 'sunday'\n      time: '02:00'\n      timezone: Europe/Berlin\n    groups:\n      dependencies:\n        dependency-type: production\n        patterns:\n          - '*'\n      dev-dependencies:\n        dependency-type: development\n        exclude-patterns:\n          - 'puppeteer*'\n          - 'chrome-devtools-frontend'\n          - '@modelcontextprotocol/sdk'\n          - 'yargs'\n          - 'debug'\n          - 'core-js'\n        patterns:\n          - '*'\n      # breaks often so better to roll separetely.\n      bundled-devtools:\n        patterns:\n          - 'chrome-devtools-frontend'\n      bundled:\n        patterns:\n          - 'puppeteer*'\n          - '@modelcontextprotocol/sdk'\n          - 'yargs'\n          - 'debug'\n          - 'core-js'\n  - package-ecosystem: github-actions\n    directory: /\n    schedule:\n      interval: weekly\n      day: 'sunday'\n      time: '04:00'\n      timezone: Europe/Berlin\n    groups:\n      all:\n        patterns:\n          - '*'\n"
  },
  {
    "path": ".github/workflows/conventional-commit.yml",
    "content": "name: 'Conventional Commit'\n\non:\n  merge_group:\n  pull_request_target:\n    types:\n      # Defaults\n      # https://docs.github.com/en/actions/reference/workflows-and-actions/events-that-trigger-workflows#pull_request_target\n      - opened\n      - reopened\n      - synchronize\n      # Tracks editing PR title or description, or base branch changes\n      # https://docs.github.com/en/webhooks/webhook-events-and-payloads?actionType=edited#pull_request\n      - edited\n\njobs:\n  main:\n    name: '[Required] Validate PR title'\n    runs-on: ubuntu-latest\n    permissions:\n      pull-requests: read\n    steps:\n      - if: github.event_name != 'merge_group'\n        uses: amannn/action-semantic-pull-request@48f256284bd46cdaab1048c3721360e808335d50 # v6.1.1\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n"
  },
  {
    "path": ".github/workflows/pre-release.yml",
    "content": "name: Pre-release\n\npermissions: read-all\n\non:\n  workflow_dispatch:\n  push:\n    branches:\n      - release-please-*\n\njobs:\n  pre-release:\n    name: 'Verify artifacts before release'\n    runs-on: ubuntu-latest\n    steps:\n      - name: Check out repository\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2\n        with:\n          fetch-depth: 2\n\n      - name: Set up Node.js\n        uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0\n        with:\n          cache: npm\n          node-version-file: '.nvmrc'\n          registry-url: 'https://registry.npmjs.org'\n\n      # Ensure npm 11.5.1 or later is installed\n      - name: Update npm\n        run: npm install -g npm@latest\n\n      - name: Install dependencies\n        run: npm ci\n\n      - name: Build and bundle\n        run: npm run bundle\n        env:\n          NODE_ENV: 'production'\n\n      - name: Verify server.json\n        run: npm run verify-server-json-version\n\n      - name: Verify npm package\n        run: npm run verify-npm-package\n"
  },
  {
    "path": ".github/workflows/presubmit.yml",
    "content": "name: Check code before submitting\n\npermissions: read-all\n\non:\n  merge_group:\n  push:\n    branches:\n      - main\n  pull_request:\n\njobs:\n  check-format:\n    name: '[Required] Check correct format'\n    runs-on: ubuntu-latest\n\n    steps:\n      - name: Check out repository\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2\n        with:\n          fetch-depth: 2\n\n      - name: Set up Node.js\n        uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0\n        with:\n          cache: npm\n          node-version-file: '.nvmrc'\n\n      - name: Install dependencies\n        run: npm ci\n\n      - name: Run format check\n        run: npm run check-format\n\n  check-docs:\n    name: '[Required] Check docs updated'\n    runs-on: ubuntu-latest\n\n    steps:\n      - name: Check out repository\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2\n        with:\n          fetch-depth: 2\n\n      - name: Set up Node.js\n        uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0\n        with:\n          cache: npm\n          node-version-file: '.nvmrc'\n\n      - name: Install dependencies\n        run: npm ci\n\n      - name: Generate\n        run: npm run gen\n\n      - name: Check if autogenerated code and docs are out of date\n        run: |\n          diff_file=$(mktemp doc_diff_XXXXXX)\n          git diff --color > $diff_file\n          if [[ -s $diff_file ]]; then\n            echo \"Please update the documentation by running 'npm run gen'. The following was the diff\"\n            cat $diff_file\n            rm $diff_file\n            exit 1\n          fi\n          rm $diff_file\n"
  },
  {
    "path": ".github/workflows/publish-to-npm-on-tag.yml",
    "content": "name: publish-on-tag\n\non:\n  push:\n    tags:\n      - 'chrome-devtools-mcp-v*'\n  workflow_dispatch:\n    inputs:\n      npm-publish:\n        description: 'Try to publish to NPM'\n        default: false\n        type: boolean\n      mcp-publish:\n        description: 'Try to publish to MCP registry'\n        default: true\n        type: boolean\n\npermissions:\n  id-token: write # Required for OIDC\n  contents: read\n\njobs:\n  publish-to-npm:\n    runs-on: ubuntu-latest\n    if: ${{ (github.event_name != 'workflow_dispatch') || (inputs.npm-publish && always()) }}\n    steps:\n      - name: Check out repository\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2\n        with:\n          fetch-depth: 2\n\n      - name: Set up Node.js\n        uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0\n        with:\n          cache: npm\n          node-version-file: '.nvmrc'\n          registry-url: 'https://registry.npmjs.org'\n\n      # Ensure npm 11.5.1 or later is installed\n      - name: Update npm\n        run: npm install -g npm@latest\n\n      - name: Install dependencies\n        run: npm ci\n\n      - name: Build and bundle\n        run: npm run bundle\n        env:\n          NODE_ENV: 'production'\n\n      - name: Publish\n        run: |\n          npm publish --provenance --access public\n\n  publish-to-mcp-registry:\n    runs-on: ubuntu-latest\n    needs: publish-to-npm\n    if: ${{ (github.event_name != 'workflow_dispatch' && needs.publish-to-npm.result == 'success') || (inputs.mcp-publish && always()) }}\n    steps:\n      - name: Check out repository\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2\n        with:\n          fetch-depth: 2\n\n      - name: Set up Node.js\n        uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0\n        with:\n          cache: npm\n          node-version-file: '.nvmrc'\n          registry-url: 'https://registry.npmjs.org'\n\n      # Ensure npm 11.5.1 or later is installed\n      - name: Update npm\n        run: npm install -g npm@latest\n\n      - name: Install dependencies\n        run: npm ci\n\n      - name: Build and bundle\n        run: npm run bundle\n        env:\n          NODE_ENV: 'production'\n\n      - name: Install MCP Publisher\n        run: |\n          export OS=$(uname -s | tr '[:upper:]' '[:lower:]')_$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/')\n          curl -L \"https://github.com/modelcontextprotocol/registry/releases/latest/download/mcp-publisher_${OS}.tar.gz\" | tar xz mcp-publisher\n\n      - name: Login to MCP Registry\n        run: ./mcp-publisher login github-oidc\n\n      - name: Publish to MCP Registry\n        run: ./mcp-publisher publish\n"
  },
  {
    "path": ".github/workflows/release-please.yml",
    "content": "on:\n  push:\n    branches:\n      - main\n\npermissions: read-all\nname: release-please\n\njobs:\n  release-please:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: googleapis/release-please-action@v4\n        with:\n          token: ${{ secrets.BROWSER_AUTOMATION_BOT_TOKEN }}\n          target-branch: main\n          config-file: release-please-config.json\n          manifest-file: .release-please-manifest.json\n"
  },
  {
    "path": ".github/workflows/run-tests.yml",
    "content": "name: Compile and run tests\n\npermissions: read-all\n\non:\n  merge_group:\n  push:\n    branches:\n      - main\n  pull_request:\n\njobs:\n  run-tests:\n    name: Tests on ${{ matrix.os }} with node ${{ matrix.node }}\n    runs-on: ${{ matrix.os }}\n    strategy:\n      fail-fast: false\n      matrix:\n        os:\n          - ubuntu-latest\n          - windows-latest\n          - macos-latest\n        node:\n          - 20\n          - 22\n          - 23\n          - 24\n    steps:\n      - name: Check out repository\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2\n        with:\n          fetch-depth: 2\n\n      - name: Set up Node.js\n        uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0\n        with:\n          cache: npm\n          node-version: 22 # build works only with 22+.\n\n      - name: Install dependencies\n        shell: bash\n        run: npm ci\n\n      - name: Build\n        run: npm run bundle\n        env:\n          NODE_OPTIONS: '--max_old_space_size=4096'\n\n      - name: Set up Node.js\n        uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0\n        with:\n          cache: npm\n          node-version: ${{ matrix.node }}\n\n      - name: Disable AppArmor\n        if: ${{ matrix.os == 'ubuntu-latest' }}\n        shell: bash\n        run: echo 0 | sudo tee /proc/sys/kernel/apparmor_restrict_unprivileged_userns\n\n      - name: Run tests\n        shell: bash\n        # Retry tests if they fail in the merge queue.\n        run: npm run test:no-build -- ${{ github.event_name == 'merge_group' && '--retry' || '' }}\n\n  # Gating job for branch protection.\n  test-success:\n    name: '[Required] Tests passed'\n    runs-on: ubuntu-latest\n    needs: run-tests\n    if: ${{ !cancelled() }}\n    steps:\n      - if: ${{ needs.run-tests.result != 'success' }}\n        run: 'exit 1'\n      - run: 'exit 0'\n"
  },
  {
    "path": ".gitignore",
    "content": "# Logs\nlogs\n*.log\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\nlerna-debug.log*\n.pnpm-debug.log*\n\ntrace.json\ntrace.json.gz\n\n# Diagnostic reports (https://nodejs.org/api/report.html)\nreport.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json\n\n# Runtime data\npids\n*.pid\n*.seed\n*.pid.lock\n\n# Directory for instrumented libs generated by jscoverage/JSCover\nlib-cov\n\n# Coverage directory used by tools like istanbul\ncoverage\n*.lcov\n\n# nyc test coverage\n.nyc_output\n\n# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)\n.grunt\n\n# Bower dependency directory (https://bower.io/)\nbower_components\n\n# node-waf configuration\n.lock-wscript\n\n# Compiled binary addons (https://nodejs.org/api/addons.html)\nbuild/Release\n\n# Dependency directories\nnode_modules/\njspm_packages/\n\n# Snowpack dependency directory (https://snowpack.dev/)\nweb_modules/\n\n# TypeScript cache\n*.tsbuildinfo\n\n# Optional npm cache directory\n.npm\n\n# Optional eslint cache\n.eslintcache\n\n# Optional stylelint cache\n.stylelintcache\n\n# Microbundle cache\n.rpt2_cache/\n.rts2_cache_cjs/\n.rts2_cache_es/\n.rts2_cache_umd/\n\n# Optional REPL history\n.node_repl_history\n\n# Output of 'npm pack'\n*.tgz\n\n# Yarn Integrity file\n.yarn-integrity\n\n# dotenv environment variable files\n.env\n.env.development.local\n.env.test.local\n.env.production.local\n.env.local\n\n# parcel-bundler cache (https://parceljs.org/)\n.cache\n.parcel-cache\n\n# Next.js build output\n.next\nout\n\n# Nuxt.js build / generate output\n.nuxt\ndist\n\n# Gatsby files\n.cache/\n# Comment in the public line in if your project uses Gatsby and not Next.js\n# https://nextjs.org/blog/next-9-1#public-directory-support\n# public\n\n# vuepress build output\n.vuepress/dist\n\n# vuepress v2.x temp and cache directory\n.temp\n.cache\n\n# vitepress build output\n**/.vitepress/dist\n\n# vitepress cache directory\n**/.vitepress/cache\n\n# Docusaurus cache and generated files\n.docusaurus\n\n# Serverless directories\n.serverless/\n\n# FuseBox cache\n.fusebox/\n\n# DynamoDB Local files\n.dynamodb/\n\n# TernJS port file\n.tern-port\n\n# Stores VSCode versions used for testing VSCode extensions\n.vscode-test\n\n# Stores VSCode specific settings\n.vscode\n!.vscode/*.template.json\n!.vscode/extensions.json\n\n# yarn v2\n.yarn/cache\n.yarn/unplugged\n.yarn/build-state.yml\n.yarn/install-state.gz\n.pnp.*\n\n# Build output directory\nbuild/\n\nlog.txt\n\n.DS_Store"
  },
  {
    "path": ".mcp.json",
    "content": "{\n  \"chrome-devtools\": {\n    \"command\": \"npx\",\n    \"args\": [\"chrome-devtools-mcp@latest\"]\n  }\n}\n"
  },
  {
    "path": ".nvmrc",
    "content": "v22"
  },
  {
    "path": ".prettierignore",
    "content": "# Prettier-only ignores.\nCHANGELOG.md\nsrc/third_party/lighthouse-devtools-mcp-bundle.js"
  },
  {
    "path": ".prettierrc.cjs",
    "content": "/**\n * @license\n * Copyright 2025 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\n/**\n * @type {import('prettier').Config}\n */\nmodule.exports = {\n  bracketSpacing: false,\n  singleQuote: true,\n  trailingComma: 'all',\n  arrowParens: 'avoid',\n  singleAttributePerLine: true,\n  htmlWhitespaceSensitivity: 'strict',\n  endOfLine: 'lf',\n};\n"
  },
  {
    "path": ".release-please-manifest.json",
    "content": "{\n  \".\": \"0.20.2\"\n}\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "# Changelog\n\n## [0.20.2](https://github.com/ChromeDevTools/chrome-devtools-mcp/compare/chrome-devtools-mcp-v0.20.1...chrome-devtools-mcp-v0.20.2) (2026-03-18)\n\n\n### 📄 Documentation\n\n* add troubleshooting for Claude Code plugin HTTPS clone failures ([#1195](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/1195)) ([d082ca4](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/d082ca4ecd35a023d09f9c1ff949d5fb0c3fb069))\n\n## [0.20.1](https://github.com/ChromeDevTools/chrome-devtools-mcp/compare/chrome-devtools-mcp-v0.20.0...chrome-devtools-mcp-v0.20.1) (2026-03-16)\n\n\n### 🛠️ Fixes\n\n* update VS Code manual installation powershell command ([#1151](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/1151)) ([6c64a5b](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/6c64a5b543714796b25a12dc6f2be7a1e683e8bd))\n\n\n### ⚡ Performance\n\n* use CDP to find open DevTools pages. ([#1150](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/1150)) ([94de19c](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/94de19cdcdae9e31d0962b273ce352dc248eb5a8))\n\n## [0.20.0](https://github.com/ChromeDevTools/chrome-devtools-mcp/compare/chrome-devtools-mcp-v0.19.0...chrome-devtools-mcp-v0.20.0) (2026-03-11)\n\n\n### 🎉 Features\n\n* experimental `chrome-devtools` CLI ([#1100](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/1100)) ([1ac574e](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/1ac574e7154948e86e414e5149fb975a190d5bb0))\n\n\n### 📄 Documentation\n\n* fix typo ([#1155](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/1155)) ([b59cabc](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/b59cabcc1d59802ffd7d9667040188e46192357d))\n* fix typos and improve phrasing ([#1130](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/1130)) ([70d4f36](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/70d4f365dc619a5743e697c30800f7065bc6227d))\n* revise contribution process and add release process ([#1134](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/1134)) ([d7d26a1](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/d7d26a103b840e2feb7cb9af6a242edda94f1ddf))\n* **troubleshooting:** add symptom for missing tools due to read-only mode ([#1148](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/1148)) ([57e7d51](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/57e7d51e8ca1e2ee325a9e7a9c64c033acbe6d6a))\n* Update troubleshooting for MCP server connection errors ([#1017](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/1017)) ([00f9c31](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/00f9c3108ab9caefca57998439052c728298920b))\n\n\n### 🏗️ Refactor\n\n* move main files ([#1120](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/1120)) ([c2d8009](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/c2d8009ff75f76bce1ec4cf79c2467b50d81725e))\n\n## [0.19.0](https://github.com/ChromeDevTools/chrome-devtools-mcp/compare/chrome-devtools-mcp-v0.18.1...chrome-devtools-mcp-v0.19.0) (2026-03-05)\n\n\n### 🎉 Features\n\n* add pageId routing for parallel multi-agent workflows ([#1022](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/1022)) ([caf601a](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/caf601a32832bb87cfac801a6bbeacb87508412f)), closes [#1019](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/1019)\n* Add skill which helps with onboarding of the mcp server ([#1083](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/1083)) ([7273f16](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/7273f16ec08f6d5b46a2693b0ad4d559086ded89))\n* integrate Lighthouse audits ([#831](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/831)) ([dfdac26](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/dfdac2648e560d756a8711ad3bb1fa470be8e7c9))\n\n\n### 🛠️ Fixes\n\n* improve error messages around --auto-connect ([#1075](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/1075)) ([bcb852d](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/bcb852dd2e440b0005f4a9ad270a1a7998767907))\n* improve tool descriptions ([#965](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/965)) ([bdbbc84](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/bdbbc84c125bdd48f4be48aa476bec0323de611c))\n* repair broken markdown and extract snippets in a11y-debugging skill ([#1096](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/1096)) ([adac7c5](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/adac7c537ee304f324c5e7284fb363396d1773f5))\n* simplify emulation and script tools ([#1073](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/1073)) ([e51ba47](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/e51ba4720338951e621585b77efc6a0e07678d99))\n* simplify focus state management ([#1063](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/1063)) ([f763da2](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/f763da24a10e27605c0a5069853ce7c92974eec2))\n* tweak lighthouse description ([#1112](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/1112)) ([5538180](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/55381804ae7ffa8a1e5933b621a9b8390b3000ff))\n\n\n### 📄 Documentation\n\n* Adapt a11y skill to utilize Lighthouse ([#1054](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/1054)) ([21634e6](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/21634e660c346e469ae62116b1824538f51567dd))\n* add feature release checklist to CONTRIBUTING.md ([#1118](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/1118)) ([0378457](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/03784577ffb6e238bcb2d637bff9ad759723ea7b))\n* fix typo in README regarding slim mode ([#1093](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/1093)) ([92f2c7b](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/92f2c7b48b56a6b1d6ac7c9e2f2e92beb26bcf62))\n\n\n### 🏗️ Refactor\n\n* clean up more of the context getters ([#1062](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/1062)) ([9628dab](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/9628dabcb4d39f0b94d152a0fc419e049246a29d))\n* consistently use McpPage in tools ([#1057](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/1057)) ([302e5a0](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/302e5a04191ba0558e3c79f1486d01d5eb0f6896))\n* improve type safety for page scoped tools ([#1051](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/1051)) ([5f694c6](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/5f694c60ffd21f8b022554c92b2ad4cbdb457375))\n* make cdp resolvers use McpPage ([#1060](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/1060)) ([d6c06c5](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/d6c06c56a7b8e4968318adc9fc7c820ace9f5bd9))\n* move dialog handling to McpPage ([#1059](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/1059)) ([40c241b](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/40c241bbfc80d6282953ab325b30a597d3d85ade))\n* move server to a separate file ([#1043](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/1043)) ([a8bf3e5](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/a8bf3e585682c3126dfd378e9f98b5dc7ab6045d))\n* remove page passing via context ([#1061](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/1061)) ([4cb5a17](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/4cb5a17b57f57d8a367cd423c960ba122b9952e3))\n* set defaults to performance trace tool ([#1090](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/1090)) ([dfa9b79](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/dfa9b79a4ecc9e67f5b043f2dd97f6889d1fee0b))\n* simplify the response texts ([#1095](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/1095)) ([cb0079e](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/cb0079efbbd41874f6913772fe3f2a037e9f5f8f))\n* type-cast as internal CdpPage interface ([#1064](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/1064)) ([2d5e4fa](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/2d5e4fa3579650a384ff21c88c2e6b9cda031e1a))\n\n## [0.18.1](https://github.com/ChromeDevTools/chrome-devtools-mcp/compare/chrome-devtools-mcp-v0.18.0...chrome-devtools-mcp-v0.18.1) (2026-02-25)\n\n\n### 🛠️ Fixes\n\n* remove endsWith for filePath in memory tools ([#1041](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/1041)) ([d0622d5](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/d0622d52d46ac72a28bc22f93a337fb5007214c7))\n\n## [0.18.0](https://github.com/ChromeDevTools/chrome-devtools-mcp/compare/chrome-devtools-mcp-v0.17.3...chrome-devtools-mcp-v0.18.0) (2026-02-24)\n\n\n### 🎉 Features\n\n* `--slim` mode for maximum token savings ([#958](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/958)) ([c402b43](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/c402b43697d834994c4fc141305189082da14bee))\n* add a new skill for accessibility debugging and auditing with Chrome DevTools MCP. ([#1002](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/1002)) ([b0c6d04](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/b0c6d042e4d68763acf989edc8097ce07e85dc7a))\n* add experimental screencast recording tools ([#941](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/941)) ([33446d4](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/33446d457e4386fadcfe4ddf6c7a43b2e9098c9a))\n* add skill to debug and optimize LCP ([#993](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/993)) ([2cd9b95](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/2cd9b95346226aa52cce18f6ab889a2ae194806c))\n* add storage-isolated browser contexts ([#991](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/991)) ([59f6477](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/59f6477a70eb07585e9a510089f1dfc840a012fd))\n* add take_memory_snapshot tool ([#1023](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/1023)) ([7ffdc5e](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/7ffdc5ee4d9df9f62f03354fa758fb4d022c3b08))\n* support any-match text arrays in wait_for ([#1011](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/1011)) ([496ab1b](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/496ab1b45f7a283a1432643777e0795a17f33667))\n* support type_text ([#1026](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/1026)) ([b5d01b5](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/b5d01b5fe65fa20f9b76555b86a749960a5d1738))\n\n\n### 🛠️ Fixes\n\n* detect X server display on Linux ([#1027](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/1027)) ([1746ed9](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/1746ed9ee11c212f78dcbb00af99a0400595e778))\n\n\n### ♻️ Chores\n\n* cleanup string and structured console formatters ([#1005](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/1005)) ([0d78685](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/0d78685a5b37dc68bb11a1088ff8816ecff3bb82))\n* extract version in a seprate file ([#1032](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/1032)) ([0106865](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/0106865aad6d51b6cb590bf98ccaf7078e8d7436))\n* move emulation settings to context ([#1000](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/1000)) ([bc3c40e](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/bc3c40e8f961433fb2ae858482d66f9a55fdde32))\n* optimize slim tool descriptions and params ([#1028](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/1028)) ([ca6635d](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/ca6635d5a5d5e8b7b9944fa8b4e1063e6269a5f2))\n* simplify JavaScript code examples, update code block language, and refine descriptions in a11y debugging skill documentation. ([#1009](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/1009)) ([5cedcaa](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/5cedcaad2c8a5e488064e21fb56cbd8643345440))\n* types for JSON output of IssueFormatter ([#1007](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/1007)) ([9ef4479](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/9ef4479bec39c5f2651d6ebb63e9ec0fecf8bf89))\n\n## [0.17.3](https://github.com/ChromeDevTools/chrome-devtools-mcp/compare/chrome-devtools-mcp-v0.17.2...chrome-devtools-mcp-v0.17.3) (2026-02-19)\n\n\n### 🛠️ Fixes\n\n* remove clean from prepare ([#997](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/997)) ([2016b98](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/2016b98217bf5aa8d65c6668b1e46c8a3400276f))\n\n## [0.17.2](https://github.com/ChromeDevTools/chrome-devtools-mcp/compare/chrome-devtools-mcp-v0.17.1...chrome-devtools-mcp-v0.17.2) (2026-02-19)\n\n\n### 🛠️ Fixes\n\n* check that combobox is actually a select element before filling out options ([#979](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/979)) ([d2bc489](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/d2bc489e4351551ba62a104433839c4198ecae84))\n* handle network request pagination correctly ([#980](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/980)) ([0d9f422](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/0d9f422201538aa847a50417f1ed370e3a6c95b2))\n\n\n### 📄 Documentation\n\n* Add a note about previously installed server installations ([#982](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/982)) ([c0009f7](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/c0009f7ab2f15bedd1c4ceb609db77bcb3c96f2d))\n* update codex doc URL ([#987](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/987)) ([ebbbea7](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/ebbbea7f9d20e4dea902d06e9b86dfe1cc9b221f))\n\n\n### ♻️ Chores\n\n* **network:** de-duplicate String and JSON formatters ([#985](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/985)) ([1896dbb](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/1896dbb5a7cdc3fc0bcc5e665aee986a1180b014))\n* remove text from the status code for Network requests ([#778](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/778)) ([327a388](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/327a3884d8443b8591c06ddb3f9081771ae973c3))\n\n## [0.17.1](https://github.com/ChromeDevTools/chrome-devtools-mcp/compare/chrome-devtools-mcp-v0.17.0...chrome-devtools-mcp-v0.17.1) (2026-02-16)\n\n\n### 📄 Documentation\n\n* Add 'Progressive Complexity' and 'Reference over Value' design principles. ([#939](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/939)) ([8d765c0](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/8d765c0aef7bbcd476c7e7fbe9ea63ee26cf4fa6))\n* add Katalon Studio setup instructions to README ([#929](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/929)) ([6cfef24](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/6cfef24ec734ed62221c66bdf03b09ce000f5bfe))\n* add MCP config for Claude plugin + docs ([#944](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/944)) ([a781da4](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/a781da4434c3490901b28017bc7aa40493ef8dcc))\n* estimate tokens using tiktoken  ([#959](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/959)) ([fd0a919](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/fd0a9193b37be4c5cda21dc4904093c7b58d61be))\n* improve Claude Code installation instructions ([#947](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/947)) ([3ec5b7e](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/3ec5b7e7a2d97c9f0165c5af3317c531a9dc058f))\n* Update README with WSL configuration details ([#946](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/946)) ([107c46a](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/107c46a4dbd2ba7c7b9217a75ae2b1871d3c7f0d))\n\n\n### ♻️ Chores\n\n* rename files to have more consistent style ([#935](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/935)) ([9e1f9ac](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/9e1f9ac69667ddc3e2917e2c30e5ee940a03d853))\n\n## [0.17.0](https://github.com/ChromeDevTools/chrome-devtools-mcp/compare/chrome-devtools-mcp-v0.16.0...chrome-devtools-mcp-v0.17.0) (2026-02-10)\n\n\n### 🎉 Features\n\n* include Error.cause chain for uncaught errors and logged Errors ([#906](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/906)) ([05b01ec](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/05b01ecaba47cf1ce38564636663222c9cab46de))\n* Integrate CrUX data into performance trace summaries ([#733](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/733)) ([b747f9d](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/b747f9d74a12d2119b6531476b2f88ab66be0ff8))\n* show message and stack trace in details when console.log'ging Error objects ([#902](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/902)) ([ffa00da](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/ffa00dab1b65b2eac8db215e0289317b8ed9b725))\n\n\n### 🛠️ Fixes\n\n* console formatter hides frames from ignored scripts ([#927](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/927)) ([8e2380b](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/8e2380b434d9659ffa8a7043d2589261772fa04f))\n* limit stack traces to 50 lines ([#923](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/923)) ([caea23a](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/caea23a7cf33c87cd4ce426eb2a10724aba3cc71))\n\n\n### 📄 Documentation\n\n* add macOS Web Bluetooth troubleshooting note ([#930](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/930)) ([3c9528b](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/3c9528b43d9bbff166fcfcfee321149ff44ddd21)), closes [#917](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/917)\n\n## [0.16.0](https://github.com/ChromeDevTools/chrome-devtools-mcp/compare/chrome-devtools-mcp-v0.15.1...chrome-devtools-mcp-v0.16.0) (2026-02-04)\n\n\n### 🎉 Features\n\n* include source-mapped stack trace for uncaught errors ([#876](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/876)) ([ecef712](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/ecef712e70b47ae81eb3364d0aed801ec1c91a70))\n\n\n### 🛠️ Fixes\n\n* accidental extra typing in the fill tool ([#886](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/886)) ([3d6e59d](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/3d6e59dda42be3c6fd97446344a28cbbaa5809b3))\n* update evaluateScript description formatting ([#880](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/880)) ([24db9dd](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/24db9dd78cd4f054d291322685b4f47601da3f5a))\n* use 1-based line/column and fix wasm offsets in stack frames ([#884](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/884)) ([7e1ec81](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/7e1ec81fb63ec8b7c6d77dbdc88beef4240243ba))\n\n\n### 📄 Documentation\n\n* mention source-mapped stack traces in 'Key features' ([#883](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/883)) ([579d18a](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/579d18a3f4d1d8d05bf267a39de7f2f53e719b17))\n* remove outdated --channel=beta note ([#882](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/882)) ([acdb5c9](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/acdb5c9bb3f249c5a9ce1d4a3e84c580af999141))\n\n## [0.15.1](https://github.com/ChromeDevTools/chrome-devtools-mcp/compare/chrome-devtools-mcp-v0.15.0...chrome-devtools-mcp-v0.15.1) (2026-01-30)\n\n\n### 🛠️ Fixes\n\n* disable usage statistics when CI or CHROME_DEVTOOLS_MCP_NO_USAGE_STATISTICS env is set ([#862](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/862)) ([c0435a2](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/c0435a2d53eb51b7500fc5cce50344520ea164e7))\n* respect custom timeouts in navigate tools ([#865](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/865)) ([a0aeb97](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/a0aeb97693fd5ca641f45ebcd4ce3b4b08ce21b8))\n\n## [0.15.0](https://github.com/ChromeDevTools/chrome-devtools-mcp/compare/chrome-devtools-mcp-v0.14.0...chrome-devtools-mcp-v0.15.0) (2026-01-28)\n\n\n### 🎉 Features\n\n* Add ability to inject script to run on page load ([#568](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/568)) ([d845ad4](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/d845ad48584a49aa57b11de308beeb17ed0b2e10))\n* enable usage statistics by default with opt-out ([#855](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/855)) ([7e279f1](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/7e279f1b67c5cfd4ad033a4147c51fe20a7833f7))\n* support testing light and dark mode ([#858](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/858)) ([5a23a8c](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/5a23a8c201d30d40395e283f4434d933826333fa))\n\n## [0.14.0](https://github.com/ChromeDevTools/chrome-devtools-mcp/compare/chrome-devtools-mcp-v0.13.0...chrome-devtools-mcp-v0.14.0) (2026-01-27)\n\n\n### 🎉 Features\n\n* add a skill for using chrome-devtools-mcp ([#830](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/830)) ([aa0a367](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/aa0a3679f59ab441908d31252afee1cd56102da8))\n* add background parameter to new_page tool ([#837](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/837)) ([d756888](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/d7568881ba4aa0e2c10dc6148fd0ef941fee10d5))\n* allow skipping snapshot generation for input tools ([#821](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/821)) ([4b8e9f2](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/4b8e9f287572e0a95c30b5ca612acf08bf79595b))\n* include stack trace in 'get_console_message' tool ([#740](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/740)) ([a3a0021](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/a3a00210a30f78045244bc897ee736bdbdc36007))\n* support device viewport and user agent emulation ([#798](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/798)) ([a816967](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/a8169676f920f88965a2574f53affe15c1278b43))\n* support filePath for network request and response bodies ([#795](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/795)) ([6d0e4ca](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/6d0e4cab28a8498c2783c1c0c6436c655de7b336))\n\n\n### 🛠️ Fixes\n\n* handle beforeunload dialogs in navigations ([#788](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/788)) ([9b21f8b](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/9b21f8b2e972f78f58c6f633851466356330c77d))\n* improve error handling for console messages ([#844](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/844)) ([dc43ede](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/dc43ede1f20302bd2feb706e63bcf992b4a66a96))\n* improve error reporting when retrieving the element ([#845](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/845)) ([f7dd003](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/f7dd00340a8ac5af7fbe4922f2a1d27d99d933cc))\n* improve performance tool description ([#800](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/800)) ([aa9a176](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/aa9a1769568aca2a357f186b2e80b38b2ed76323))\n* increase timeouts for long text input ([#787](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/787)) ([a83a338](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/a83a33835148905b538b39be93f6115774f91696))\n* make request and response handling more robust ([#846](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/846)) ([695817f](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/695817f6d6da5fcb94934fb1c2be8b006522f53b))\n* re-use node ids across snapshots ([#814](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/814)) ([a6cd2cd](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/a6cd2cd3f2bd823f0e044d7796fd8ff2c100cda3))\n\n\n### 📄 Documentation\n\n* add a mention of evals into contributing.md ([#773](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/773)) ([9a31ac7](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/9a31ac7abab5890d11fec627bbdcbb8051452453))\n* document how to add extensions to gemini-cli ([#834](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/834)) ([0610d11](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/0610d11aa9add484951b76adef557eed5e2bd275))\n* update auto-connect docs ([#779](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/779)) ([a106fba](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/a106fbadbc1a487ce4c53a9eb783c98e524c0a9e))\n* Update README.md to include a link to Android debugging ([#783](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/783)) ([6e52e66](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/6e52e66a7a7ebbf1f2e2080a857f72192036eb0c))\n\n## [0.13.0](https://github.com/ChromeDevTools/chrome-devtools-mcp/compare/chrome-devtools-mcp-v0.12.1...chrome-devtools-mcp-v0.13.0) (2026-01-14)\n\n\n### 🎉 Features\n\n* Allow opting out of default Chrome launch arguments ([#729](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/729)) ([9a51af2](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/9a51af219fc9216cd463bef9363716283f41f36a))\n* support filePath in performance tools ([#686](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/686)) ([68ae2f8](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/68ae2f8253e2ba5c34436e25df114874c537f6df))\n\n\n### 🛠️ Fixes\n\n* support resize_page when browser window is maximized/fullscreenwindow state ([#748](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/748)) ([4d9ac22](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/4d9ac227ddff6fc4aec44e46673f6e44a8168db9))\n* use relative path for plugin source in marketplace ([#724](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/724)) ([5c1ecf8](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/5c1ecf835ac8aad4947d0a8f82c899acd4115b64))\n\n\n### 📄 Documentation\n\n* add experimental chrome on android guide ([#691](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/691)) ([4a87702](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/4a87702ca6913ed62987f71e080f3d481d13b8d8))\n* autoConnect - clarify how the mcp server selects a profile ([#693](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/693)) ([28b8ff8](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/28b8ff816461760c82e9b19b70f288bc7fa2fa38))\n* claude code broken link ([#707](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/707)) ([1f532b8](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/1f532b8fafa0fa60aaf94c302bad663fab1c12ea))\n* enhance cli docs + sort required vs opt params ([#674](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/674)) ([81cbd99](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/81cbd99f52d013d07bdcf21a0840f61a16bacd33))\n* update auto connect docs to mention min Chrome version ([#681](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/681)) ([ab2340f](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/ab2340f40127dcdabde6887a411163ce9d130394))\n* Update Claude Code instructions in README.md ([#711](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/711)) ([f81cd2d](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/f81cd2d8dfc35da8c718b227e0ee4c4d7c5daca8))\n* update readme to include OpenCode example ([#560](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/560)) ([fbba3c9](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/fbba3c9461cec8113216fa4569e879c85312ea29))\n\n\n### ♻️ Chores\n\n* change pageIdx to page ids ([#741](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/741)) ([a23c6ba](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/a23c6ba8c9e1da90c885e68946635a8cc536a11e))\n\n## [0.12.1](https://github.com/ChromeDevTools/chrome-devtools-mcp/compare/chrome-devtools-mcp-v0.12.0...chrome-devtools-mcp-v0.12.1) (2025-12-12)\n\n\n### 🛠️ Fixes\n\n* catch unexpected error in event handlers ([#672](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/672)) ([ca0f560](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/ca0f5607f18bf04134e85ea1f61d1a839a47827b))\n* log unhandledRejection instead of crashing ([#673](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/673)) ([f59b4a2](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/f59b4a2ed8b09e1d64916552ee6db49b978fe9a7))\n* make bringToFront optional in select_page ([#668](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/668)) ([ceae17b](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/ceae17be26b0a812f1b013dcebaed9beb510e7b3))\n* Update installation badges in README.md for VS Code ([#660](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/660)) ([61ede1c](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/61ede1c0531ea8b028d9a5cbb28fcdc00cc521e0))\n\n\n### 📄 Documentation\n\n* Add debug instructions ([#670](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/670)) ([a8aae66](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/a8aae6652e205b87ac2efa29217b7cbd18dcbbe6))\n* explain new auto connection feature ([#664](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/664)) ([a537a8c](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/a537a8c8cef4f2a3493e9f7de47345d565b6fc9f))\n\n## [0.12.0](https://github.com/ChromeDevTools/chrome-devtools-mcp/compare/chrome-devtools-mcp-v0.11.0...chrome-devtools-mcp-v0.12.0) (2025-12-09)\n\n\n### 🎉 Features\n\n* support --auto-connect to a Chrome instance ([#651](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/651)) ([6ab6d85](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/6ab6d85d50226cf12a62563430f552e783f428b2))\n* support --user-data-dir with --auto-connect ([#654](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/654)) ([e3c59bc](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/e3c59bcd9c284f3be99cc15e22116b887f04cdab))\n\n\n### 🛠️ Fixes\n\n* map channel for resolveDefaultUserDataDir ([#658](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/658)) ([6f59b39](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/6f59b3975abda50536f8b890f3245662b22e3657))\n\n\n### 📄 Documentation\n\n* Add AX design principles ([#643](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/643)) ([90ed192](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/90ed192c558d36faf9f6300be1c1fd5abd464d8a))\n* improve autoConnect docs ([#653](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/653)) ([09111cc](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/09111cc16464bed27cd623f3b345d3885db12521))\n\n## [0.11.0](https://github.com/ChromeDevTools/chrome-devtools-mcp/compare/chrome-devtools-mcp-v0.10.2...chrome-devtools-mcp-v0.11.0) (2025-12-03)\n\n\n### 🎉 Features\n\n* **emulation:** add geolocation emulation tool ([#634](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/634)) ([3991e4c](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/3991e4c2a9c28bf8180f9057ce804d978c39529d))\n* integrate DevTools issues into the console tools ([#636](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/636)) ([d892145](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/d8921453c77a1c0815059fb9bc72c0cd769a7bd4))\n* support --user-data-dir ([#622](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/622)) ([fcaf553](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/fcaf55354c2afbdbae538e27eb4b6d02f2e87985))\n\n\n### 🛠️ Fixes\n\n* handle error messages that are not instanceof Error ([#618](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/618)) ([a67528a](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/a67528a046746c7131d5265f6c94613d607aaf90))\n* handle the case when all pages are filtered out ([#616](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/616)) ([bff5c65](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/bff5c6569003fdbc207448d89a8be6a9a8172ca0))\n* ignore hash parts of URLs when finding DevTools ([#608](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/608)) ([52533d0](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/52533d0c695354b816807de253f0ec17099aa9d7))\n* ignore quality for png ([#589](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/589)) ([2eaf268](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/2eaf2689c3360f88479f4cdab8ddde5899378e33))\n* include a note about selected elements missing from the snapshot ([#593](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/593)) ([80e77fd](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/80e77fd9a35a3dc5c451cc5b070b8baa574c686c))\n* prevent dropping license notices on some files when publishing ([#604](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/604)) ([94752ff](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/94752ffade847671ebfd15e4013a5b5cdf8377df))\n* rename page content to latest page snapshot ([#579](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/579)) ([9cb99ad](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/9cb99ad3e65054f4ea12a39358719f6630a020d0))\n* **wait_for:** respect the provided timeout ([#630](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/630)) ([6b0984a](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/6b0984aa7dca6f651afd1fed56246893810781c9)), closes [#624](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/624)\n\n\n### 📄 Documentation\n\n* add Antigravity config ([#580](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/580)) ([6f9182f](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/6f9182f4b60f1f6ff8d321fec35545712828686e))\n* add Qoder CLI to the MCP client configuration section in the README. ([#552](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/552)) ([1a16f15](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/1a16f15546e227a0708f89d3084c98d4916db53f))\n* add VS Code install badges ([#532](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/532)) ([cc4d065](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/cc4d065dd6081a2a9fbcc3d8ebb1536e5426116e))\n* clarify browser-url parameter in README ([#613](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/613)) ([05cf8cb](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/05cf8cb8a6c68506282075bc1522c81f0b84f07b))\n* Fix Antigravity docs ([#605](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/605)) ([fae2608](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/fae260888748ece77b368a13ee913153caffcef7))\n* update readme to explain agy's browser integration ([#612](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/612)) ([2d89865](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/2d89865ddbff6e77332c6157f687dcc2f0bef892))\n\n\n### ♻️ Chores\n\n* avoid throwing in resolveCdpElementId ([#606](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/606)) ([eb261fd](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/eb261fd48b6753db246d24b77e1f477dc7a9455e))\n\n## [0.10.2](https://github.com/ChromeDevTools/chrome-devtools-mcp/compare/chrome-devtools-mcp-v0.10.1...chrome-devtools-mcp-v0.10.2) (2025-11-19)\n\n\n### 📄 Documentation\n\n* add Factory CLI configuration to MCP clients ([#523](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/523)) ([016e2fd](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/016e2fd6ee57447103f7385285dd503b5576a860))\n\n\n### ♻️ Chores\n\n* clear issue aggregator on page navigation ([#565](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/565)) ([c3784d1](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/c3784d1990a926f651951e4eef05520c5c448964))\n* disable issues in list_console_messages for now ([#575](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/575)) ([08e9a9f](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/08e9a9f42e6ff1a92c60b3e958b0817c7b785afc))\n* simplify issue management ([#564](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/564)) ([3b016f1](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/3b016f1a814b1a69750813548b3f35e79bfb6fef))\n\n## [0.10.1](https://github.com/ChromeDevTools/chrome-devtools-mcp/compare/chrome-devtools-mcp-v0.10.0...chrome-devtools-mcp-v0.10.1) (2025-11-07)\n\n\n### 🛠️ Fixes\n\n* avoid no page selected errors ([#537](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/537)) ([4724bbb](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/4724bbba9327fc162cd1f0372e608f6ebefc59cc))\n\n## [0.10.0](https://github.com/ChromeDevTools/chrome-devtools-mcp/compare/chrome-devtools-mcp-v0.9.0...chrome-devtools-mcp-v0.10.0) (2025-11-05)\n\n\n### 🎉 Features\n\n* add a press_key tool ([#458](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/458)) ([b427392](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/b4273923928704e718e0a0f8b5cc86758416e994))\n* add insightSetId to performance_analyze_insight ([#518](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/518)) ([36504d2](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/36504d29caf637b2d7bf231204c0478b54220c83))\n* an option to ignore cache on reload ([#485](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/485)) ([8e56307](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/8e56307d623fe3651262287b30544ed70426b0b8))\n* detect network requests inspected in DevTools UI ([#477](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/477)) ([796aed7](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/796aed72b7126ed4332888ffbc06d6cb678265ef))\n* fetch DOM node selected in the DevTools Elements panel ([#486](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/486)) ([4a83574](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/4a83574961d8d6b974037db56fc8bdbbb91f79b6))\n* support page reload ([#462](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/462)) ([d177087](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/d17708798194486b2571092aa67838085da7231e))\n* support saving snapshots to file ([#463](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/463)) ([b0ce08a](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/b0ce08ae2ce422813fef3f28c18f2cb6c976d9fc))\n\n\n### 🛠️ Fixes\n\n* Augment fix to prevent stray OGS frames in NTP from causing hangs. ([#521](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/521)) ([d90abd4](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/d90abd4e9e534417622d7f4676e9c3dbeb39ea8d))\n* improve get_network_request description ([#500](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/500)) ([2f448e8](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/2f448e84ea8d3a44687c74b3577edf882ef2c19f))\n* work around NTP iframes causing hangs ([#504](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/504)) ([cca5ff4](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/cca5ff471c2d2c663e63ade1e2ea58f9a7f5a2cd))\n\n\n### 📄 Documentation\n\n* add Windsurf to the editor config README ([#493](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/493)) ([63a5d82](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/63a5d824c2d914c9007e2b837fa292f5ba74ceed))\n* fix typos in README.md exlcude -&gt; exclude ([#513](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/513)) ([8854a34](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/8854a3400c3a6b84c761bf8ed82769fc2dec7366))\n* remove unnecessary replace ([#475](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/475)) ([40e1753](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/40e1753d2e874bb22005dbebdb551da304a80033))\n\n\n### ♻️ Chores\n\n* connect to DevTools targets by default ([#466](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/466)) ([a41e440](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/a41e4407996b8090f8cccc85f6c4696006fc31ec))\n* detect DevTools page for each page ([#467](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/467)) ([1560ff2](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/1560ff23cad28ab63c1cf9fb1b961db886bc4a3e))\n* merge emulate tools into one ([#494](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/494)) ([c06f452](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/c06f4522ee8f762b59c60c2fd23a0deaaa544766))\n\n## [0.9.0](https://github.com/ChromeDevTools/chrome-devtools-mcp/compare/chrome-devtools-mcp-v0.8.1...chrome-devtools-mcp-v0.9.0) (2025-10-22)\n\n\n### 🎉 Features\n\n* add claude marketplace and plugin json ([#396](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/396)) ([0498611](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/0498611429f769c6ccae365674003d2bd538c292))\n* add filters and pagination to the console messages tool ([#387](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/387)) ([15d942c](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/15d942c4f3335b35f1cba8e8634651688323663d))\n* add WebSocket endpoint and custom headers support ([#404](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/404)) ([41d6a10](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/41d6a107baee0d14a1c14573f958d44198de23aa))\n* allow configuring tool categories ([#454](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/454)) ([0fe2b8a](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/0fe2b8a2b4d64b9da5f7d1adccc5425fd7cbec34))\n* expose previous navigations to the MCP ([#419](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/419)) ([165cf9c](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/165cf9c70b7f91dc116558547a870281f29da710))\n* support previous navigation for Console messages ([#452](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/452)) ([6f24362](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/6f243620391f0c608f51d464257cf3222d653e9e))\n* support stable id for network requests ([#375](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/375)) ([f4d7b49](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/f4d7b49bb112b4336bef0d90059485f41f71e4f1))\n* support verbose snapshots ([#388](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/388)) ([d47aaa9](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/d47aaa96ff990c49dd07a481ea1924f85881eafa))\n* tool to get a verbose single console message ([#435](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/435)) ([9205593](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/92055933dc44e5d200dda2ee4ae0e365b24281bb))\n* use stable id for network request querying ([#382](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/382)) ([579819b](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/579819b5e76f7a34c7c5c0877ac1e5e284beb328))\n\n\n### 🛠️ Fixes\n\n* allow evaluating in Frames ([#443](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/443)) ([053f1f8](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/053f1f830d051ec415f4b00e645f5a1aff8554a1))\n* better wording for evaluate_script ([#392](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/392)) ([2313fda](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/2313fdacad72a1bc5c4d8f1cbdd80fd64ba91771))\n* indicate when request and response bodies are not available ([#446](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/446)) ([7d47d6b](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/7d47d6b2f40bf08def29de3ca37b1a4a28ce6777))\n* pageerror for non-error types ([#442](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/442)) ([b6b42ec](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/b6b42ecb998dd4f8fbf4a8e7a49f461333a41103))\n* retrieve data correctly with fewer than 3 navigations ([#451](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/451)) ([4c65f59](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/4c65f59cf9f62662cf903fbbd19b67a8828d674a))\n\n\n### 📄 Documentation\n\n* add instructions for Qoder ([#386](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/386)) ([d8df784](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/d8df784127afd590eb02e0060378465ae115a7a4))\n* add VM-to-host remote debugging workaround ([#399](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/399)) ([9f9dab0](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/9f9dab0787f19c5730b65daf148c382fb2d9e365))\n* Update Copilot CLI instructions ([#423](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/423)) ([c7733a8](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/c7733a818050e50830c9a8e3d62bb80892cf9121))\n\n\n### ♻️ Chores\n\n* bundle all dependencies together ([#450](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/450)) ([914b980](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/914b980113353fd41b301da397aa45975090487a))\n* bundle modelcontextprotocol-sdk ([#409](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/409)) ([6c8432b](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/6c8432b6b69d5d56d0dee01968882492033f2dc1))\n* bundle puppeteer-core ([#417](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/417)) ([b443033](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/b443033000e46a992ea7fa071af0f9ec304b9ea7))\n* bundle zod together with modelcontextprotocol/sdk ([#414](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/414)) ([800e7e8](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/800e7e836433f3f1b2bfafa12ed35a991404d270))\n* cleanup data fetching ([#441](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/441)) ([5c871c3](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/5c871c3bd98127996011f269faddd8d8e7163917))\n* dispose listeners on page destroyed ([#318](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/318)) ([76d5e94](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/76d5e9416d833299561242ac45c0ce7813e61dbe))\n* extract common paginate type ([#415](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/415)) ([29fd602](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/29fd60216ca1394c46a266c6f853f8d65418e861))\n* store the last 3 navigations in PageCollector ([#411](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/411)) ([b873822](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/b8738221d8cf8322d5f968ee829f03dc83238a05))\n* use different format for reqid ([#380](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/380)) ([78bf66a](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/78bf66a7b1eefc93768f39d6d38fd141104fe812))\n\n## [0.8.1](https://github.com/ChromeDevTools/chrome-devtools-mcp/compare/chrome-devtools-mcp-v0.8.0...chrome-devtools-mcp-v0.8.1) (2025-10-13)\n\n\n### Bug Fixes\n\n* add an option value to the snapshot ([#362](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/362)) ([207137e](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/207137edd6d8af2f49277d88a30d8afa51671631))\n* improve navigate_page_history error messages ([#321](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/321)) ([0624029](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/0624029e0f8735345d202d29dde446b8869d9561))\n* return the default dialog value correctly ([#366](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/366)) ([f08f808](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/f08f8080d0be1074a48e5c2ab0a6533f01f65928))\n* update puppeteer to 24.24.1 ([#370](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/370)) ([477eef4](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/477eef481a2e6241121ee4aaaed34e8342a8b347))\n\n## [0.8.0](https://github.com/ChromeDevTools/chrome-devtools-mcp/compare/chrome-devtools-mcp-v0.7.1...chrome-devtools-mcp-v0.8.0) (2025-10-10)\n\n\n### Features\n\n* support passing args to Chrome ([#338](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/338)) ([e1b5363](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/e1b536365363e1e1a3aa7661dd84290c794510ad))\n\n## [0.7.1](https://github.com/ChromeDevTools/chrome-devtools-mcp/compare/chrome-devtools-mcp-v0.7.0...chrome-devtools-mcp-v0.7.1) (2025-10-10)\n\n\n### Bug Fixes\n\n* document that console and requests are since the last nav ([#335](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/335)) ([9ad7cbb](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/9ad7cbb2de3d285e46e5f3e7c098b0a7535c7e7a))\n\n## [0.7.0](https://github.com/ChromeDevTools/chrome-devtools-mcp/compare/chrome-devtools-mcp-v0.6.1...chrome-devtools-mcp-v0.7.0) (2025-10-10)\n\n\n### Features\n\n* Add offline network emulation support to emulate_network command ([#326](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/326)) ([139ce60](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/139ce607814bf25ba541a7264ce96a04b2fac871))\n* add request and response body ([#267](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/267)) ([dd3c143](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/dd3c14336ee44d057d06231a5bfd5c5bcf661029))\n\n\n### Bug Fixes\n\n* ordering of information in performance trace summary ([#334](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/334)) ([2d4484a](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/2d4484a123968754b4840d112b9c1ca59fb29997))\n* publishing to MCP registry ([#313](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/313)) ([1faec78](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/1faec78f84569a03f63585fb84df35992bcfe81a))\n* use default ProtocolTimeout ([#315](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/315)) ([a525f19](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/a525f199458afb266db4540bf0fa8007323f3301))\n\n## [0.6.1](https://github.com/ChromeDevTools/chrome-devtools-mcp/compare/chrome-devtools-mcp-v0.6.0...chrome-devtools-mcp-v0.6.1) (2025-10-07)\n\n\n### Bug Fixes\n\n* change default screen size in headless ([#299](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/299)) ([357db65](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/357db65d18f87b1299a0f6212b7ec982ef187171))\n* **cli:** tolerate empty browser URLs ([#298](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/298)) ([098a904](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/098a904b363f3ad81595ed58c25d34dd7d82bcd8))\n* guard performance_stop_trace when tracing inactive ([#295](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/295)) ([8200194](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/8200194c8037cc30b8ab815e5ee0d0b2b000bea6))\n\n## [0.6.0](https://github.com/ChromeDevTools/chrome-devtools-mcp/compare/chrome-devtools-mcp-v0.5.1...chrome-devtools-mcp-v0.6.0) (2025-10-01)\n\n\n### Features\n\n* **screenshot:** add WebP format support with quality parameter ([#220](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/220)) ([03e02a2](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/03e02a2d769fbfc0c98599444dfed5413d15ae6e))\n* **screenshot:** adds ability to output screenshot to a specific pat… ([#172](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/172)) ([f030726](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/f03072698ddda8587ce23229d733405f88b7c89e))\n* support --accept-insecure-certs CLI ([#231](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/231)) ([efb106d](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/efb106dc94af0057f88c89f810beb65114eeaa4b))\n* support --proxy-server CLI ([#230](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/230)) ([dfacc75](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/dfacc75ee9f46137b5194e35fc604b89a00ff53f))\n* support initial viewport in the CLI ([#229](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/229)) ([ef61a08](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/ef61a08707056c5078d268a83a2c95d10e224f31))\n* support timeouts in wait_for and navigations ([#228](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/228)) ([36e64d5](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/36e64d5ae21e8bb244a18201a23a16932947e938))\n\n\n### Bug Fixes\n\n* **network:** show only selected request ([#236](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/236)) ([73f0aec](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/73f0aecd8a48b9d1ee354897fe14d785c80e863e))\n* PageCollector subscribing multiple times ([#241](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/241)) ([0412878](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/0412878bf51ae46e48a171183bb38cfbbee1038a))\n* snapshot does not capture Iframe content ([#217](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/217)) ([ce356f2](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/ce356f256545e805db74664797de5f42e7b92bed)), closes [#186](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/186)\n\n## [0.5.1](https://github.com/ChromeDevTools/chrome-devtools-mcp/compare/chrome-devtools-mcp-v0.5.0...chrome-devtools-mcp-v0.5.1) (2025-09-29)\n\n\n### Bug Fixes\n\n* update package.json engines to reflect node20 support ([#210](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/210)) ([b31e647](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/b31e64713e0524f28cbf760fad27b25829ec419d))\n\n## [0.5.0](https://github.com/ChromeDevTools/chrome-devtools-mcp/compare/chrome-devtools-mcp-v0.4.0...chrome-devtools-mcp-v0.5.0) (2025-09-29)\n\n\n### Features\n\n* **screenshot:** add JPEG quality parameter support ([#184](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/184)) ([139cfd1](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/139cfd135cdb07573fe87d824631fcdb6153186e))\n\n\n### Bug Fixes\n\n* do not error if the dialog was already handled ([#208](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/208)) ([d9f77f8](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/d9f77f85098ffe851308c5de05effb03ac21237b))\n* reference to handle_dialog tool ([#209](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/209)) ([205eef5](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/205eef5cdff19ccb7ddbd113bb1450cb87e8f398))\n* support node20 ([#52](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/52)) ([13613b4](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/13613b4a33ab7cf2d4fb1f4849bfa6b82f546945))\n* update tool reference in an error ([#205](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/205)) ([7765bb3](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/7765bb381ad9d01219547faf879a74978188754a))\n\n## [0.4.0](https://github.com/ChromeDevTools/chrome-devtools-mcp/compare/chrome-devtools-mcp-v0.3.0...chrome-devtools-mcp-v0.4.0) (2025-09-26)\n\n\n### Features\n\n* add network request filtering by resource type ([#162](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/162)) ([59d81a3](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/59d81a33258a199a3f993c9e02a415f62ef05ce4))\n\n\n### Bug Fixes\n\n* add core web vitals to performance_start_trace description ([#168](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/168)) ([6cfc977](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/6cfc9774f4ec7944c70842999506b2bc2018a667))\n* add data format information to trace summary ([#166](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/166)) ([869dd42](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/869dd4273e42309c1bb57d44e0e5a6a9506ffad7))\n* expose --debug-file argument ([#164](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/164)) ([22ec7ee](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/22ec7ee45cc04892000cf6dc32f3fe58d33855c1))\n* typo in the disclaimers ([#156](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/156)) ([90f686e](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/90f686e5df3d880c35ec566c837ee5a98824be28))\n\n## [0.3.0](https://github.com/ChromeDevTools/chrome-devtools-mcp/compare/chrome-devtools-mcp-v0.2.7...chrome-devtools-mcp-v0.3.0) (2025-09-25)\n\n\n### Features\n\n* Add pagination list_network_requests ([#145](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/145)) ([4c909bb](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/4c909bb8d7c4a420cb8e3219ec98abf28f5cc664))\n\n\n### Bug Fixes\n\n* avoid reporting page close errors as errors ([#127](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/127)) ([44cfc8f](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/44cfc8f945edf9370efe26247f322a59a4a4a7be))\n* clarify the node version message ([#135](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/135)) ([0cc907a](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/0cc907a9ad79289a6785e9690c3c6940f0a5de52))\n* do not set channel if executablePath is provided ([#150](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/150)) ([03b59f0](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/03b59f0bca024173ad45d7a617994e919d9cbbad))\n* **performance:** ImageDelivery insight errors ([#144](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/144)) ([d64ba0d](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/d64ba0d9027540eb707381e2577ae3c1fe014346))\n* roll latest DevTools to handle Insight errors ([#149](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/149)) ([b2e1e39](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/b2e1e3944c7fa170584ce36c7b8923b0e6d6c6cb))\n\n## [0.2.7](https://github.com/ChromeDevTools/chrome-devtools-mcp/compare/chrome-devtools-mcp-v0.2.6...chrome-devtools-mcp-v0.2.7) (2025-09-24)\n\n\n### Bug Fixes\n\n* validate and report incompatible Node versions ([#113](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/113)) ([adfcecf](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/adfcecf9871938b1ad5d1460e0050b849fb2aa49))\n\n## [0.2.6](https://github.com/ChromeDevTools/chrome-devtools-mcp/compare/chrome-devtools-mcp-v0.2.5...chrome-devtools-mcp-v0.2.6) (2025-09-24)\n\n\n### Bug Fixes\n\n* manually bump server.json versions based on package.json ([#105](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/105)) ([cae1cf1](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/cae1cf13d5a97add3b96f20c425f720a1ceabf94))\n\n## [0.2.5](https://github.com/ChromeDevTools/chrome-devtools-mcp/compare/chrome-devtools-mcp-v0.2.4...chrome-devtools-mcp-v0.2.5) (2025-09-24)\n\n\n### Bug Fixes\n\n* add mcpName to package.json ([#103](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/103)) ([bd0351f](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/bd0351fd36ae35e41e613f0d15df40aeca17ba94))\n\n## [0.2.4](https://github.com/ChromeDevTools/chrome-devtools-mcp/compare/chrome-devtools-mcp-v0.2.3...chrome-devtools-mcp-v0.2.4) (2025-09-24)\n\n\n### Bug Fixes\n\n* forbid closing the last page ([#90](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/90)) ([0ca2434](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/0ca2434a29eb4bc6e570a4ebe21a135d85f4c0f3))\n\n## [0.2.3](https://github.com/ChromeDevTools/chrome-devtools-mcp/compare/chrome-devtools-mcp-v0.2.2...chrome-devtools-mcp-v0.2.3) (2025-09-24)\n\n\n### Bug Fixes\n\n* add a message indicating that no console messages exist ([#91](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/91)) ([1a4ba4d](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/1a4ba4d3e05f51a85747816f8638f31230881437))\n* clean up pending promises on action errors ([#84](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/84)) ([4e7001a](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/4e7001ac375ec51f55b29e9faf68aff0dd09fa0f))\n\n## [0.2.2](https://github.com/ChromeDevTools/chrome-devtools-mcp/compare/chrome-devtools-mcp-v0.2.1...chrome-devtools-mcp-v0.2.2) (2025-09-23)\n\n\n### Bug Fixes\n\n* cli version being reported as unknown ([#74](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/74)) ([d6bab91](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/d6bab912df55dc2e96a8d7893d1906f1fc608d0a))\n* remove unnecessary waiting for navigation ([#83](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/83)) ([924c042](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/924c042492222a555074063841ce765342e3b5b9))\n* rework performance parsing & error handling ([#75](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/75)) ([e8fb30c](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/e8fb30c1bfdc2b4ea8c2daf74b24aa82210f99be))\n\n## [0.2.1](https://github.com/ChromeDevTools/chrome-devtools-mcp/compare/chrome-devtools-mcp-v0.2.0...chrome-devtools-mcp-v0.2.1) (2025-09-23)\n\n\n### Bug Fixes\n\n* add 'on the selected page' to performance tools ([#69](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/69)) ([b877f7a](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/b877f7a3053d0cdf2aad1fefc26cf7b913eb95ce))\n* **emulation:** correctly report info for selected page ([#63](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/63)) ([1e8662f](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/1e8662f06860aecb5c01ed4ff1515ceb9dac26e4))\n* expose timeout when Emulation is enabled ([#73](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/73)) ([0208bfd](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/0208bfdcf6924953879408c18f4c20da544bf4ff))\n* fix browserUrl not working ([#53](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/53)) ([a6923b8](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/a6923b8d9397d12ee0f9fe67dd62b10088ec6e87))\n* increase timeouts in case of Emulation ([#71](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/71)) ([c509c64](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/c509c64576e1be1ddc283653004ef08a117907a2))\n* **windows:** work around Chrome not reporting reasons for crash ([#64](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/64)) ([d545741](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/d5457412a4a76726547190fb3a46bb78c9d6645c))\n\n## [0.2.0](https://github.com/ChromeDevTools/chrome-devtools-mcp/compare/chrome-devtools-mcp-v0.1.0...chrome-devtools-mcp-v0.2.0) (2025-09-17)\n\n\n### Features\n\n* add performance_analyze_insight tool. ([#42](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/42)) ([21e175b](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/21e175b862c624d7a2d07802141187edf2d2e489))\n* support script evaluate arguments ([#40](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/40)) ([c663f4d](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/c663f4d7f9c0b868e8b4750f6441525939bfe920))\n* use Performance Trace Formatter in trace output ([#36](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/36)) ([0cb6147](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/0cb6147b870e17bc3a624e9c6396d963a3e16b44))\n* validate uids ([#37](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/37)) ([014a8bc](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/014a8bc52ecc58080cedeb8023d44f4a55055a05))\n\n\n### Bug Fixes\n\n* change profile folder name to browser-profile ([#39](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/39)) ([36115d7](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/36115d757abbae0502ffee814f55368d2ca59b9e))\n* refresh context based on the browser instance ([#44](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/44)) ([93f4579](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/93f4579dd9aca3beef2bd9f2930ddfcc4069c0e3))\n* update puppeteer to fix a11y snapshot issues ([#43](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/43)) ([b58f787](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/b58f787234a34d5fcb01b336f5fb14e1c55ecdd5))\n\n## [0.1.0](https://github.com/ChromeDevTools/chrome-devtools-mcp/compare/chrome-devtools-mcp-v0.0.2...chrome-devtools-mcp-v0.1.0) (2025-09-16)\n\n\n### Features\n\n* improve tools with awaiting common events ([#10](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/10)) ([dba8b3c](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/dba8b3c5fad0d1bca26aaf172751c51188799927))\n* initial version ([31a0bdc](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/31a0bdce266a33eaca9a7daae4611abb78ff5a25))\n\n\n### Bug Fixes\n\n* define tracing categories ([#21](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/21)) ([c939456](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/c93945657cc96ac7ba213730a750c16e9ab87526))\n* detect multiple instances and throw ([#12](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/12)) ([732267d](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/732267db5fea0048ed1fcc530bcdd074df4126be))\n* make sure tool calls are processed sequentially ([#22](https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/22)) ([a76b23d](https://github.com/ChromeDevTools/chrome-devtools-mcp/commit/a76b23dccf074a13304b0341178665465a2c3399))\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# How to contribute\n\nWe'd love to accept your patches and contributions to this project.\n\n## Before you begin\n\n### Sign our Contributor License Agreement\n\nContributions to this project must be accompanied by a\n[Contributor License Agreement](https://cla.developers.google.com/about) (CLA).\nYou (or your employer) retain the copyright to your contribution; this simply\ngives us permission to use and redistribute your contributions as part of the\nproject.\n\nIf you or your current employer have already signed the Google CLA (even if it\nwas for a different project), you probably don't need to do it again.\n\nVisit <https://cla.developers.google.com/> to see your current agreements or to\nsign a new one.\n\n### Review our community guidelines\n\nThis project follows\n[Google's Open Source Community Guidelines](https://opensource.google/conduct/).\n\n## Development process\n\n### Code reviews\n\nAll submissions, including submissions by project members, require review. We\nuse GitHub pull requests for this purpose. Consult\n[GitHub Help](https://help.github.com/articles/about-pull-requests/) for more\ninformation on using pull requests.\n\n### Conventional commits\n\nPlease follow [conventional commits](https://www.conventionalcommits.org/en/v1.0.0/)\nfor PR and commit titles.\n\n### Feature release checklist\n\nUse `chore:` for commits containing incomplete features that are not available\nto users yet. Once the feature is ready to be released, create a PR with a\n`feat:` prefix that enables the feature. The following criteria need to be\ncompleted:\n\n- Documentation for the feature is up to date. For example, README.md and tools\n  reference are updated.\n- The feature can be used with Chrome stable or version restrictions are\n  documented otherwise.\n- Corresponding skills are updated or new skills are added if needed.\n- The feature fulfills the use case by its own or in conjunction with existing\n  features (we want to avoid features that offer some tools but cannot be used\n  successfully to debug things).\n\n### Release process\n\nReleasing `chrome-devtools-mcp` is automated by GitHub Actions. To release a new\nversion, [search for a PR titled `chore(main): release chrome-devtools-mcp`](https://github.com/ChromeDevTools/chrome-devtools-mcp/pulls?q=is%3Apr+is%3Aopen+%22chore%28main%29%3A+release+chrome-devtools-mcp%22)\nand review, test, and land it. The release PR is automatically opened if there\nare any changes on the main branch that show up in the changelog.\n\n## Installation\n\nCheck that you are using node version specified in .nvmrc, then run following commands:\n\n```sh\ngit clone https://github.com/ChromeDevTools/chrome-devtools-mcp.git\ncd chrome-devtools-mcp\nnpm ci\nnpm run build\n```\n\n### Testing with @modelcontextprotocol/inspector\n\n```sh\nnpx @modelcontextprotocol/inspector node /build/src/bin/chrome-devtools-mcp.js\n```\n\n### Testing with an MCP client\n\nAdd the MCP server to your client's config.\n\n```json\n{\n  \"mcpServers\": {\n    \"chrome-devtools\": {\n      \"command\": \"node\",\n      \"args\": [\"/path-to/build/src/bin/chrome-devtools-mcp.js\"]\n    }\n  }\n}\n```\n\n#### Using with VS Code SSH\n\nWhen running the `@modelcontextprotocol/inspector` it spawns 2 services - one on port `6274` and one on `6277`.\nUsually VS Code automatically detects and forwards `6274` but fails to detect `6277` so you need to manually forward it.\n\n### Debugging\n\nTo write debug logs to `log.txt` in the working directory, run with the following commands:\n\n```sh\nnpx @modelcontextprotocol/inspector node /build/src/bin/chrome-devtools-mcp.js --log-file=/your/desired/path/log.txt\n```\n\nYou can use the `DEBUG` environment variable as usual to control categories that are logged.\n\n### Updating documentation\n\nWhen adding a new tool or updating a tool name or description, make sure to run `npm run gen` to generate the tool reference documentation.\n\n### Contributing to Evals\n\nWe use Gemini to evaluate the MCP server tools in `scripts/eval_scenarios`.\nEach scenario is a TypeScript file that exports a `scenario` object implementing `TestScenario`.\n\n- **prompt**: The prompt to send to the model.\n- **maxTurns**: Maximum number of conversation turns.\n- **expectations**: A function that verifies the tool calls made by the model.\n- **htmlRoute** (Optional): Serve custom HTML content for the test at a specific path.\n\nWe look to test that the tools are used correctly without too rigid assertions. Avoid asserting exact argument values if they can vary (e.g., natural language reasoning), but ensure the core parameters (like URLs or selectors) were correct.\n\nExample:\n\n```ts\nimport {TestScenario} from '../eval_gemini.js';\n\nexport const scenario: TestScenario = {\n  prompt: 'Navigate to example.com',\n  maxTurns: 2,\n  expectations: calls => {\n    // Check that at least one call was 'browse_page'\n    const navigation = calls.find(c => c.name === 'browse_page');\n    if (!navigation) throw new Error('Model did not browse the page');\n    // Verify essential args\n    if (navigation.args.url !== 'http://example.com') {\n      throw new Error(`Wrong URL: ${navigation.args.url}`);\n    }\n  },\n};\n```\n\n## Restrictions on JSON schema\n\n- no .nullable(), no .object() types.\n- represent complex object as a short formatted string.\n\nTODO: implement eslint for schema https://github.com/ChromeDevTools/chrome-devtools-mcp/issues/1076\n"
  },
  {
    "path": "LICENSE",
    "content": "\n                                 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 [yyyy] [name of copyright owner]\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."
  },
  {
    "path": "README.md",
    "content": "# Chrome DevTools MCP\n\n[![npm chrome-devtools-mcp package](https://img.shields.io/npm/v/chrome-devtools-mcp.svg)](https://npmjs.org/package/chrome-devtools-mcp)\n\n`chrome-devtools-mcp` lets your coding agent (such as Gemini, Claude, Cursor or Copilot)\ncontrol and inspect a live Chrome browser. It acts as a Model-Context-Protocol\n(MCP) server, giving your AI coding assistant access to the full power of\nChrome DevTools for reliable automation, in-depth debugging, and performance analysis.\n\n## [Tool reference](./docs/tool-reference.md) | [Changelog](./CHANGELOG.md) | [Contributing](./CONTRIBUTING.md) | [Troubleshooting](./docs/troubleshooting.md) | [Design Principles](./docs/design-principles.md)\n\n## Key features\n\n- **Get performance insights**: Uses [Chrome\n  DevTools](https://github.com/ChromeDevTools/devtools-frontend) to record\n  traces and extract actionable performance insights.\n- **Advanced browser debugging**: Analyze network requests, take screenshots and\n  check browser console messages (with source-mapped stack traces).\n- **Reliable automation**. Uses\n  [puppeteer](https://github.com/puppeteer/puppeteer) to automate actions in\n  Chrome and automatically wait for action results.\n\n## Disclaimers\n\n`chrome-devtools-mcp` exposes content of the browser instance to the MCP clients\nallowing them to inspect, debug, and modify any data in the browser or DevTools.\nAvoid sharing sensitive or personal information that you don't want to share with\nMCP clients.\n\nPerformance tools may send trace URLs to the Google CrUX API to fetch real-user\nexperience data. This helps provide a holistic performance picture by\npresenting field data alongside lab data. This data is collected by the [Chrome\nUser Experience Report (CrUX)](https://developer.chrome.com/docs/crux). To disable\nthis, run with the `--no-performance-crux` flag.\n\n## **Usage statistics**\n\nGoogle collects usage statistics (such as tool invocation success rates, latency, and environment information) to improve the reliability and performance of Chrome DevTools MCP.\n\nData collection is **enabled by default**. You can opt-out by passing the `--no-usage-statistics` flag when starting the server:\n\n```json\n\"args\": [\"-y\", \"chrome-devtools-mcp@latest\", \"--no-usage-statistics\"]\n```\n\nGoogle handles this data in accordance with the [Google Privacy Policy](https://policies.google.com/privacy).\n\nGoogle's collection of usage statistics for Chrome DevTools MCP is independent from the Chrome browser's usage statistics. Opting out of Chrome metrics does not automatically opt you out of this tool, and vice-versa.\n\nCollection is disabled if CHROME_DEVTOOLS_MCP_NO_USAGE_STATISTICS or CI env variables are set.\n\n## Requirements\n\n- [Node.js](https://nodejs.org/) v20.19 or a newer [latest maintenance LTS](https://github.com/nodejs/Release#release-schedule) version.\n- [Chrome](https://www.google.com/chrome/) current stable version or newer.\n- [npm](https://www.npmjs.com/).\n\n## Getting started\n\nAdd the following config to your MCP client:\n\n```json\n{\n  \"mcpServers\": {\n    \"chrome-devtools\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"chrome-devtools-mcp@latest\"]\n    }\n  }\n}\n```\n\n> [!NOTE]  \n> Using `chrome-devtools-mcp@latest` ensures that your MCP client will always use the latest version of the Chrome DevTools MCP server.\n\nIf you are interested in doing only basic browser tasks, use the `--slim` mode:\n\n```json\n{\n  \"mcpServers\": {\n    \"chrome-devtools\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"chrome-devtools-mcp@latest\", \"--slim\", \"--headless\"]\n    }\n  }\n}\n```\n\nSee [Slim tool reference](./docs/slim-tool-reference.md).\n\n### MCP Client configuration\n\n<details>\n  <summary>Amp</summary>\n  Follow https://ampcode.com/manual#mcp and use the config provided above. You can also install the Chrome DevTools MCP server using the CLI:\n\n```bash\namp mcp add chrome-devtools -- npx chrome-devtools-mcp@latest\n```\n\n</details>\n\n<details>\n  <summary>Antigravity</summary>\n\nTo use the Chrome DevTools MCP server follow the instructions from <a href=\"https://antigravity.google/docs/mcp\">Antigravity's docs</a> to install a custom MCP server. Add the following config to the MCP servers config:\n\n```bash\n{\n  \"mcpServers\": {\n    \"chrome-devtools\": {\n      \"command\": \"npx\",\n      \"args\": [\n        \"chrome-devtools-mcp@latest\",\n        \"--browser-url=http://127.0.0.1:9222\",\n        \"-y\"\n      ]\n    }\n  }\n}\n```\n\nThis will make the Chrome DevTools MCP server automatically connect to the browser that Antigravity is using. If you are not using port 9222, make sure to adjust accordingly.\n\nChrome DevTools MCP will not start the browser instance automatically using this approach because the Chrome DevTools MCP server connects to Antigravity's built-in browser. If the browser is not already running, you have to start it first by clicking the Chrome icon at the top right corner.\n\n</details>\n\n<details>\n  <summary>Claude Code</summary>\n\n**Install via CLI (MCP only)**\n\nUse the Claude Code CLI to add the Chrome DevTools MCP server (<a href=\"https://code.claude.com/docs/en/mcp\">guide</a>):\n\n```bash\nclaude mcp add chrome-devtools --scope user npx chrome-devtools-mcp@latest\n```\n\n**Install as a Plugin (MCP + Skills)**\n\n> [!NOTE]  \n> If you already had Chrome DevTools MCP installed previously for Claude Code, make sure to remove it first from your installation and configuration files.\n\nTo install Chrome DevTools MCP with skills, add the marketplace registry in Claude Code:\n\n```sh\n/plugin marketplace add ChromeDevTools/chrome-devtools-mcp\n```\n\nThen, install the plugin:\n\n```sh\n/plugin install chrome-devtools-mcp\n```\n\nRestart Claude Code to have the MCP server and skills load (check with `/skills`).\n\n> [!TIP]\n> If the plugin installation fails with a `Failed to clone repository` error (e.g., HTTPS connectivity issues behind a corporate firewall), see the [troubleshooting guide](./docs/troubleshooting.md#claude-code-plugin-installation-fails-with-failed-to-clone-repository) for workarounds, or use the CLI installation method above instead.\n\n</details>\n\n<details>\n  <summary>Cline</summary>\n  Follow https://docs.cline.bot/mcp/configuring-mcp-servers and use the config provided above.\n</details>\n\n<details>\n  <summary>Codex</summary>\n  Follow the <a href=\"https://developers.openai.com/codex/mcp/#configure-with-the-cli\">configure MCP guide</a>\n  using the standard config from above. You can also install the Chrome DevTools MCP server using the Codex CLI:\n\n```bash\ncodex mcp add chrome-devtools -- npx chrome-devtools-mcp@latest\n```\n\n**On Windows 11**\n\nConfigure the Chrome install location and increase the startup timeout by updating `.codex/config.toml` and adding the following `env` and `startup_timeout_ms` parameters:\n\n```\n[mcp_servers.chrome-devtools]\ncommand = \"cmd\"\nargs = [\n    \"/c\",\n    \"npx\",\n    \"-y\",\n    \"chrome-devtools-mcp@latest\",\n]\nenv = { SystemRoot=\"C:\\\\Windows\", PROGRAMFILES=\"C:\\\\Program Files\" }\nstartup_timeout_ms = 20_000\n```\n\n</details>\n\n<details>\n  <summary>Copilot CLI</summary>\n\nStart Copilot CLI:\n\n```\ncopilot\n```\n\nStart the dialog to add a new MCP server by running:\n\n```\n/mcp add\n```\n\nConfigure the following fields and press `CTRL+S` to save the configuration:\n\n- **Server name:** `chrome-devtools`\n- **Server Type:** `[1] Local`\n- **Command:** `npx -y chrome-devtools-mcp@latest`\n\n</details>\n\n<details>\n  <summary>Copilot / VS Code</summary>\n\n**Click the button to install:**\n\n[<img src=\"https://img.shields.io/badge/VS_Code-VS_Code?style=flat-square&label=Install%20Server&color=0098FF\" alt=\"Install in VS Code\">](https://vscode.dev/redirect/mcp/install?name=io.github.ChromeDevTools%2Fchrome-devtools-mcp&config=%7B%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22chrome-devtools-mcp%22%5D%2C%22env%22%3A%7B%7D%7D)\n\n[<img src=\"https://img.shields.io/badge/VS_Code_Insiders-VS_Code_Insiders?style=flat-square&label=Install%20Server&color=24bfa5\" alt=\"Install in VS Code Insiders\">](https://insiders.vscode.dev/redirect?url=vscode-insiders%3Amcp%2Finstall%3F%257B%2522name%2522%253A%2522io.github.ChromeDevTools%252Fchrome-devtools-mcp%2522%252C%2522config%2522%253A%257B%2522command%2522%253A%2522npx%2522%252C%2522args%2522%253A%255B%2522-y%2522%252C%2522chrome-devtools-mcp%2522%255D%252C%2522env%2522%253A%257B%257D%257D%257D)\n\n**Or install manually:**\n\nFollow the MCP install <a href=\"https://code.visualstudio.com/docs/copilot/chat/mcp-servers#_add-an-mcp-server\">guide</a>,\nwith the standard config from above. You can also install the Chrome DevTools MCP server using the VS Code CLI:\n\nFor macOS and Linux:\n\n```bash\ncode --add-mcp '{\"name\":\"io.github.ChromeDevTools/chrome-devtools-mcp\",\"command\":\"npx\",\"args\":[\"-y\",\"chrome-devtools-mcp\"],\"env\":{}}'\n```\n\nFor Windows (PowerShell):\n\n```powershell\ncode --add-mcp '{\"\"\"name\"\"\":\"\"\"io.github.ChromeDevTools/chrome-devtools-mcp\"\"\",\"\"\"command\"\"\":\"\"\"npx\"\"\",\"\"\"args\"\"\":[\"\"\"-y\"\"\",\"\"\"chrome-devtools-mcp\"\"\"]}'\n```\n\n</details>\n\n<details>\n  <summary>Cursor</summary>\n\n**Click the button to install:**\n\n[<img src=\"https://cursor.com/deeplink/mcp-install-dark.svg\" alt=\"Install in Cursor\">](https://cursor.com/en/install-mcp?name=chrome-devtools&config=eyJjb21tYW5kIjoibnB4IC15IGNocm9tZS1kZXZ0b29scy1tY3BAbGF0ZXN0In0%3D)\n\n**Or install manually:**\n\nGo to `Cursor Settings` -> `MCP` -> `New MCP Server`. Use the config provided above.\n\n</details>\n\n<details>\n  <summary>Factory CLI</summary>\nUse the Factory CLI to add the Chrome DevTools MCP server (<a href=\"https://docs.factory.ai/cli/configuration/mcp\">guide</a>):\n\n```bash\ndroid mcp add chrome-devtools \"npx -y chrome-devtools-mcp@latest\"\n```\n\n</details>\n\n<details>\n  <summary>Gemini CLI</summary>\nInstall the Chrome DevTools MCP server using the Gemini CLI.\n\n**Project wide:**\n\n```bash\n# Either MCP only:\ngemini mcp add chrome-devtools npx chrome-devtools-mcp@latest\n# Or as a Gemini extension (MCP+Skills):\ngemini extensions install --auto-update https://github.com/ChromeDevTools/chrome-devtools-mcp\n```\n\n**Globally:**\n\n```bash\ngemini mcp add -s user chrome-devtools npx chrome-devtools-mcp@latest\n```\n\nAlternatively, follow the <a href=\"https://github.com/google-gemini/gemini-cli/blob/main/docs/tools/mcp-server.md#how-to-set-up-your-mcp-server\">MCP guide</a> and use the standard config from above.\n\n</details>\n\n<details>\n  <summary>Gemini Code Assist</summary>\n  Follow the <a href=\"https://cloud.google.com/gemini/docs/codeassist/use-agentic-chat-pair-programmer#configure-mcp-servers\">configure MCP guide</a>\n  using the standard config from above.\n</details>\n\n<details>\n  <summary>JetBrains AI Assistant & Junie</summary>\n\nGo to `Settings | Tools | AI Assistant | Model Context Protocol (MCP)` -> `Add`. Use the config provided above.\nThe same way chrome-devtools-mcp can be configured for JetBrains Junie in `Settings | Tools | Junie | MCP Settings` -> `Add`. Use the config provided above.\n\n</details>\n\n<details>\n  <summary>Kiro</summary>\n\nIn **Kiro Settings**, go to `Configure MCP` > `Open Workspace or User MCP Config` > Use the configuration snippet provided above.\n\nOr, from the IDE **Activity Bar** > `Kiro` > `MCP Servers` > `Click Open MCP Config`. Use the configuration snippet provided above.\n\n</details>\n\n<details>\n  <summary>Katalon Studio</summary>\n\nThe Chrome DevTools MCP server can be used with <a href=\"https://docs.katalon.com/katalon-studio/studioassist/mcp-servers/setting-up-chrome-devtools-mcp-server-for-studioassist\">Katalon StudioAssist</a> via an MCP proxy.\n\n**Step 1:** Install the MCP proxy by following the <a href=\"https://docs.katalon.com/katalon-studio/studioassist/mcp-servers/setting-up-mcp-proxy-for-stdio-mcp-servers\">MCP proxy setup guide</a>.\n\n**Step 2:** Start the Chrome DevTools MCP server with the proxy:\n\n```bash\nmcp-proxy --transport streamablehttp --port 8080 -- npx -y chrome-devtools-mcp@latest\n```\n\n**Note:** You may need to pick another port if 8080 is already in use.\n\n**Step 3:** In Katalon Studio, add the server to StudioAssist with the following settings:\n\n- **Connection URL:** `http://127.0.0.1:8080/mcp`\n- **Transport type:** `HTTP`\n\nOnce connected, the Chrome DevTools MCP tools will be available in StudioAssist.\n\n</details>\n\n<details>\n  <summary>OpenCode</summary>\n\nAdd the following configuration to your `opencode.json` file. If you don't have one, create it at `~/.config/opencode/opencode.json` (<a href=\"https://opencode.ai/docs/mcp-servers\">guide</a>):\n\n```json\n{\n  \"$schema\": \"https://opencode.ai/config.json\",\n  \"mcp\": {\n    \"chrome-devtools\": {\n      \"type\": \"local\",\n      \"command\": [\"npx\", \"-y\", \"chrome-devtools-mcp@latest\"]\n    }\n  }\n}\n```\n\n</details>\n\n<details>\n  <summary>Qoder</summary>\n\nIn **Qoder Settings**, go to `MCP Server` > `+ Add` > Use the configuration snippet provided above.\n\nAlternatively, follow the <a href=\"https://docs.qoder.com/user-guide/chat/model-context-protocol\">MCP guide</a> and use the standard config from above.\n\n</details>\n\n<details>\n  <summary>Qoder CLI</summary>\n\nInstall the Chrome DevTools MCP server using the Qoder CLI (<a href=\"https://docs.qoder.com/cli/using-cli#mcp-servers\">guide</a>):\n\n**Project wide:**\n\n```bash\nqodercli mcp add chrome-devtools -- npx chrome-devtools-mcp@latest\n```\n\n**Globally:**\n\n```bash\nqodercli mcp add -s user chrome-devtools -- npx chrome-devtools-mcp@latest\n```\n\n</details>\n\n<details>\n  <summary>Visual Studio</summary>\n  \n  **Click the button to install:**\n  \n  [<img src=\"https://img.shields.io/badge/Visual_Studio-Install-C16FDE?logo=visualstudio&logoColor=white\" alt=\"Install in Visual Studio\">](https://vs-open.link/mcp-install?%7B%22name%22%3A%22chrome-devtools%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22chrome-devtools-mcp%40latest%22%5D%7D)\n</details>\n\n<details>\n  <summary>Warp</summary>\n\nGo to `Settings | AI | Manage MCP Servers` -> `+ Add` to [add an MCP Server](https://docs.warp.dev/knowledge-and-collaboration/mcp#adding-an-mcp-server). Use the config provided above.\n\n</details>\n\n<details>\n  <summary>Windsurf</summary>\n  Follow the <a href=\"https://docs.windsurf.com/windsurf/cascade/mcp#mcp-config-json\">configure MCP guide</a>\n  using the standard config from above.\n</details>\n\n### Your first prompt\n\nEnter the following prompt in your MCP Client to check if everything is working:\n\n```\nCheck the performance of https://developers.chrome.com\n```\n\nYour MCP client should open the browser and record a performance trace.\n\n> [!NOTE]  \n> The MCP server will start the browser automatically once the MCP client uses a tool that requires a running browser instance. Connecting to the Chrome DevTools MCP server on its own will not automatically start the browser.\n\n## Tools\n\nIf you run into any issues, checkout our [troubleshooting guide](./docs/troubleshooting.md).\n\n<!-- BEGIN AUTO GENERATED TOOLS -->\n\n- **Input automation** (9 tools)\n  - [`click`](docs/tool-reference.md#click)\n  - [`drag`](docs/tool-reference.md#drag)\n  - [`fill`](docs/tool-reference.md#fill)\n  - [`fill_form`](docs/tool-reference.md#fill_form)\n  - [`handle_dialog`](docs/tool-reference.md#handle_dialog)\n  - [`hover`](docs/tool-reference.md#hover)\n  - [`press_key`](docs/tool-reference.md#press_key)\n  - [`type_text`](docs/tool-reference.md#type_text)\n  - [`upload_file`](docs/tool-reference.md#upload_file)\n- **Navigation automation** (6 tools)\n  - [`close_page`](docs/tool-reference.md#close_page)\n  - [`list_pages`](docs/tool-reference.md#list_pages)\n  - [`navigate_page`](docs/tool-reference.md#navigate_page)\n  - [`new_page`](docs/tool-reference.md#new_page)\n  - [`select_page`](docs/tool-reference.md#select_page)\n  - [`wait_for`](docs/tool-reference.md#wait_for)\n- **Emulation** (2 tools)\n  - [`emulate`](docs/tool-reference.md#emulate)\n  - [`resize_page`](docs/tool-reference.md#resize_page)\n- **Performance** (4 tools)\n  - [`performance_analyze_insight`](docs/tool-reference.md#performance_analyze_insight)\n  - [`performance_start_trace`](docs/tool-reference.md#performance_start_trace)\n  - [`performance_stop_trace`](docs/tool-reference.md#performance_stop_trace)\n  - [`take_memory_snapshot`](docs/tool-reference.md#take_memory_snapshot)\n- **Network** (2 tools)\n  - [`get_network_request`](docs/tool-reference.md#get_network_request)\n  - [`list_network_requests`](docs/tool-reference.md#list_network_requests)\n- **Debugging** (6 tools)\n  - [`evaluate_script`](docs/tool-reference.md#evaluate_script)\n  - [`get_console_message`](docs/tool-reference.md#get_console_message)\n  - [`lighthouse_audit`](docs/tool-reference.md#lighthouse_audit)\n  - [`list_console_messages`](docs/tool-reference.md#list_console_messages)\n  - [`take_screenshot`](docs/tool-reference.md#take_screenshot)\n  - [`take_snapshot`](docs/tool-reference.md#take_snapshot)\n\n<!-- END AUTO GENERATED TOOLS -->\n\n## Configuration\n\nThe Chrome DevTools MCP server supports the following configuration option:\n\n<!-- BEGIN AUTO GENERATED OPTIONS -->\n\n- **`--autoConnect`/ `--auto-connect`**\n  If specified, automatically connects to a browser (Chrome 144+) running locally from the user data directory identified by the channel param (default channel is stable). Requires the remoted debugging server to be started in the Chrome instance via chrome://inspect/#remote-debugging.\n  - **Type:** boolean\n  - **Default:** `false`\n\n- **`--browserUrl`/ `--browser-url`, `-u`**\n  Connect to a running, debuggable Chrome instance (e.g. `http://127.0.0.1:9222`). For more details see: https://github.com/ChromeDevTools/chrome-devtools-mcp#connecting-to-a-running-chrome-instance.\n  - **Type:** string\n\n- **`--wsEndpoint`/ `--ws-endpoint`, `-w`**\n  WebSocket endpoint to connect to a running Chrome instance (e.g., ws://127.0.0.1:9222/devtools/browser/<id>). Alternative to --browserUrl.\n  - **Type:** string\n\n- **`--wsHeaders`/ `--ws-headers`**\n  Custom headers for WebSocket connection in JSON format (e.g., '{\"Authorization\":\"Bearer token\"}'). Only works with --wsEndpoint.\n  - **Type:** string\n\n- **`--headless`**\n  Whether to run in headless (no UI) mode.\n  - **Type:** boolean\n  - **Default:** `false`\n\n- **`--executablePath`/ `--executable-path`, `-e`**\n  Path to custom Chrome executable.\n  - **Type:** string\n\n- **`--isolated`**\n  If specified, creates a temporary user-data-dir that is automatically cleaned up after the browser is closed. Defaults to false.\n  - **Type:** boolean\n\n- **`--userDataDir`/ `--user-data-dir`**\n  Path to the user data directory for Chrome. Default is $HOME/.cache/chrome-devtools-mcp/chrome-profile$CHANNEL_SUFFIX_IF_NON_STABLE\n  - **Type:** string\n\n- **`--channel`**\n  Specify a different Chrome channel that should be used. The default is the stable channel version.\n  - **Type:** string\n  - **Choices:** `stable`, `canary`, `beta`, `dev`\n\n- **`--logFile`/ `--log-file`**\n  Path to a file to write debug logs to. Set the env variable `DEBUG` to `*` to enable verbose logs. Useful for submitting bug reports.\n  - **Type:** string\n\n- **`--viewport`**\n  Initial viewport size for the Chrome instances started by the server. For example, `1280x720`. In headless mode, max size is 3840x2160px.\n  - **Type:** string\n\n- **`--proxyServer`/ `--proxy-server`**\n  Proxy server configuration for Chrome passed as --proxy-server when launching the browser. See https://www.chromium.org/developers/design-documents/network-settings/ for details.\n  - **Type:** string\n\n- **`--acceptInsecureCerts`/ `--accept-insecure-certs`**\n  If enabled, ignores errors relative to self-signed and expired certificates. Use with caution.\n  - **Type:** boolean\n\n- **`--experimentalScreencast`/ `--experimental-screencast`**\n  Exposes experimental screencast tools (requires ffmpeg). Install ffmpeg https://www.ffmpeg.org/download.html and ensure it is available in the MCP server PATH.\n  - **Type:** boolean\n\n- **`--chromeArg`/ `--chrome-arg`**\n  Additional arguments for Chrome. Only applies when Chrome is launched by chrome-devtools-mcp.\n  - **Type:** array\n\n- **`--ignoreDefaultChromeArg`/ `--ignore-default-chrome-arg`**\n  Explicitly disable default arguments for Chrome. Only applies when Chrome is launched by chrome-devtools-mcp.\n  - **Type:** array\n\n- **`--categoryEmulation`/ `--category-emulation`**\n  Set to false to exclude tools related to emulation.\n  - **Type:** boolean\n  - **Default:** `true`\n\n- **`--categoryPerformance`/ `--category-performance`**\n  Set to false to exclude tools related to performance.\n  - **Type:** boolean\n  - **Default:** `true`\n\n- **`--categoryNetwork`/ `--category-network`**\n  Set to false to exclude tools related to network.\n  - **Type:** boolean\n  - **Default:** `true`\n\n- **`--performanceCrux`/ `--performance-crux`**\n  Set to false to disable sending URLs from performance traces to CrUX API to get field performance data.\n  - **Type:** boolean\n  - **Default:** `true`\n\n- **`--usageStatistics`/ `--usage-statistics`**\n  Set to false to opt-out of usage statistics collection. Google collects usage data to improve the tool, handled under the Google Privacy Policy (https://policies.google.com/privacy). This is independent from Chrome browser metrics. Disabled if CHROME_DEVTOOLS_MCP_NO_USAGE_STATISTICS or CI env variables are set.\n  - **Type:** boolean\n  - **Default:** `true`\n\n- **`--slim`**\n  Exposes a \"slim\" set of 3 tools covering navigation, script execution and screenshots only. Useful for basic browser tasks.\n  - **Type:** boolean\n\n<!-- END AUTO GENERATED OPTIONS -->\n\nPass them via the `args` property in the JSON configuration. For example:\n\n```json\n{\n  \"mcpServers\": {\n    \"chrome-devtools\": {\n      \"command\": \"npx\",\n      \"args\": [\n        \"chrome-devtools-mcp@latest\",\n        \"--channel=canary\",\n        \"--headless=true\",\n        \"--isolated=true\"\n      ]\n    }\n  }\n}\n```\n\n### Connecting via WebSocket with custom headers\n\nYou can connect directly to a Chrome WebSocket endpoint and include custom headers (e.g., for authentication):\n\n```json\n{\n  \"mcpServers\": {\n    \"chrome-devtools\": {\n      \"command\": \"npx\",\n      \"args\": [\n        \"chrome-devtools-mcp@latest\",\n        \"--wsEndpoint=ws://127.0.0.1:9222/devtools/browser/<id>\",\n        \"--wsHeaders={\\\"Authorization\\\":\\\"Bearer YOUR_TOKEN\\\"}\"\n      ]\n    }\n  }\n}\n```\n\nTo get the WebSocket endpoint from a running Chrome instance, visit `http://127.0.0.1:9222/json/version` and look for the `webSocketDebuggerUrl` field.\n\nYou can also run `npx chrome-devtools-mcp@latest --help` to see all available configuration options.\n\n## Concepts\n\n### User data directory\n\n`chrome-devtools-mcp` starts a Chrome's stable channel instance using the following user\ndata directory:\n\n- Linux / macOS: `$HOME/.cache/chrome-devtools-mcp/chrome-profile-$CHANNEL`\n- Windows: `%HOMEPATH%/.cache/chrome-devtools-mcp/chrome-profile-$CHANNEL`\n\nThe user data directory is not cleared between runs and shared across\nall instances of `chrome-devtools-mcp`. Set the `isolated` option to `true`\nto use a temporary user data dir instead which will be cleared automatically after\nthe browser is closed.\n\n### Connecting to a running Chrome instance\n\nBy default, the Chrome DevTools MCP server will start a new Chrome instance with a dedicated profile. This might not be ideal in all situations:\n\n- If you would like to maintain the same application state when alternating between manual site testing and agent-driven testing.\n- When the MCP needs to sign into a website. Some accounts may prevent sign-in when the browser is controlled via WebDriver (the default launch mechanism for the Chrome DevTools MCP server).\n- If you're running your LLM inside a sandboxed environment, but you would like to connect to a Chrome instance that runs outside the sandbox.\n\nIn these cases, start Chrome first and let the Chrome DevTools MCP server connect to it. There are two ways to do so:\n\n- **Automatic connection (available in Chrome 144)**: best for sharing state between manual and agent-driven testing.\n- **Manual connection via remote debugging port**: best when running inside a sandboxed environment.\n\n#### Automatically connecting to a running Chrome instance\n\n**Step 1:** Set up remote debugging in Chrome\n\nIn Chrome (\\>= M144), do the following to set up remote debugging:\n\n1.  Navigate to `chrome://inspect/#remote-debugging` to enable remote debugging.\n2.  Follow the dialog UI to allow or disallow incoming debugging connections.\n\n**Step 2:** Configure Chrome DevTools MCP server to automatically connect to a running Chrome Instance\n\nTo connect the `chrome-devtools-mcp` server to the running Chrome instance, use\n`--autoConnect` command line argument for the MCP server.\n\nThe following code snippet is an example configuration for gemini-cli:\n\n```json\n{\n  \"mcpServers\": {\n    \"chrome-devtools\": {\n      \"command\": \"npx\",\n      \"args\": [\"chrome-devtools-mcp@latest\", \"--autoConnect\"]\n    }\n  }\n}\n```\n\n**Step 3:** Test your setup\n\nMake sure your browser is running. Open gemini-cli and run the following prompt:\n\n```none\nCheck the performance of https://developers.chrome.com\n```\n\n> [!NOTE]  \n> The <code>autoConnect</code> option requires the user to start Chrome. If the user has multiple active profiles, the MCP server will connect to the default profile (as determined by Chrome). The MCP server has access to all open windows for the selected profile.\n\nThe Chrome DevTools MCP server will try to connect to your running Chrome\ninstance. It shows a dialog asking for user permission.\n\nClicking **Allow** results in the Chrome DevTools MCP server opening\n[developers.chrome.com](http://developers.chrome.com) and taking a performance\ntrace.\n\n#### Manual connection using port forwarding\n\nYou can connect to a running Chrome instance by using the `--browser-url` option. This is useful if you are running the MCP server in a sandboxed environment that does not allow starting a new Chrome instance.\n\nHere is a step-by-step guide on how to connect to a running Chrome instance:\n\n**Step 1: Configure the MCP client**\n\nAdd the `--browser-url` option to your MCP client configuration. The value of this option should be the URL of the running Chrome instance. `http://127.0.0.1:9222` is a common default.\n\n```json\n{\n  \"mcpServers\": {\n    \"chrome-devtools\": {\n      \"command\": \"npx\",\n      \"args\": [\n        \"chrome-devtools-mcp@latest\",\n        \"--browser-url=http://127.0.0.1:9222\"\n      ]\n    }\n  }\n}\n```\n\n**Step 2: Start the Chrome browser**\n\n> [!WARNING]  \n> Enabling the remote debugging port opens up a debugging port on the running browser instance. Any application on your machine can connect to this port and control the browser. Make sure that you are not browsing any sensitive websites while the debugging port is open.\n\nStart the Chrome browser with the remote debugging port enabled. Make sure to close any running Chrome instances before starting a new one with the debugging port enabled. The port number you choose must be the same as the one you specified in the `--browser-url` option in your MCP client configuration.\n\nFor security reasons, [Chrome requires you to use a non-default user data directory](https://developer.chrome.com/blog/remote-debugging-port) when enabling the remote debugging port. You can specify a custom directory using the `--user-data-dir` flag. This ensures that your regular browsing profile and data are not exposed to the debugging session.\n\n**macOS**\n\n```bash\n/Applications/Google\\ Chrome.app/Contents/MacOS/Google\\ Chrome --remote-debugging-port=9222 --user-data-dir=/tmp/chrome-profile-stable\n```\n\n**Linux**\n\n```bash\n/usr/bin/google-chrome --remote-debugging-port=9222 --user-data-dir=/tmp/chrome-profile-stable\n```\n\n**Windows**\n\n```bash\n\"C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe\" --remote-debugging-port=9222 --user-data-dir=\"%TEMP%\\chrome-profile-stable\"\n```\n\n**Step 3: Test your setup**\n\nAfter configuring the MCP client and starting the Chrome browser, you can test your setup by running a simple prompt in your MCP client:\n\n```\nCheck the performance of https://developers.chrome.com\n```\n\nYour MCP client should connect to the running Chrome instance and receive a performance report.\n\nIf you hit VM-to-host port forwarding issues, see the “Remote debugging between virtual machine (VM) and host fails” section in [`docs/troubleshooting.md`](./docs/troubleshooting.md#remote-debugging-between-virtual-machine-vm-and-host-fails).\n\nFor more details on remote debugging, see the [Chrome DevTools documentation](https://developer.chrome.com/docs/devtools/remote-debugging/).\n\n### Debugging Chrome on Android\n\nPlease consult [these instructions](./docs/debugging-android.md).\n\n## Known limitations\n\nSee [Troubleshooting](./docs/troubleshooting.md).\n"
  },
  {
    "path": "SECURITY.md",
    "content": "## Security policy\n\nThe Chrome DevTools MCP project takes security very seriously. Please use [Chromium’s process to report security issues](https://www.chromium.org/Home/chromium-security/reporting-security-bugs/).\n"
  },
  {
    "path": "docs/cli.md",
    "content": "# Chrome DevTools CLI\n\nThe `chrome-devtools-mcp` package includes an **experimental** CLI interface that allows you to interact with the browser directly from your terminal. This is particularly useful for debugging or when you want an agent to generate scripts that automate browser actions.\n\n## Getting started\n\nInstall the package globally to make the `chrome-devtools` command available:\n\n```sh\nnpm i chrome-devtools-mcp@latest -g\nchrome-devtools status # check if install worked.\n```\n\n## How it works\n\nThe CLI acts as a client to a background `chrome-devtools-mcp` daemon (uses Unix sockets on Linux/Mac and named pipes on Windows).\n\n- **Automatic Start**: The first time you call a tool (e.g., `list_pages`), the CLI automatically starts the MCP server and the browser in the background if they aren't already running.\n- **Persistence**: The same background instance is reused for subsequent commands, preserving the browser state (open pages, cookies, etc.).\n- **Manual Control**: You can explicitly manage the background process using `start`, `stop`, and `status`. The `start` command forwards all subsequent arguments to the underlying MCP server (e.g., `--headless`, `--userDataDir`) but not all args are supported. Run `chrome-devtools start --help` for supported args. Headless and isolated are enabled by default.\n\n```sh\n# Check if the daemon is running\nchrome-devtools status\n\n# Navigate the current page to a URL\nchrome-devtools navigate_page \"https://google.com\"\n\n# Take a screenshot and save it to a file\nchrome-devtools take_screenshot --filePath screenshot.png\n\n# Stop the background daemon when finished\nchrome-devtools stop\n```\n\n## Command Usage\n\nThe CLI supports all tools available in the [Tool reference](./tool-reference.md).\n\n```sh\nchrome-devtools <tool> [arguments] [flags]\n```\n\n- **Required Arguments**: Passed as positional arguments.\n- **Optional Arguments**: Passed as flags (e.g., `--filePath`, `--fullPage`).\n\n### Examples\n\n**New Page and Navigation:**\n\n```sh\nchrome-devtools new_page \"https://example.com\"\nchrome-devtools navigate_page \"https://web.dev\" --type url\n```\n\n**Interaction:**\n\n```sh\n# Click an element by its UID from a snapshot\nchrome-devtools click \"element-uid-123\"\n\n# Fill a form field\nchrome-devtools fill \"input-uid-456\" \"search query\"\n```\n\n**Analysis:**\n\n```sh\n# Run a Lighthouse audit (defaults to navigation mode)\nchrome-devtools lighthouse_audit --mode snapshot\n```\n\n## Output format\n\nBy default, the CLI outputs a human-readable summary of the tool's result. For programmatic use, you can request raw JSON:\n\n```sh\nchrome-devtools list_pages --output-format=json\n```\n\n## Troubleshooting\n\nIf the CLI hangs or fails to connect, try stopping the background process:\n\n```sh\nchrome-devtools stop\n```\n\nFor more verbose logs, set the `DEBUG` environment variable:\n\n```sh\nDEBUG=* chrome-devtools list_pages\n```\n\n## CLI generation\n\nImplemented in `scripts/generate-cli.ts`. Some commands are excluded from CLI\ngeneration such as `wait_for` and `fill_form`.\n\n`chrome-devtools-mcp` args are also filtered in `src/bin/chrome-devtools.ts`\nbecause not all args make sense in a CLI interface.\n"
  },
  {
    "path": "docs/debugging-android.md",
    "content": "# Experimental: Debugging Chrome on Android\n\nThis is an experimental feature as Puppeteer does not officially support Chrome on Android as a target.\n\nThe workflow below works for most users. See [Troubleshooting: DevTools is not detecting the Android device for more help](https://developer.chrome.com/docs/devtools/remote-debugging#troubleshooting) for more help.\n\n1. Open the Developer Options screen on your Android. See [Configure on-device developer Options](https://developer.android.com/studio/debug/dev-options.html).\n2. Select Enable USB Debugging.\n3. Connect your Android device directly to your development machine using a USB cable.\n4. On your development machine setup port forwarding from your development machine to your android device:\n   ```shell\n   adb forward tcp:9222 localabstract:chrome_devtools_remote\n   ```\n5. Configure your MCP server to connect to the Chrome\n   ```json\n   \"chrome-devtools\": {\n     \"command\": \"npx\",\n     \"args\": [\n       \"chrome-devtools-mcp@latest\",\n       \"--wsEndpoint=ws://127.0.0.1:9222/devtools/browser/\"\n     ],\n     \"trust\": true\n   }\n   ```\n6. Test your setup by running the following prompt in your coding agent:\n   ```none\n   Check the performance of developers.chrome.com\n   ```\n\nThe Chrome DevTools MCP server should now control Chrome on your Android device.\n"
  },
  {
    "path": "docs/design-principles.md",
    "content": "# Design Principles\n\nThese are rough guidelines to follow when shipping features for the MCP server.\nApply them with nuance.\n\n- **Agent-Agnostic API**: Use standards like MCP. Don't lock in to one LLM. Interoperability is key.\n- **Token-Optimized**: Return semantic summaries. \"LCP was 3.2s\" is better than 50k lines of JSON. Files are the right location for large amounts of data.\n- **Small, Deterministic Blocks**: Give agents composable tools (Click, Screenshot), not magic buttons.\n- **Self-Healing Errors**: Return actionable errors that include context and potential fixes.\n- **Human-Agent Collaboration**: Output must be readable by machines (structured) AND humans (summaries).\n- **Progressive Complexity**: Tools should be simple by default (high-level actions) but offer advanced optional arguments for power users.\n- **Reference over Value**: for heavy assets (screenshots, traces, videos), return a file path or resource URI, never the raw data stream. Some MCP clients support a built-in handling of heavy assets e.g. directly displaying images. This _could_ be an exception.\n"
  },
  {
    "path": "docs/slim-tool-reference.md",
    "content": "<!-- AUTO GENERATED DO NOT EDIT - run 'npm run gen' to update-->\n\n# Chrome DevTools MCP Slim Tool Reference (~359 cl100k_base tokens)\n\n- **[Navigation automation](#navigation-automation)** (1 tools)\n  - [`navigate`](#navigate)\n- **[Debugging](#debugging)** (2 tools)\n  - [`evaluate`](#evaluate)\n  - [`screenshot`](#screenshot)\n\n## Navigation automation\n\n### `navigate`\n\n**Description:** Loads a URL\n\n**Parameters:**\n\n- **url** (string) **(required)**: URL to [`navigate`](#navigate) to\n\n---\n\n## Debugging\n\n### `evaluate`\n\n**Description:** Evaluates a JavaScript script\n\n**Parameters:**\n\n- **script** (string) **(required)**: JS script to run on the page\n\n---\n\n### `screenshot`\n\n**Description:** Takes a [`screenshot`](#screenshot)\n\n**Parameters:** None\n\n---\n"
  },
  {
    "path": "docs/tool-reference.md",
    "content": "<!-- AUTO GENERATED DO NOT EDIT - run 'npm run gen' to update-->\n\n# Chrome DevTools MCP Tool Reference (~6940 cl100k_base tokens)\n\n- **[Input automation](#input-automation)** (9 tools)\n  - [`click`](#click)\n  - [`drag`](#drag)\n  - [`fill`](#fill)\n  - [`fill_form`](#fill_form)\n  - [`handle_dialog`](#handle_dialog)\n  - [`hover`](#hover)\n  - [`press_key`](#press_key)\n  - [`type_text`](#type_text)\n  - [`upload_file`](#upload_file)\n- **[Navigation automation](#navigation-automation)** (6 tools)\n  - [`close_page`](#close_page)\n  - [`list_pages`](#list_pages)\n  - [`navigate_page`](#navigate_page)\n  - [`new_page`](#new_page)\n  - [`select_page`](#select_page)\n  - [`wait_for`](#wait_for)\n- **[Emulation](#emulation)** (2 tools)\n  - [`emulate`](#emulate)\n  - [`resize_page`](#resize_page)\n- **[Performance](#performance)** (4 tools)\n  - [`performance_analyze_insight`](#performance_analyze_insight)\n  - [`performance_start_trace`](#performance_start_trace)\n  - [`performance_stop_trace`](#performance_stop_trace)\n  - [`take_memory_snapshot`](#take_memory_snapshot)\n- **[Network](#network)** (2 tools)\n  - [`get_network_request`](#get_network_request)\n  - [`list_network_requests`](#list_network_requests)\n- **[Debugging](#debugging)** (6 tools)\n  - [`evaluate_script`](#evaluate_script)\n  - [`get_console_message`](#get_console_message)\n  - [`lighthouse_audit`](#lighthouse_audit)\n  - [`list_console_messages`](#list_console_messages)\n  - [`take_screenshot`](#take_screenshot)\n  - [`take_snapshot`](#take_snapshot)\n\n## Input automation\n\n### `click`\n\n**Description:** Clicks on the provided element\n\n**Parameters:**\n\n- **uid** (string) **(required)**: The uid of an element on the page from the page content snapshot\n- **dblClick** (boolean) _(optional)_: Set to true for double clicks. Default is false.\n- **includeSnapshot** (boolean) _(optional)_: Whether to include a snapshot in the response. Default is false.\n\n---\n\n### `drag`\n\n**Description:** [`Drag`](#drag) an element onto another element\n\n**Parameters:**\n\n- **from_uid** (string) **(required)**: The uid of the element to [`drag`](#drag)\n- **to_uid** (string) **(required)**: The uid of the element to drop into\n- **includeSnapshot** (boolean) _(optional)_: Whether to include a snapshot in the response. Default is false.\n\n---\n\n### `fill`\n\n**Description:** Type text into a input, text area or select an option from a &lt;select&gt; element.\n\n**Parameters:**\n\n- **uid** (string) **(required)**: The uid of an element on the page from the page content snapshot\n- **value** (string) **(required)**: The value to [`fill`](#fill) in\n- **includeSnapshot** (boolean) _(optional)_: Whether to include a snapshot in the response. Default is false.\n\n---\n\n### `fill_form`\n\n**Description:** [`Fill`](#fill) out multiple form elements at once\n\n**Parameters:**\n\n- **elements** (array) **(required)**: Elements from snapshot to [`fill`](#fill) out.\n- **includeSnapshot** (boolean) _(optional)_: Whether to include a snapshot in the response. Default is false.\n\n---\n\n### `handle_dialog`\n\n**Description:** If a browser dialog was opened, use this command to handle it\n\n**Parameters:**\n\n- **action** (enum: \"accept\", \"dismiss\") **(required)**: Whether to dismiss or accept the dialog\n- **promptText** (string) _(optional)_: Optional prompt text to enter into the dialog.\n\n---\n\n### `hover`\n\n**Description:** [`Hover`](#hover) over the provided element\n\n**Parameters:**\n\n- **uid** (string) **(required)**: The uid of an element on the page from the page content snapshot\n- **includeSnapshot** (boolean) _(optional)_: Whether to include a snapshot in the response. Default is false.\n\n---\n\n### `press_key`\n\n**Description:** Press a key or key combination. Use this when other input methods like [`fill`](#fill)() cannot be used (e.g., keyboard shortcuts, navigation keys, or special key combinations).\n\n**Parameters:**\n\n- **key** (string) **(required)**: A key or a combination (e.g., \"Enter\", \"Control+A\", \"Control++\", \"Control+Shift+R\"). Modifiers: Control, Shift, Alt, Meta\n- **includeSnapshot** (boolean) _(optional)_: Whether to include a snapshot in the response. Default is false.\n\n---\n\n### `type_text`\n\n**Description:** Type text using keyboard into a previously focused input\n\n**Parameters:**\n\n- **text** (string) **(required)**: The text to type\n- **submitKey** (string) _(optional)_: Optional key to press after typing. E.g., \"Enter\", \"Tab\", \"Escape\"\n\n---\n\n### `upload_file`\n\n**Description:** Upload a file through a provided element.\n\n**Parameters:**\n\n- **filePath** (string) **(required)**: The local path of the file to upload\n- **uid** (string) **(required)**: The uid of the file input element or an element that will open file chooser on the page from the page content snapshot\n- **includeSnapshot** (boolean) _(optional)_: Whether to include a snapshot in the response. Default is false.\n\n---\n\n## Navigation automation\n\n### `close_page`\n\n**Description:** Closes the page by its index. The last open page cannot be closed.\n\n**Parameters:**\n\n- **pageId** (number) **(required)**: The ID of the page to close. Call [`list_pages`](#list_pages) to list pages.\n\n---\n\n### `list_pages`\n\n**Description:** Get a list of pages open in the browser.\n\n**Parameters:** None\n\n---\n\n### `navigate_page`\n\n**Description:** Go to a URL, or back, forward, or reload. Use project URL if not specified otherwise.\n\n**Parameters:**\n\n- **handleBeforeUnload** (enum: \"accept\", \"decline\") _(optional)_: Whether to auto accept or beforeunload dialogs triggered by this navigation. Default is accept.\n- **ignoreCache** (boolean) _(optional)_: Whether to ignore cache on reload.\n- **initScript** (string) _(optional)_: A JavaScript script to be executed on each new document before any other scripts for the next navigation.\n- **timeout** (integer) _(optional)_: Maximum wait time in milliseconds. If set to 0, the default timeout will be used.\n- **type** (enum: \"url\", \"back\", \"forward\", \"reload\") _(optional)_: Navigate the page by URL, back or forward in history, or reload.\n- **url** (string) _(optional)_: Target URL (only type=url)\n\n---\n\n### `new_page`\n\n**Description:** Open a new tab and load a URL. Use project URL if not specified otherwise.\n\n**Parameters:**\n\n- **url** (string) **(required)**: URL to load in a new page.\n- **background** (boolean) _(optional)_: Whether to open the page in the background without bringing it to the front. Default is false (foreground).\n- **isolatedContext** (string) _(optional)_: If specified, the page is created in an isolated browser context with the given name. Pages in the same browser context share cookies and storage. Pages in different browser contexts are fully isolated.\n- **timeout** (integer) _(optional)_: Maximum wait time in milliseconds. If set to 0, the default timeout will be used.\n\n---\n\n### `select_page`\n\n**Description:** Select a page as a context for future tool calls.\n\n**Parameters:**\n\n- **pageId** (number) **(required)**: The ID of the page to select. Call [`list_pages`](#list_pages) to get available pages.\n- **bringToFront** (boolean) _(optional)_: Whether to focus the page and bring it to the top.\n\n---\n\n### `wait_for`\n\n**Description:** Wait for the specified text to appear on the selected page.\n\n**Parameters:**\n\n- **text** (array) **(required)**: Non-empty list of texts. Resolves when any value appears on the page.\n- **timeout** (integer) _(optional)_: Maximum wait time in milliseconds. If set to 0, the default timeout will be used.\n\n---\n\n## Emulation\n\n### `emulate`\n\n**Description:** Emulates various features on the selected page.\n\n**Parameters:**\n\n- **colorScheme** (enum: \"dark\", \"light\", \"auto\") _(optional)_: [`Emulate`](#emulate) the dark or the light mode. Set to \"auto\" to reset to the default.\n- **cpuThrottlingRate** (number) _(optional)_: Represents the CPU slowdown factor. Omit or set the rate to 1 to disable throttling\n- **geolocation** (string) _(optional)_: Geolocation (`&lt;latitude&gt;x&lt;longitude&gt;`) to [`emulate`](#emulate). Latitude between -90 and 90. Longitude between -180 and 180. Omit clear the geolocation override.\n- **networkConditions** (enum: \"Offline\", \"Slow 3G\", \"Fast 3G\", \"Slow 4G\", \"Fast 4G\") _(optional)_: Throttle network. Omit to disable throttling.\n- **userAgent** (string) _(optional)_: User agent to [`emulate`](#emulate). Set to empty string to clear the user agent override.\n- **viewport** (string) _(optional)_: [`Emulate`](#emulate) device viewports '&lt;width&gt;x&lt;height&gt;x&lt;devicePixelRatio&gt;[,mobile][,touch][,landscape]'. 'touch' and 'mobile' to [`emulate`](#emulate) mobile devices. 'landscape' to [`emulate`](#emulate) landscape mode.\n\n---\n\n### `resize_page`\n\n**Description:** Resizes the selected page's window so that the page has specified dimension\n\n**Parameters:**\n\n- **height** (number) **(required)**: Page height\n- **width** (number) **(required)**: Page width\n\n---\n\n## Performance\n\n### `performance_analyze_insight`\n\n**Description:** Provides more detailed information on a specific Performance Insight of an insight set that was highlighted in the results of a trace recording.\n\n**Parameters:**\n\n- **insightName** (string) **(required)**: The name of the Insight you want more information on. For example: \"DocumentLatency\" or \"LCPBreakdown\"\n- **insightSetId** (string) **(required)**: The id for the specific insight set. Only use the ids given in the \"Available insight sets\" list.\n\n---\n\n### `performance_start_trace`\n\n**Description:** Start a performance trace on the selected webpage. Use to find frontend performance issues, Core Web Vitals (LCP, INP, CLS), and improve page load speed.\n\n**Parameters:**\n\n- **autoStop** (boolean) _(optional)_: Determines if the trace recording should be automatically stopped.\n- **filePath** (string) _(optional)_: The absolute file path, or a file path relative to the current working directory, to save the raw trace data. For example, trace.json.gz (compressed) or trace.json (uncompressed).\n- **reload** (boolean) _(optional)_: Determines if, once tracing has started, the current selected page should be automatically reloaded. Navigate the page to the right URL using the [`navigate_page`](#navigate_page) tool BEFORE starting the trace if reload or autoStop is set to true.\n\n---\n\n### `performance_stop_trace`\n\n**Description:** Stop the active performance trace recording on the selected webpage.\n\n**Parameters:**\n\n- **filePath** (string) _(optional)_: The absolute file path, or a file path relative to the current working directory, to save the raw trace data. For example, trace.json.gz (compressed) or trace.json (uncompressed).\n\n---\n\n### `take_memory_snapshot`\n\n**Description:** Capture a memory heapsnapshot of the currently selected page to memory leak debugging\n\n**Parameters:**\n\n- **filePath** (string) **(required)**: A path to a .heapsnapshot file to save the heapsnapshot to.\n\n---\n\n## Network\n\n### `get_network_request`\n\n**Description:** Gets a network request by an optional reqid, if omitted returns the currently selected request in the DevTools Network panel.\n\n**Parameters:**\n\n- **reqid** (number) _(optional)_: The reqid of the network request. If omitted returns the currently selected request in the DevTools Network panel.\n- **requestFilePath** (string) _(optional)_: The absolute or relative path to save the request body to. If omitted, the body is returned inline.\n- **responseFilePath** (string) _(optional)_: The absolute or relative path to save the response body to. If omitted, the body is returned inline.\n\n---\n\n### `list_network_requests`\n\n**Description:** List all requests for the currently selected page since the last navigation.\n\n**Parameters:**\n\n- **includePreservedRequests** (boolean) _(optional)_: Set to true to return the preserved requests over the last 3 navigations.\n- **pageIdx** (integer) _(optional)_: Page number to return (0-based). When omitted, returns the first page.\n- **pageSize** (integer) _(optional)_: Maximum number of requests to return. When omitted, returns all requests.\n- **resourceTypes** (array) _(optional)_: Filter requests to only return requests of the specified resource types. When omitted or empty, returns all requests.\n\n---\n\n## Debugging\n\n### `evaluate_script`\n\n**Description:** Evaluate a JavaScript function inside the currently selected page. Returns the response as JSON,\nso returned values have to be JSON-serializable.\n\n**Parameters:**\n\n- **function** (string) **(required)**: A JavaScript function declaration to be executed by the tool in the currently selected page.\n  Example without arguments: `() => {\n  return document.title\n}` or `async () => {\n  return await fetch(\"example.com\")\n}`.\n  Example with arguments: `(el) => {\n  return el.innerText;\n}`\n\n- **args** (array) _(optional)_: An optional list of arguments to pass to the function.\n\n---\n\n### `get_console_message`\n\n**Description:** Gets a console message by its ID. You can get all messages by calling [`list_console_messages`](#list_console_messages).\n\n**Parameters:**\n\n- **msgid** (number) **(required)**: The msgid of a console message on the page from the listed console messages\n\n---\n\n### `lighthouse_audit`\n\n**Description:** Get Lighthouse score and reports for accessibility, SEO and best practices. This excludes performance. For performance audits, run [`performance_start_trace`](#performance_start_trace)\n\n**Parameters:**\n\n- **device** (enum: \"desktop\", \"mobile\") _(optional)_: Device to [`emulate`](#emulate).\n- **mode** (enum: \"navigation\", \"snapshot\") _(optional)_: \"navigation\" reloads &amp; audits. \"snapshot\" analyzes current state.\n- **outputDirPath** (string) _(optional)_: Directory for reports. If omitted, uses temporary files.\n\n---\n\n### `list_console_messages`\n\n**Description:** List all console messages for the currently selected page since the last navigation.\n\n**Parameters:**\n\n- **includePreservedMessages** (boolean) _(optional)_: Set to true to return the preserved messages over the last 3 navigations.\n- **pageIdx** (integer) _(optional)_: Page number to return (0-based). When omitted, returns the first page.\n- **pageSize** (integer) _(optional)_: Maximum number of messages to return. When omitted, returns all requests.\n- **types** (array) _(optional)_: Filter messages to only return messages of the specified resource types. When omitted or empty, returns all messages.\n\n---\n\n### `take_screenshot`\n\n**Description:** Take a screenshot of the page or element.\n\n**Parameters:**\n\n- **filePath** (string) _(optional)_: The absolute path, or a path relative to the current working directory, to save the screenshot to instead of attaching it to the response.\n- **format** (enum: \"png\", \"jpeg\", \"webp\") _(optional)_: Type of format to save the screenshot as. Default is \"png\"\n- **fullPage** (boolean) _(optional)_: If set to true takes a screenshot of the full page instead of the currently visible viewport. Incompatible with uid.\n- **quality** (number) _(optional)_: Compression quality for JPEG and WebP formats (0-100). Higher values mean better quality but larger file sizes. Ignored for PNG format.\n- **uid** (string) _(optional)_: The uid of an element on the page from the page content snapshot. If omitted takes a pages screenshot.\n\n---\n\n### `take_snapshot`\n\n**Description:** Take a text snapshot of the currently selected page based on the a11y tree. The snapshot lists page elements along with a unique\nidentifier (uid). Always use the latest snapshot. Prefer taking a snapshot over taking a screenshot. The snapshot indicates the element selected\nin the DevTools Elements panel (if any).\n\n**Parameters:**\n\n- **filePath** (string) _(optional)_: The absolute path, or a path relative to the current working directory, to save the snapshot to instead of attaching it to the response.\n- **verbose** (boolean) _(optional)_: Whether to include all possible information available in the full a11y tree. Default is false.\n\n---\n"
  },
  {
    "path": "docs/troubleshooting.md",
    "content": "# Troubleshooting\n\n## General tips\n\n- Run `npx chrome-devtools-mcp@latest --help` to test if the MCP server runs on your machine.\n- Make sure that your MCP client uses the same npm and node version as your terminal.\n- When configuring your MCP client, try using the `--yes` argument to `npx` to\n  auto-accept installation prompt.\n- Find a specific error in the output of the `chrome-devtools-mcp` server.\n  Usually, if your client is an IDE, logs would be in the Output pane.\n- Search the [GitHub repository issues and discussions](https://github.com/ChromeDevTools/chrome-devtools-mcp) for help or existing similar problems.\n\n## Debugging\n\nStart the MCP server with debugging enabled and a log file:\n\n- `DEBUG=* npx chrome-devtools-mcp@latest --log-file=/path/to/chrome-devtools-mcp.log`\n\nUsing `.mcp.json` to debug while using a client:\n\n```json\n{\n  \"mcpServers\": {\n    \"chrome-devtools\": {\n      \"type\": \"stdio\",\n      \"command\": \"npx\",\n      \"args\": [\n        \"chrome-devtools-mcp@latest\",\n        \"--log-file\",\n        \"/path/to/chrome-devtools-mcp.log\"\n      ],\n      \"env\": {\n        \"DEBUG\": \"*\"\n      }\n    }\n  }\n}\n```\n\n## Specific problems\n\n### `Error [ERR_MODULE_NOT_FOUND]: Cannot find module ...`\n\nThis usually indicates either a non-supported Node version is in use or that the\n`npm`/`npx` cache is corrupted. Try clearing the cache, uninstalling\n`chrome-devtools-mcp` and installing it again. Clear the cache by running:\n\n```sh\nrm -rf ~/.npm/_npx # NOTE: this might remove other installed npx executables.\nnpm cache clean --force\n```\n\n### `Target closed` error\n\nThis indicates that the browser could not be started. Make sure that no Chrome\ninstances are running or close them. Make sure you have the latest stable Chrome\ninstalled and that [your system is able to run Chrome](https://support.google.com/chrome/a/answer/7100626?hl=en).\n\n### Chrome crashes on macOS when using Web Bluetooth\n\nOn macOS, Chrome launched by an MCP client application (such as Claude Desktop) may crash when a Web Bluetooth prompt appears. This is caused by a macOS privacy permission violation (TCC).\n\nTo resolve this, grant Bluetooth permission to the MCP client application in `System Settings > Privacy & Security > Bluetooth`. After granting permission, restart the client application and start a new MCP session.\n\n### Remote debugging between virtual machine (VM) and host fails\n\nWhen attempting to connect to Chrome running on a host machine from within a virtual machine (VM), Chrome may reject the connection due to 'Host' header validation. You can bypass this restriction by creating an SSH tunnel from the VM to the host. In the VM, run:\n\n```sh\nssh -N -L 127.0.0.1:9222:127.0.0.1:9222 <user>@<host-ip>\n```\n\nPoint the MCP connection inside the VM to `http://127.0.0.1:9222`. This allows DevTools to reach the host browser without triggering the Host validation error.\n\n### Operating system sandboxes\n\nSome MCP clients allow sandboxing the MCP server using macOS Seatbelt or Linux\ncontainers. If sandboxes are enabled, `chrome-devtools-mcp` is not able to start\nChrome that requires permissions to create its own sandboxes. As a workaround,\neither disable sandboxing for `chrome-devtools-mcp` in your MCP client or use\n`--browser-url` to connect to a Chrome instance that you start manually outside\nof the MCP client sandbox.\n\n### WSL\n\nBy default, `chrome-devtools-mcp` in WSL requires Chrome to be installed within the Linux environment. While it normally attempts to launch Chrome on the Windows side, this currently fails due to a [known WSL issue](https://github.com/microsoft/WSL/issues/14201). Ensure you are using a [Linux distribution compatible with Chrome](https://support.google.com/chrome/a/answer/7100626).\n\nPossible workarounds include:\n\n- **Install Google Chrome in WSL:**\n  - `wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb`\n  - `sudo dpkg -i google-chrome-stable_current_amd64.deb`\n\n- **Use Mirrored networking:**\n  1. Configure [Mirrored networking for WSL](https://learn.microsoft.com/en-us/windows/wsl/networking).\n  2. Start Chrome on the Windows side with:\n     `chrome.exe --remote-debugging-port=9222 --user-data-dir=C:\\path\\to\\dir`\n  3. Start `chrome-devtools-mcp` with:\n     `npx chrome-devtools-mcp --browser-url http://127.0.0.1:9222`\n\n- **Use Powershell or Git Bash** instead of WSL.\n\n### Windows 10: Error during discovery for MCP server 'chrome-devtools': MCP error -32000: Connection closed\n\n- **Solution 1** Call using `cmd` (For more info https://github.com/modelcontextprotocol/servers/issues/1082#issuecomment-2791786310)\n\n  ```json\n  \"mcpServers\": {\n      \"chrome-devtools\": {\n        \"command\": \"cmd\",\n        \"args\": [\"/c\", \"npx\", \"-y\", \"chrome-devtools-mcp@latest\"]\n      }\n    }\n  ```\n\n  > **The Key Change:** On Windows, running a Node.js package via `npx` often requires the `cmd /c` prefix to be executed correctly from within another process like VSCode's extension host. Therefore, `\"command\": \"npx\"` was replaced with `\"command\": \"cmd\"`, and the actual `npx` command was moved into the `\"args\"` array, preceded by `\"/c\"`. This fix allows Windows to interpret the command correctly and launch the server.\n\n- **Solution 2** Instead of another layer of shell you can write the absolute path to `npx`:\n  > Note: The path below is an example. You must adjust it to match the actual location of `npx` on your machine. Depending on your setup, the file extension might be `.cmd`, `.bat`, or `.exe` rather than `.ps1`. Also, ensure you use double backslashes (`\\\\`) as path delimiters, as required by the JSON format.\n  ```json\n  \"mcpServers\": {\n      \"chrome-devtools\": {\n        \"command\": \"C:\\\\nvm4w\\\\nodejs\\\\npx.ps1\",\n        \"args\": [\"-y\", \"chrome-devtools-mcp@latest\"]\n      }\n    }\n  ```\n\n### Claude Code plugin installation fails with `Failed to clone repository`\n\nWhen installing `chrome-devtools-mcp` as a Claude Code plugin (either from the\nofficial marketplace or via `/plugin marketplace add`), the installation may fail\nwith a timeout error if your environment cannot reach `github.com` on port 443\n(HTTPS):\n\n```\nFailed to download/cache plugin chrome-devtools-mcp: Failed to clone repository:\n  Cloning into '...'...\n  fatal: unable to access 'https://github.com/ChromeDevTools/chrome-devtools-mcp.git/':\n  Failed to connect to github.com port 443\n```\n\nThis can happen in environments with restricted outbound HTTPS connectivity,\ncorporate firewalls, or proxy configurations that block HTTPS git operations.\n\n**Workaround 1: Use SSH instead of HTTPS**\n\nIf you have SSH access to GitHub configured, you can redirect all GitHub HTTPS\nURLs to use SSH by running:\n\n```sh\ngit config --global url.\"git@github.com:\".insteadOf \"https://github.com/\"\n```\n\nThen retry the plugin installation. This tells git to use your SSH key for all\nGitHub operations instead of HTTPS.\n\n**Workaround 2: Install via CLI instead**\n\nIf the plugin marketplace approach fails, you can install `chrome-devtools-mcp`\nas an MCP server directly without cloning the repository:\n\n```sh\nclaude mcp add chrome-devtools --scope user npx chrome-devtools-mcp@latest\n```\n\nThis bypasses the git clone entirely and uses npm/npx to fetch the package. Note\nthat this method installs only the MCP server without the bundled skills.\n\n### Connection timeouts with `--autoConnect`\n\nIf you are using the `--autoConnect` flag and tools like `list_pages`, `new_page`, or `navigate_page` fail with a timeout (e.g., `ProtocolError: Network.enable timed out` or `The socket connection was closed unexpectedly`), this usually means the MCP server cannot handshake with the running Chrome instance correctly. Ensure:\n\n1. Chrome 144+ is **already** running.\n2. Remote debugging is enabled in Chrome via `chrome://inspect/#remote-debugging`.\n3. You have allowed the remote debugging connection prompt in the browser.\n4. There is no other MCP server or tool trying to connect to the same debugging port.\n"
  },
  {
    "path": "eslint.config.mjs",
    "content": "/**\n * @license\n * Copyright 2025 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport js from '@eslint/js';\nimport stylisticPlugin from '@stylistic/eslint-plugin';\nimport {defineConfig, globalIgnores} from 'eslint/config';\nimport importPlugin from 'eslint-plugin-import';\nimport globals from 'globals';\nimport tseslint from 'typescript-eslint';\n\nimport localPlugin from './scripts/eslint_rules/local-plugin.js';\n\nexport default defineConfig([\n  globalIgnores([\n    '**/node_modules',\n    '**/build/',\n    'tests/tools/fixtures/',\n    'src/third_party/lighthouse-devtools-mcp-bundle.js',\n  ]),\n  importPlugin.flatConfigs.typescript,\n  {\n    languageOptions: {\n      ecmaVersion: 'latest',\n      sourceType: 'module',\n\n      globals: {\n        ...globals.node,\n      },\n\n      parserOptions: {\n        projectService: {\n          allowDefaultProject: [\n            '.prettierrc.cjs',\n            'puppeteer.config.cjs',\n            'eslint.config.mjs',\n            'rollup.config.mjs',\n          ],\n        },\n      },\n\n      parser: tseslint.parser,\n    },\n\n    plugins: {\n      js,\n      '@local': localPlugin,\n      '@typescript-eslint': tseslint.plugin,\n      '@stylistic': stylisticPlugin,\n    },\n\n    settings: {\n      'import/resolver': {\n        typescript: true,\n      },\n    },\n\n    extends: ['js/recommended'],\n  },\n  tseslint.configs.recommended,\n  tseslint.configs.stylistic,\n  {\n    name: 'TypeScript rules',\n    rules: {\n      '@local/check-license': 'error',\n      curly: ['error', 'all'],\n\n      'no-undef': 'off',\n      'no-unused-vars': 'off',\n      '@typescript-eslint/no-unused-vars': [\n        'error',\n        {\n          argsIgnorePattern: '^_',\n          varsIgnorePattern: '^_',\n        },\n      ],\n      '@typescript-eslint/no-explicit-any': [\n        'error',\n        {\n          ignoreRestArgs: true,\n        },\n      ],\n      // This optimizes the dependency tracking for type-only files.\n      '@typescript-eslint/consistent-type-imports': 'error',\n      // So type-only exports get elided.\n      '@typescript-eslint/consistent-type-exports': 'error',\n      // Prefer interfaces over types for shape like.\n      '@typescript-eslint/consistent-type-definitions': ['error', 'interface'],\n      '@typescript-eslint/array-type': [\n        'error',\n        {\n          default: 'array-simple',\n        },\n      ],\n      '@typescript-eslint/no-floating-promises': 'error',\n\n      'import/order': [\n        'error',\n        {\n          'newlines-between': 'always',\n\n          alphabetize: {\n            order: 'asc',\n            caseInsensitive: true,\n          },\n        },\n      ],\n\n      'import/no-cycle': [\n        'error',\n        {\n          maxDepth: Infinity,\n        },\n      ],\n\n      'import/enforce-node-protocol-usage': ['error', 'always'],\n\n      '@stylistic/function-call-spacing': 'error',\n      '@stylistic/semi': 'error',\n\n      'no-restricted-imports': [\n        'error',\n        {\n          patterns: [\n            {\n              regex: '.*chrome-devtools-frontend/(?!mcp/mcp.js$).*',\n              message:\n                'Import only the devtools-frontend code exported via node_modules/chrome-devtools-frontend/mcp/mcp.js',\n            },\n          ],\n        },\n      ],\n    },\n  },\n  {\n    name: 'Tests',\n    files: ['**/*.test.ts'],\n    rules: {\n      // With the Node.js test runner, `describe` and `it` are technically\n      // promises, but we don't need to await them.\n      '@typescript-eslint/no-floating-promises': 'off',\n    },\n  },\n]);\n"
  },
  {
    "path": "gemini-extension.json",
    "content": "{\n  \"name\": \"chrome-devtools-mcp\",\n  \"version\": \"latest\",\n  \"mcpServers\": {\n    \"chrome-devtools\": {\n      \"command\": \"npx\",\n      \"args\": [\"chrome-devtools-mcp@latest\"]\n    }\n  }\n}\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"chrome-devtools-mcp\",\n  \"version\": \"0.20.2\",\n  \"description\": \"MCP server for Chrome DevTools\",\n  \"type\": \"module\",\n  \"bin\": {\n    \"chrome-devtools-mcp\": \"./build/src/bin/chrome-devtools-mcp.js\",\n    \"chrome-devtools\": \"./build/src/bin/chrome-devtools.js\"\n  },\n  \"main\": \"./build/src/index.js\",\n  \"scripts\": {\n    \"cli:generate\": \"node --experimental-strip-types scripts/generate-cli.ts\",\n    \"clean\": \"node -e \\\"require('fs').rmSync('build', {recursive: true, force: true})\\\"\",\n    \"bundle\": \"npm run clean && npm run build && rollup -c rollup.config.mjs && node -e \\\"require('fs').rmSync('build/node_modules', {recursive: true, force: true})\\\" && node --experimental-strip-types scripts/append-lighthouse-notices.ts\",\n    \"build\": \"tsc && node --experimental-strip-types --no-warnings=ExperimentalWarning scripts/post-build.ts\",\n    \"typecheck\": \"tsc --noEmit\",\n    \"format\": \"eslint --cache --fix . && prettier --write --cache .\",\n    \"check-format\": \"eslint --cache . && prettier --check --cache .;\",\n    \"gen\": \"npm run build && npm run docs:generate && npm run cli:generate && npm run format\",\n    \"docs:generate\": \"node --experimental-strip-types scripts/generate-docs.ts\",\n    \"start\": \"npm run build && node build/src/index.js\",\n    \"start-debug\": \"DEBUG=mcp:* DEBUG_COLORS=false npm run build && node build/src/index.js\",\n    \"test\": \"npm run build && node scripts/test.mjs\",\n    \"test:no-build\": \"node scripts/test.mjs\",\n    \"test:only\": \"npm run build && node scripts/test.mjs --test-only\",\n    \"test:update-snapshots\": \"npm run build && node scripts/test.mjs --test-update-snapshots\",\n    \"prepare\": \"node --experimental-strip-types scripts/prepare.ts\",\n    \"verify-server-json-version\": \"node --experimental-strip-types scripts/verify-server-json-version.ts\",\n    \"update-lighthouse\": \"node --experimental-strip-types scripts/update-lighthouse.ts\",\n    \"verify-npm-package\": \"node scripts/verify-npm-package.mjs\",\n    \"eval\": \"npm run build && node --experimental-strip-types scripts/eval_gemini.ts\",\n    \"count-tokens\": \"node --experimental-strip-types scripts/count_tokens.ts\"\n  },\n  \"files\": [\n    \"build/src\",\n    \"LICENSE\",\n    \"!*.tsbuildinfo\"\n  ],\n  \"repository\": \"ChromeDevTools/chrome-devtools-mcp\",\n  \"author\": \"Google LLC\",\n  \"license\": \"Apache-2.0\",\n  \"bugs\": {\n    \"url\": \"https://github.com/ChromeDevTools/chrome-devtools-mcp/issues\"\n  },\n  \"homepage\": \"https://github.com/ChromeDevTools/chrome-devtools-mcp#readme\",\n  \"mcpName\": \"io.github.ChromeDevTools/chrome-devtools-mcp\",\n  \"devDependencies\": {\n    \"@eslint/js\": \"^9.35.0\",\n    \"@google/genai\": \"^1.37.0\",\n    \"@modelcontextprotocol/sdk\": \"1.27.1\",\n    \"@rollup/plugin-commonjs\": \"^29.0.0\",\n    \"@rollup/plugin-json\": \"^6.1.0\",\n    \"@rollup/plugin-node-resolve\": \"^16.0.3\",\n    \"@stylistic/eslint-plugin\": \"^5.4.0\",\n    \"@types/debug\": \"^4.1.12\",\n    \"@types/filesystem\": \"^0.0.36\",\n    \"@types/node\": \"^25.0.0\",\n    \"@types/sinon\": \"^21.0.0\",\n    \"@types/yargs\": \"^17.0.33\",\n    \"@typescript-eslint/eslint-plugin\": \"^8.43.0\",\n    \"@typescript-eslint/parser\": \"^8.43.0\",\n    \"chrome-devtools-frontend\": \"1.0.1599001\",\n    \"core-js\": \"3.48.0\",\n    \"debug\": \"4.4.3\",\n    \"eslint\": \"^9.35.0\",\n    \"eslint-import-resolver-typescript\": \"^4.4.4\",\n    \"eslint-plugin-import\": \"^2.32.0\",\n    \"globals\": \"^17.0.0\",\n    \"lighthouse\": \"13.0.3\",\n    \"prettier\": \"^3.6.2\",\n    \"puppeteer\": \"24.39.1\",\n    \"rollup\": \"4.59.0\",\n    \"rollup-plugin-cleanup\": \"^3.2.1\",\n    \"rollup-plugin-license\": \"^3.6.0\",\n    \"sinon\": \"^21.0.0\",\n    \"tiktoken\": \"^1.0.22\",\n    \"typescript\": \"^5.9.2\",\n    \"typescript-eslint\": \"^8.43.0\",\n    \"yargs\": \"18.0.0\"\n  },\n  \"engines\": {\n    \"node\": \"^20.19.0 || ^22.12.0 || >=23\"\n  }\n}\n"
  },
  {
    "path": "puppeteer.config.cjs",
    "content": "/**\n * @license\n * Copyright 2025 Google Inc.\n * SPDX-License-Identifier: Apache-2.0\n */\n\n/**\n * @type {import(\"puppeteer\").Configuration}\n */\nmodule.exports = {\n  chrome: {\n    skipDownload: false,\n  },\n  ['chrome-headless-shell']: {\n    skipDownload: true,\n  },\n  firefox: {\n    skipDownload: true,\n  },\n};\n"
  },
  {
    "path": "release-please-config.json",
    "content": "{\n  \"changelog-sections\": [\n    {\"type\": \"feat\", \"section\": \"🎉 Features\", \"hidden\": false},\n    {\"type\": \"fix\", \"section\": \"🛠️ Fixes\", \"hidden\": false},\n    {\"type\": \"docs\", \"section\": \"📄 Documentation\", \"hidden\": false},\n\n    {\"type\": \"perf\", \"section\": \"⚡ Performance\", \"hidden\": false},\n    {\"type\": \"refactor\", \"section\": \"🏗️ Refactor\", \"hidden\": false},\n    {\"type\": \"chore\", \"section\": \"♻️ Chores\", \"hidden\": true},\n    {\"type\": \"test\", \"section\": \"♻️ Chores\", \"hidden\": true},\n\n    {\"type\": \"build\", \"section\": \"⚙️ Automation\", \"hidden\": true},\n    {\"type\": \"ci\", \"section\": \"⚙️ Automation\", \"hidden\": true}\n  ],\n\n  \"packages\": {\n    \".\": {\n      \"extra-files\": [\n        {\n          \"type\": \"generic\",\n          \"path\": \"src/version.ts\"\n        },\n        {\n          \"type\": \"json\",\n          \"path\": \"server.json\",\n          \"jsonpath\": \"version\"\n        },\n        {\n          \"type\": \"json\",\n          \"path\": \"server.json\",\n          \"jsonpath\": \"packages[0].version\"\n        }\n      ]\n    }\n  }\n}\n"
  },
  {
    "path": "rollup.config.mjs",
    "content": "/**\n * Copyright 2021 Google LLC.\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/**\n * @fileoverview taken from {@link https://github.com/GoogleChromeLabs/chromium-bidi/blob/main/rollup.config.mjs | chromium-bidi}\n * and modified to specific requirement.\n */\n\nimport fs from 'node:fs';\nimport path from 'node:path';\n\nimport commonjs from '@rollup/plugin-commonjs';\nimport json from '@rollup/plugin-json';\nimport {nodeResolve} from '@rollup/plugin-node-resolve';\nimport cleanup from 'rollup-plugin-cleanup';\nimport license from 'rollup-plugin-license';\n\nconst isProduction = process.env.NODE_ENV === 'production';\n\nconst allowedLicenses = [\n  'MIT',\n  'Apache 2.0',\n  'Apache-2.0',\n  'BSD-3-Clause',\n  'BSD-2-Clause',\n  'ISC',\n  '0BSD',\n];\n\nconst thirdPartyDir = './build/src/third_party';\n\nconst {devDependencies = {}} = JSON.parse(\n  fs.readFileSync(path.join(process.cwd(), 'package.json'), 'utf-8'),\n);\n\n// special case for puppeteer, from which we only bundle puppeteer-core\ndevDependencies['puppeteer-core'] = devDependencies['puppeteer'];\n\nconst aggregatedStats = {\n  bundlesProcessed: 0,\n  totalBundles: 0,\n  bundledPackages: new Set(),\n};\n\nconst projectNodeModulesPath =\n  path.join(process.cwd(), 'node_modules') + path.sep;\n\nfunction getPackageName(modulePath) {\n  // Handle rollup's virtual module paths (paths starting with 0x00)\n  const absolutePathStart = modulePath.indexOf(projectNodeModulesPath);\n  if (absolutePathStart < 0) {\n    return null;\n  }\n\n  const relativePath = modulePath.slice(\n    projectNodeModulesPath.length + absolutePathStart,\n  );\n  const segments = relativePath.split(path.sep);\n\n  // handle scoped packages\n  if (segments[0].startsWith('@') && segments[1]) {\n    return `${segments[0]}/${segments[1]}`;\n  }\n  return segments[0];\n}\n\n/**\n * @returns {import('rollup').Plugin}\n */\nfunction listBundledDeps() {\n  aggregatedStats.totalBundles++;\n  return {\n    name: 'gather-bundled-dependencies',\n    generateBundle(options, bundle) {\n      for (const chunk of Object.values(bundle)) {\n        if (chunk.type === 'chunk' && chunk.modules) {\n          // chunk.modules is an object where keys are the absolute file paths\n          Object.keys(chunk.modules).forEach(modulePath => {\n            const packageName = getPackageName(modulePath);\n            if (packageName) {\n              aggregatedStats.bundledPackages.add(packageName);\n            }\n          });\n        }\n      }\n      aggregatedStats.bundlesProcessed++;\n\n      // Only write the file when the last bundle is finished\n      if (aggregatedStats.bundlesProcessed === aggregatedStats.totalBundles) {\n        const outputPath = path.join(thirdPartyDir, 'bundled-packages.json');\n\n        const bundledDevDeps = Object.fromEntries(\n          Object.entries(devDependencies).filter(\n            ([name]) =>\n              aggregatedStats.bundledPackages.has(name) ||\n              name === 'chrome-devtools-frontend' ||\n              name === 'lighthouse',\n          ),\n        );\n\n        fs.writeFileSync(outputPath, JSON.stringify(bundledDevDeps, null, 2));\n      }\n    },\n  };\n}\n\nconst seenDependencies = new Map();\n\n/**\n * @param {string} wrapperIndexName\n * @param {import('rollup').OutputOptions} [extraOutputOptions={}]\n * @param {import('rollup').ExternalOption} [external=[]]\n * @returns {import('rollup').RollupOptions}\n */\nconst bundleDependency = (\n  wrapperIndexName,\n  extraOutputOptions = {},\n  external = [],\n) => ({\n  input: path.join(thirdPartyDir, wrapperIndexName),\n  output: {\n    ...extraOutputOptions,\n    file: path.join(thirdPartyDir, wrapperIndexName),\n    sourcemap: !isProduction,\n    format: 'esm',\n  },\n  plugins: [\n    cleanup({\n      // Keep license comments. Other comments are removed due to\n      // http://b/390559299 and\n      // https://github.com/microsoft/TypeScript/issues/60811.\n      comments: [/Copyright/i],\n    }),\n    license({\n      thirdParty: {\n        allow: {\n          test: dependency => {\n            return allowedLicenses.includes(dependency.license);\n          },\n          failOnUnlicensed: true,\n          failOnViolation: true,\n        },\n        output: {\n          file: path.join(thirdPartyDir, 'THIRD_PARTY_NOTICES'),\n          template(dependencies) {\n            for (const dependency of dependencies) {\n              const key = `${dependency.name}:${dependency.version}`;\n              seenDependencies.set(key, dependency);\n            }\n\n            const stringifiedDependencies = Array.from(\n              seenDependencies.values(),\n            ).map(dependency => {\n              let arr = [];\n              arr.push(`Name: ${dependency.name ?? 'N/A'}`);\n              let url = dependency.homepage ?? dependency.repository;\n              if (url !== null && typeof url !== 'string') {\n                url = url.url;\n              }\n              arr.push(`URL: ${url ?? 'N/A'}`);\n              arr.push(`Version: ${dependency.version ?? 'N/A'}`);\n              arr.push(`License: ${dependency.license ?? 'N/A'}`);\n              if (dependency.licenseText !== null) {\n                arr.push('');\n                arr.push(dependency.licenseText.replaceAll('\\r', ''));\n              }\n              return arr.join('\\n');\n            });\n\n            // Manual license handling for chrome-devtools-frontend third_party\n            const tsConfig = JSON.parse(\n              fs.readFileSync(\n                path.join(process.cwd(), 'tsconfig.json'),\n                'utf-8',\n              ),\n            );\n            const thirdPartyDirectories = tsConfig.include.filter(location =>\n              location.includes(\n                'node_modules/chrome-devtools-frontend/front_end/third_party',\n              ),\n            );\n\n            const manualLicenses = [];\n            // Add chrome-devtools-frontend main license\n            const cdtfLicensePath = path.join(\n              process.cwd(),\n              'node_modules/chrome-devtools-frontend/LICENSE',\n            );\n            if (fs.existsSync(cdtfLicensePath)) {\n              manualLicenses.push(\n                [\n                  'Name: chrome-devtools-frontend',\n                  'License: Apache-2.0',\n                  '',\n                  fs.readFileSync(cdtfLicensePath, 'utf-8'),\n                ].join('\\n'),\n              );\n            }\n\n            // Add chrome-devtools-frontend main license\n            const lighthouseLicensePath = path.join(\n              process.cwd(),\n              'node_modules/lighthouse/LICENSE',\n            );\n            if (fs.existsSync(lighthouseLicensePath)) {\n              manualLicenses.push(\n                [\n                  'Name: lighthouse',\n                  'License: Apache-2.0',\n                  '',\n                  fs.readFileSync(lighthouseLicensePath, 'utf-8'),\n                ].join('\\n'),\n              );\n            }\n\n            for (const thirdPartyDir of thirdPartyDirectories) {\n              const fullPath = path.join(process.cwd(), thirdPartyDir);\n              const licenseFile = path.join(fullPath, 'LICENSE');\n              if (fs.existsSync(licenseFile)) {\n                const name = path.basename(thirdPartyDir);\n                manualLicenses.push(\n                  [\n                    `Name: ${name}`,\n                    `License:`,\n                    '',\n                    fs.readFileSync(licenseFile, 'utf-8').replaceAll('\\r', ''),\n                  ].join('\\n'),\n                );\n              }\n            }\n\n            if (manualLicenses.length > 0) {\n              stringifiedDependencies.push(...manualLicenses);\n            }\n\n            const divider =\n              '\\n\\n-------------------- DEPENDENCY DIVIDER --------------------\\n\\n';\n            return stringifiedDependencies.join(divider);\n          },\n        },\n      },\n    }),\n    listBundledDeps(),\n    commonjs(),\n    json(),\n    nodeResolve(),\n  ],\n  external,\n});\n\nexport default [\n  bundleDependency(\n    'index.js',\n    {\n      inlineDynamicImports: true,\n    },\n    (source, importer, _isResolved) => {\n      if (\n        source === 'yargs' &&\n        importer &&\n        importer.includes('puppeteer-core')\n      ) {\n        return true;\n      }\n\n      const existingExternals = [\n        './bidi.js',\n        '../bidi/bidi.js',\n        './lighthouse-devtools-mcp-bundle.js',\n      ];\n\n      if (existingExternals.includes(source)) {\n        return true;\n      }\n      return false;\n    },\n  ),\n  bundleDependency(\n    'devtools-formatter-worker.js',\n    {\n      inlineDynamicImports: true,\n    },\n    (_source, _importer, _isResolved) => false,\n  ),\n];\n"
  },
  {
    "path": "scripts/append-lighthouse-notices.ts",
    "content": "/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport fs from 'node:fs';\nimport path from 'node:path';\n\nconst ROOT_DIR = process.cwd();\nconst TARGET_DIR = path.join(ROOT_DIR, 'build/src/third_party');\nconst SOURCE_DIR = path.join(ROOT_DIR, 'src/third_party');\n\nfunction main() {\n  const lighthouseNotices = fs.readFileSync(\n    path.join(SOURCE_DIR, 'LIGHTHOUSE_MCP_BUNDLE_THIRD_PARTY_NOTICES'),\n    'utf8',\n  );\n  const bundledNotices = fs.readFileSync(\n    path.join(TARGET_DIR, 'THIRD_PARTY_NOTICES'),\n    'utf8',\n  );\n  fs.writeFileSync(\n    path.join(TARGET_DIR, 'THIRD_PARTY_NOTICES'),\n    bundledNotices +\n      '\\n\\n-------------------- DEPENDENCY DIVIDER --------------------\\n\\n' +\n      lighthouseNotices,\n  );\n  console.log('Done.');\n}\n\nmain();\n"
  },
  {
    "path": "scripts/count_tokens.ts",
    "content": "/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport {readFileSync} from 'node:fs';\nimport {parseArgs} from 'node:util';\n\nimport {GoogleGenAI} from '@google/genai';\n\nconst ai = new GoogleGenAI({apiKey: process.env.GEMINI_API_KEY});\n\nconst {values, positionals} = parseArgs({\n  options: {\n    model: {\n      type: 'string',\n      default: 'gemini-2.5-flash',\n    },\n    file: {\n      type: 'string',\n      short: 'f',\n    },\n  },\n  allowPositionals: true,\n});\n\nlet contents = positionals[0];\n\nif (values.file) {\n  contents = readFileSync(values.file, 'utf8');\n}\n\nif (!contents) {\n  console.error('Usage: npm run count-tokens -- [-f <file>] [<text>]');\n  process.exit(1);\n}\n\nconst response = await ai.models.countTokens({\n  model: values.model,\n  contents,\n});\nconsole.log(`Input: ${values.file || positionals[0]}`);\nconsole.log(`Tokens: ${response.totalTokens}`);\n"
  },
  {
    "path": "scripts/eslint_rules/check-license-rule.js",
    "content": "/**\n * @license\n * Copyright 2025 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nconst currentYear = new Date().getFullYear();\nconst licenseHeader = `\n/**\n * @license\n * Copyright ${currentYear} Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n`;\n\nexport default {\n  name: 'check-license',\n  meta: {\n    type: 'layout',\n    docs: {\n      description: 'Validate existence of license header',\n    },\n    fixable: 'code',\n    schema: [],\n    messages: {\n      licenseRule: 'Add license header.',\n      emptyLine: 'Add empty line after license header.',\n    },\n  },\n  defaultOptions: [],\n  create(context) {\n    const sourceCode = context.getSourceCode();\n    const comments = sourceCode.getAllComments();\n    let insertAfter = [0, 0];\n    let header = null;\n    // Check only the first 2 comments\n    for (let index = 0; index < 2; index++) {\n      const comment = comments[index];\n      if (!comment) {\n        break;\n      }\n      // Shebang comments should be at the top\n      if (\n        comment.type === 'Shebang' ||\n        (comment.type === 'Line' && comment.value.startsWith('#!'))\n      ) {\n        insertAfter = comment.range;\n        continue;\n      }\n      if (comment.type === 'Block') {\n        header = comment;\n        break;\n      }\n    }\n\n    return {\n      Program(node) {\n        if (context.getFilename().endsWith('.json')) {\n          return;\n        }\n\n        if (\n          header &&\n          (header.value.includes('@license') ||\n            header.value.includes('License') ||\n            header.value.includes('Copyright'))\n        ) {\n          const nextToken = sourceCode.getTokenAfter(header, {\n            includeComments: true,\n          });\n          if (\n            nextToken &&\n            nextToken.loc.start.line === header.loc.end.line + 1\n          ) {\n            context.report({\n              node: node,\n              loc: header.loc,\n              messageId: 'emptyLine',\n              fix(fixer) {\n                return fixer.insertTextAfter(header, '\\n');\n              },\n            });\n          }\n          return;\n        }\n\n        // Add header license\n        if (!header || !header.value.includes('@license')) {\n          context.report({\n            node: node,\n            messageId: 'licenseRule',\n            fix(fixer) {\n              return fixer.insertTextAfterRange(insertAfter, licenseHeader);\n            },\n          });\n        }\n      },\n    };\n  },\n};\n"
  },
  {
    "path": "scripts/eslint_rules/local-plugin.js",
    "content": "/**\n * @license\n * Copyright 2025 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport checkLicenseRule from './check-license-rule.js';\n\nexport default {rules: {'check-license': checkLicenseRule}};\n"
  },
  {
    "path": "scripts/eval_gemini.ts",
    "content": "/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport {pathToFileURL} from 'node:url';\nimport {parseArgs} from 'node:util';\n\nimport {GoogleGenAI, mcpToTool} from '@google/genai';\nimport {Client} from '@modelcontextprotocol/sdk/client/index.js';\nimport {StdioClientTransport} from '@modelcontextprotocol/sdk/client/stdio.js';\n\nimport {TestServer} from '../build/tests/server.js';\n\nconst ROOT_DIR = path.resolve(import.meta.dirname, '..');\nconst SCENARIOS_DIR = path.join(import.meta.dirname, 'eval_scenarios');\nconst SKILL_PATH = path.join(ROOT_DIR, 'skills', 'chrome-devtools', 'SKILL.md');\n\n// Define schema for our test scenarios\nexport interface CapturedFunctionCall {\n  name: string;\n  args: Record<string, unknown>;\n}\n\nexport interface TestScenario {\n  prompt: string;\n  maxTurns: number;\n  expectations: (calls: CapturedFunctionCall[]) => void;\n  htmlRoute?: {\n    path: string;\n    htmlContent: string;\n  };\n  /** Extra CLI flags passed to the MCP server (e.g. '--experimental-page-id-routing'). */\n  serverArgs?: string[];\n}\n\nasync function loadScenario(scenarioPath: string): Promise<TestScenario> {\n  const module = await import(pathToFileURL(scenarioPath).href);\n  if (!module.scenario) {\n    throw new Error(\n      `Scenario file ${scenarioPath} does not export a 'scenario' object.`,\n    );\n  }\n  return module.scenario;\n}\n\nasync function runSingleScenario(\n  scenarioPath: string,\n  apiKey: string,\n  server: TestServer,\n  modelId: string,\n  debug: boolean,\n  includeSkill: boolean,\n): Promise<void> {\n  const debugLog = (...args: unknown[]) => {\n    if (debug) {\n      console.log(...args);\n    }\n  };\n  const absolutePath = path.resolve(scenarioPath);\n  debugLog(\n    `\\n### Running Scenario: ${path.relative(ROOT_DIR, absolutePath)} ###`,\n  );\n\n  let client: Client | undefined;\n  let transport: StdioClientTransport | undefined;\n\n  try {\n    const loadedScenario = await loadScenario(absolutePath);\n    const scenario = {...loadedScenario};\n\n    // Prepend skill content if requested\n    if (includeSkill) {\n      if (!fs.existsSync(SKILL_PATH)) {\n        throw new Error(\n          `Skill file not found at ${SKILL_PATH}. Please ensure the skill file exists.`,\n        );\n      }\n      const skillContent = fs.readFileSync(SKILL_PATH, 'utf-8');\n      scenario.prompt = `${skillContent}\\n\\n---\\n\\n${scenario.prompt}`;\n    }\n\n    // Append random queryid to avoid caching issues and test distinct runs\n    const randomId = Math.floor(Math.random() * 1000000);\n    scenario.prompt = `${scenario.prompt}\\nqueryid=${randomId}`;\n\n    if (scenario.htmlRoute) {\n      server.addHtmlRoute(\n        scenario.htmlRoute.path,\n        scenario.htmlRoute.htmlContent,\n      );\n      scenario.prompt = scenario.prompt.replace(\n        '<TEST_URL>',\n        server.getRoute(scenario.htmlRoute.path),\n      );\n    }\n\n    // Path to the compiled MCP server\n    const serverPath = path.join(ROOT_DIR, 'build/src/index.js');\n    if (!fs.existsSync(serverPath)) {\n      throw new Error(\n        `MCP server not found at ${serverPath}. Please run 'npm run build' first.`,\n      );\n    }\n\n    // Environment variables\n    const env: Record<string, string> = {};\n    Object.entries(process.env).forEach(([key, value]) => {\n      if (value !== undefined) {\n        env[key] = value;\n      }\n    });\n    env['CHROME_DEVTOOLS_MCP_NO_USAGE_STATISTICS'] = 'true';\n\n    const args = [serverPath];\n    if (!debug) {\n      args.push('--headless');\n    }\n    if (scenario.serverArgs) {\n      args.push(...scenario.serverArgs);\n    }\n\n    transport = new StdioClientTransport({\n      command: 'node',\n      args,\n      env,\n      stderr: debug ? 'inherit' : 'ignore',\n    });\n\n    client = new Client(\n      {name: 'gemini-eval-client', version: '1.0.0'},\n      {capabilities: {}},\n    );\n\n    await client.connect(transport);\n\n    const allCalls: CapturedFunctionCall[] = [];\n    const originalCallTool = client.callTool.bind(client);\n    client.callTool = async (request, schema) => {\n      // NOTE: request.name is the original name as the MCP client sees it.\n      // mcpToTool handles the conversion from Gemini sanitized name to original name.\n      debugLog(\n        `Executing tool: ${request.name} with args: ${JSON.stringify(request.arguments)}`,\n      );\n      allCalls.push({\n        name: request.name,\n        args: (request.arguments as Record<string, unknown>) || {},\n      });\n      const response = await originalCallTool(request, schema);\n      debugLog(`Tool response: ${JSON.stringify(response)}`);\n      return response;\n    };\n\n    const ai = new GoogleGenAI({apiKey});\n\n    debugLog(`\\n--- Prompt ---\\n${scenario.prompt}`);\n\n    const result = await ai.models.generateContent({\n      model: modelId,\n      contents: scenario.prompt,\n      config: {\n        tools: [mcpToTool(client)],\n        automaticFunctionCalling: {\n          maximumRemoteCalls: scenario.maxTurns,\n        },\n      },\n    });\n\n    debugLog(`\\n--- Response ---\\n${result.text}`);\n\n    debugLog('\\nVerifying expectations...');\n    scenario.expectations(allCalls);\n  } finally {\n    try {\n      await client?.close();\n    } catch (e) {\n      console.error('Error closing client:', e);\n    }\n  }\n}\n\nasync function main() {\n  const apiKey = process.env.GEMINI_API_KEY;\n  if (!apiKey) {\n    throw new Error('GEMINI_API_KEY environment variable is required.');\n  }\n\n  const {values, positionals} = parseArgs({\n    options: {\n      model: {\n        type: 'string',\n        default: 'gemini-2.5-flash',\n      },\n      debug: {\n        type: 'boolean',\n        default: false,\n      },\n      repeat: {\n        type: 'boolean',\n        default: false,\n      },\n      'include-skill': {\n        type: 'boolean',\n        default: false,\n      },\n    },\n    allowPositionals: true,\n  });\n\n  const modelId = values.model;\n  const debug = values.debug;\n  const repeat = values.repeat;\n  const includeSkill = values['include-skill'];\n\n  const scenarioFiles =\n    positionals.length > 0\n      ? positionals.map(p => path.resolve(p))\n      : fs\n          .readdirSync(SCENARIOS_DIR)\n          .filter(file => file.endsWith('.ts') || file.endsWith('.js'))\n          .map(file => path.join(SCENARIOS_DIR, file));\n\n  const server = new TestServer(TestServer.randomPort());\n  await server.start();\n\n  let successCount = 0;\n  let failureCount = 0;\n\n  try {\n    for (const scenarioPath of scenarioFiles) {\n      for (let i = 1; i <= (repeat ? 3 : 1); i++) {\n        try {\n          if (debug) {\n            console.log(\n              `Running scenario: ${path.relative(ROOT_DIR, scenarioPath)} (Run ${i}/3)`,\n            );\n          }\n          await runSingleScenario(\n            scenarioPath,\n            apiKey,\n            server,\n            modelId,\n            debug,\n            includeSkill,\n          );\n          console.log(`✔ ${path.relative(ROOT_DIR, scenarioPath)} (Run ${i})`);\n          successCount++;\n        } catch (e) {\n          console.error(\n            `✖ ${path.relative(ROOT_DIR, scenarioPath)} (Run ${i})`,\n          );\n          console.error(e);\n          failureCount++;\n        } finally {\n          server.restore();\n        }\n      }\n    }\n  } finally {\n    await server.stop();\n  }\n\n  console.log(`\\nSummary: ${successCount} passed, ${failureCount} failed`);\n\n  if (failureCount > 0) {\n    process.exit(1);\n  }\n}\n\nmain().catch(error => {\n  console.error('Fatal error:', error);\n  process.exit(1);\n});\n"
  },
  {
    "path": "scripts/eval_scenarios/console_test.ts",
    "content": "/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport assert from 'node:assert';\n\nimport type {TestScenario} from '../eval_gemini.ts';\n\nexport const scenario: TestScenario = {\n  prompt: 'Navigate to <TEST_URL> and check the console messages.',\n  maxTurns: 2,\n  htmlRoute: {\n    path: '/console_test.html',\n    htmlContent: `\n      <script>\n        console.log('Test log message');\n        console.error('Test error message');\n      </script>\n    `,\n  },\n  expectations: calls => {\n    assert.strictEqual(calls.length, 2);\n    assert.ok(\n      calls[0].name === 'navigate_page' || calls[0].name === 'new_page',\n      'First call should be navigation',\n    );\n    assert.strictEqual(\n      calls[1].name,\n      'list_console_messages',\n      'Second call should be list_console_messages',\n    );\n  },\n};\n"
  },
  {
    "path": "scripts/eval_scenarios/emulation_test.ts",
    "content": "/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport assert from 'node:assert';\n\nimport type {TestScenario} from '../eval_gemini.ts';\n\nexport const scenario: TestScenario = {\n  prompt: 'Emulate offline network conditions.',\n  maxTurns: 2,\n  expectations: calls => {\n    assert.strictEqual(calls.length, 1);\n    assert.strictEqual(calls[0].name, 'emulate');\n    assert.strictEqual(calls[0].args.networkConditions, 'Offline');\n  },\n};\n"
  },
  {
    "path": "scripts/eval_scenarios/emulation_userAgent_test.ts",
    "content": "/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport assert from 'node:assert';\n\nimport type {TestScenario} from '../eval_gemini.ts';\n\nexport const scenario: TestScenario = {\n  prompt: 'Emulate iPhone 14 user agent',\n  maxTurns: 2,\n  expectations: calls => {\n    assert.strictEqual(calls.length, 1);\n    assert.strictEqual(calls[0].name, 'emulate');\n    assert.deepStrictEqual(\n      calls[0].args.userAgent,\n      'Mozilla/5.0 (iPhone; CPU iPhone OS 16_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.0 Mobile/15E148 Safari/604.1',\n    );\n  },\n};\n"
  },
  {
    "path": "scripts/eval_scenarios/emulation_viewport_test.ts",
    "content": "/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport assert from 'node:assert';\n\nimport {KnownDevices} from 'puppeteer';\n\nimport type {TestScenario} from '../eval_gemini.ts';\n\nexport const scenario: TestScenario = {\n  prompt: 'Emulate iPhone 14 viewport',\n  maxTurns: 2,\n  expectations: calls => {\n    assert.strictEqual(calls.length, 1);\n    assert.strictEqual(calls[0].name, 'emulate');\n    assert.deepStrictEqual(\n      {\n        ...(calls[0].args.viewport as object),\n        // models might not send defaults.\n        isLandscape: KnownDevices['iPhone 14'].viewport.isLandscape ?? false,\n      },\n      {\n        ...KnownDevices['iPhone 14'].viewport,\n        height: 844, // Puppeteer is wrong about the expected height.\n      },\n    );\n  },\n};\n"
  },
  {
    "path": "scripts/eval_scenarios/fix_webpage_issues_test.ts",
    "content": "/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n *\n * Eval scenario: user asks to fix issues with their webpage (no URL given).\n * When no URL is provided, the model should pick the current frontend and run\n * and inspect it. Verifies the MCP server is invoked and the model opens the\n * frontend and inspects it (snapshot, console, or network).\n *\n * Note: Tools like performance_start_trace, take_snapshot, list_console_messages,\n * and list_network_requests do not require a URL in the prompt—they operate on\n * the currently selected page. Only navigate_page/new_page need a URL to open\n * a page; the eval runner injects the test URL when htmlRoute is set.\n */\n\nimport assert from 'node:assert';\n\nimport type {TestScenario} from '../eval_gemini.ts';\n\nconst INSPECTION_TOOLS = [\n  'take_snapshot',\n  'list_console_messages',\n  'list_network_requests',\n];\n\nexport const scenario: TestScenario = {\n  prompt: 'Can you fix issues with my webpage?',\n  maxTurns: 4,\n  htmlRoute: {\n    path: '/fix_issues_test.html',\n    htmlContent: `\n      <h1>Test Page</h1>\n      <p>Some content</p>\n      <script>\n        console.error('Intentional error for testing');\n      </script>\n    `,\n  },\n  expectations: calls => {\n    const NAVIGATION_TOOLS = ['navigate_page', 'new_page'];\n    assert.ok(\n      calls.length >= 2,\n      'Expected at least navigation and one inspection',\n    );\n    const navigationIndex = calls.findIndex(c =>\n      NAVIGATION_TOOLS.includes(c.name),\n    );\n    assert.ok(\n      navigationIndex !== -1,\n      `Expected a navigation call (${NAVIGATION_TOOLS.join(' or ')}), got: ${calls.map(c => c.name).join(', ')}`,\n    );\n    const afterNavigation = calls.slice(navigationIndex + 1);\n    const inspectionCalls = afterNavigation.filter(c =>\n      INSPECTION_TOOLS.includes(c.name),\n    );\n    assert.ok(\n      inspectionCalls.length >= 1,\n      `Expected at least one inspection tool (${INSPECTION_TOOLS.join(', ')}) after navigation, got: ${calls.map(c => c.name).join(', ')}`,\n    );\n  },\n};\n"
  },
  {
    "path": "scripts/eval_scenarios/frontend_snapshot_test.ts",
    "content": "/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n *\n * Eval scenario using \"website\"/\"webpage\" wording to verify the model invokes\n * the right tools when users ask to open a site and read its content.\n */\n\nimport assert from 'node:assert';\n\nimport type {TestScenario} from '../eval_gemini.ts';\n\nexport const scenario: TestScenario = {\n  prompt:\n    'Open the website at <TEST_URL> and tell me what content is on the page.',\n  maxTurns: 3,\n  htmlRoute: {\n    path: '/frontend_snapshot.html',\n    htmlContent: '<h1>Frontend Test</h1><p>This is a test webpage.</p>',\n  },\n  expectations: calls => {\n    assert.strictEqual(calls.length, 2);\n    assert.ok(\n      calls[0].name === 'navigate_page' || calls[0].name === 'new_page',\n      'First call should be navigation',\n    );\n    assert.strictEqual(\n      calls[1].name,\n      'take_snapshot',\n      'Second call should be take_snapshot to read page content',\n    );\n  },\n};\n"
  },
  {
    "path": "scripts/eval_scenarios/input_parallel_test.ts",
    "content": "/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport assert from 'node:assert';\n\nimport type {TestScenario} from '../eval_gemini.ts';\n\nexport const scenario: TestScenario = {\n  prompt:\n    'Go to <TEST_URL>, fill the input with \"hello world\" and click the button five times in parallel.',\n  maxTurns: 10,\n  htmlRoute: {\n    path: '/input_test.html',\n    htmlContent: `\n      <input type=\"text\" id=\"test-input\" />\n      <button id=\"test-button\">Submit</button>\n    `,\n  },\n  expectations: calls => {\n    assert.strictEqual(calls.length, 8);\n    assert.ok(\n      calls[0].name === 'navigate_page' || calls[0].name === 'new_page',\n    );\n    assert.ok(calls[1].name === 'take_snapshot');\n    assert.ok(calls[2].name === 'fill');\n    for (let i = 3; i < 8; i++) {\n      assert.ok(calls[i].name === 'click');\n      assert.strictEqual(Boolean(calls[i].args.includeSnapshot), false);\n    }\n  },\n};\n"
  },
  {
    "path": "scripts/eval_scenarios/input_test.ts",
    "content": "/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport assert from 'node:assert';\n\nimport type {TestScenario} from '../eval_gemini.ts';\n\nexport const scenario: TestScenario = {\n  prompt:\n    'Go to <TEST_URL>, fill the input with \"hello world\" and click the button.',\n  maxTurns: 4,\n  htmlRoute: {\n    path: '/input_test.html',\n    htmlContent: `\n      <input type=\"text\" id=\"test-input\" />\n      <button id=\"test-button\">Submit</button>\n    `,\n  },\n  expectations: calls => {\n    assert.strictEqual(calls.length, 4);\n    assert.ok(\n      calls[0].name === 'navigate_page' || calls[0].name === 'new_page',\n    );\n    assert.ok(calls[1].name === 'take_snapshot');\n    assert.ok(calls[2].name === 'fill');\n    assert.ok(calls[3].name === 'click');\n  },\n};\n"
  },
  {
    "path": "scripts/eval_scenarios/isolated_context_test.ts",
    "content": "/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport assert from 'node:assert';\n\nimport type {TestScenario} from '../eval_gemini.ts';\n\nexport const scenario: TestScenario = {\n  prompt:\n    'Create a new page <TEST_URL> in an isolated context called contextB. Take a screenshot there.',\n  maxTurns: 3,\n  htmlRoute: {\n    path: '/test.html',\n    htmlContent: `\n      <h1>test</h1>\n    `,\n  },\n  expectations: calls => {\n    console.log(JSON.stringify(calls, null, 2));\n    assert.strictEqual(calls.length, 2);\n    assert.ok(calls[0].name === 'new_page', 'First call should be navigation');\n    assert.deepStrictEqual(calls[0].args.isolatedContext, 'contextB');\n    assert.ok(\n      calls[1].name === 'take_screenshot',\n      'Second call should be a screenshot',\n    );\n  },\n};\n"
  },
  {
    "path": "scripts/eval_scenarios/lighthouse_a11y_test.ts",
    "content": "/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport assert from 'node:assert';\n\nimport type {TestScenario} from '../eval_gemini.ts';\n\nexport const scenario: TestScenario = {\n  prompt: 'Check a11y issues on the current page',\n  maxTurns: 1,\n  expectations: calls => {\n    assert.strictEqual(calls.length, 1);\n    assert.ok(\n      calls[0].name === 'lighthouse_audit',\n      'First call should be lighthouse_audit',\n    );\n  },\n};\n"
  },
  {
    "path": "scripts/eval_scenarios/lighthouse_best_practices_test.ts",
    "content": "/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport assert from 'node:assert';\n\nimport type {TestScenario} from '../eval_gemini.ts';\n\nexport const scenario: TestScenario = {\n  prompt: 'Check for best practices on the current page',\n  maxTurns: 1,\n  expectations: calls => {\n    assert.strictEqual(calls.length, 1);\n    assert.ok(\n      calls[0].name === 'lighthouse_audit',\n      'First call should be lighthouse_audit',\n    );\n  },\n};\n"
  },
  {
    "path": "scripts/eval_scenarios/navigation_test.ts",
    "content": "/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport assert from 'node:assert';\n\nimport type {TestScenario} from '../eval_gemini.ts';\n\nexport const scenario: TestScenario = {\n  prompt: 'Navigate to https://developers.chrome.com and tell me if it worked.',\n  maxTurns: 1,\n  expectations: calls => {\n    assert.deepStrictEqual(calls, [\n      {\n        name: 'navigate_page',\n        args: {url: 'https://developers.chrome.com'},\n      },\n    ]);\n  },\n};\n"
  },
  {
    "path": "scripts/eval_scenarios/network_test.ts",
    "content": "/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport assert from 'node:assert';\n\nimport type {TestScenario} from '../eval_gemini.ts';\n\nexport const scenario: TestScenario = {\n  prompt: 'Navigate to <TEST_URL> and list all network requests.',\n  maxTurns: 2,\n  htmlRoute: {\n    path: '/network_test.html',\n    htmlContent: `\n      <h1>Network Test</h1>\n      <script>\n        fetch('/network_test.html'); // Self fetch to ensure at least one request\n      </script>\n    `,\n  },\n  expectations: calls => {\n    assert.strictEqual(calls.length, 2);\n    assert.ok(\n      calls[0].name === 'navigate_page' || calls[0].name === 'new_page',\n      'First call should be navigation',\n    );\n    assert.strictEqual(\n      calls[1].name,\n      'list_network_requests',\n      'Second call should be list_network_requests',\n    );\n  },\n};\n"
  },
  {
    "path": "scripts/eval_scenarios/page_focus_keyboard_test.ts",
    "content": "/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport assert from 'node:assert';\n\nimport type {TestScenario} from '../eval_gemini.ts';\n\nexport const scenario: TestScenario = {\n  serverArgs: ['--experimental-page-id-routing'],\n  prompt: `Open two pages in the same isolated context \"session\":\n- Page 1 at data:text/html,<textarea id=\"ta\"></textarea>\n- Page 2 at data:text/html,<h1>Other</h1>\n\nNow use the press_key tool to type \"a\" on Page 1 without selecting it first. You must use press_key, not fill or type_text. If you encounter any errors, recover from them.`,\n  maxTurns: 10,\n  expectations: calls => {\n    // Should open 2 pages in the same context.\n    const newPages = calls.filter(c => c.name === 'new_page');\n    assert.strictEqual(newPages.length, 2, 'Should open 2 pages');\n    assert.strictEqual(newPages[0].args.isolatedContext, 'session');\n    assert.strictEqual(newPages[1].args.isolatedContext, 'session');\n\n    // Should attempt press_key at least once.\n    const pressKeys = calls.filter(c => c.name === 'press_key');\n    assert.ok(pressKeys.length >= 1, 'Should attempt press_key at least once');\n\n    const selectPages = calls.filter(c => c.name === 'select_page');\n\n    if (selectPages.length > 0) {\n      const firstPressKeyIndex = calls.indexOf(pressKeys[0]);\n      const firstSelectPageIndex = calls.indexOf(selectPages[0]);\n\n      if (firstPressKeyIndex < firstSelectPageIndex) {\n        // Error path: press_key was attempted first and failed.\n        // Verify recovery: must have a second press_key after select_page.\n        assert.ok(\n          pressKeys.length >= 2,\n          'Should retry press_key after error recovery',\n        );\n        const lastPressKeyIndex = calls.lastIndexOf(pressKeys.at(-1)!);\n        assert.ok(\n          firstSelectPageIndex < lastPressKeyIndex,\n          'select_page should precede the successful press_key',\n        );\n      } else {\n        // Proactive path: model selected page first.\n        assert.ok(\n          firstSelectPageIndex < firstPressKeyIndex,\n          'select_page should precede press_key',\n        );\n      }\n    }\n    // If no select_page was called, the model found another recovery path.\n    // This is acceptable as long as press_key was attempted.\n  },\n};\n"
  },
  {
    "path": "scripts/eval_scenarios/page_id_routing_test.ts",
    "content": "/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport assert from 'node:assert';\n\nimport type {TestScenario} from '../eval_gemini.ts';\n\nexport const scenario: TestScenario = {\n  serverArgs: ['--experimental-page-id-routing'],\n  prompt: `Open two new pages in isolated contexts:\n- Page A (isolatedContext \"contextA\") at data:text/html,<button>Click A</button>\n- Page B (isolatedContext \"contextB\") at data:text/html,<button>Click B</button>\nThen take a snapshot of Page A, take a snapshot of Page B, and then click the button on Page A.`,\n  maxTurns: 12,\n  expectations: calls => {\n    // Should have 2 new_page calls with isolatedContext.\n    const newPages = calls.filter(c => c.name === 'new_page');\n    assert.strictEqual(newPages.length, 2, 'Should open 2 pages');\n    for (const np of newPages) {\n      assert.strictEqual(\n        typeof np.args.isolatedContext,\n        'string',\n        'new_page should use isolatedContext',\n      );\n    }\n\n    // Should have at least 2 take_snapshot calls (one per page).\n    // The model may use pageId directly or select_page before each snapshot.\n    const snapshots = calls.filter(c => c.name === 'take_snapshot');\n    assert.ok(snapshots.length >= 2, 'Should take at least 2 snapshots');\n\n    // Should have a click call (resolving uid from Page A's snapshot\n    // even though Page B was snapshotted after).\n    const clicks = calls.filter(c => c.name === 'click');\n    assert.ok(clicks.length >= 1, 'Should click the button on Page A');\n  },\n};\n"
  },
  {
    "path": "scripts/eval_scenarios/performance_test.ts",
    "content": "/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport assert from 'node:assert';\n\nimport type {TestScenario} from '../eval_gemini.ts';\n\nexport const scenario: TestScenario = {\n  prompt: 'Check the performance of https://developers.chrome.com',\n  maxTurns: 2,\n  expectations: calls => {\n    assert.strictEqual(calls.length, 2);\n    assert.ok(\n      calls[0].name === 'navigate_page' || calls[0].name === 'new_page',\n    );\n    assert.ok(calls[1].name === 'performance_start_trace');\n  },\n};\n"
  },
  {
    "path": "scripts/eval_scenarios/select_page_test.ts",
    "content": "/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport assert from 'node:assert';\n\nimport type {TestScenario} from '../eval_gemini.ts';\n\nexport const scenario: TestScenario = {\n  prompt:\n    'Open new page <TEST_URL> and then open new page https://developers.chrome.com. Select the <TEST_URL> page.',\n  maxTurns: 3,\n  htmlRoute: {\n    path: '/test.html',\n    htmlContent: `\n      <h1>test</h1>\n    `,\n  },\n  expectations: calls => {\n    assert.strictEqual(calls.length, 3);\n    assert.ok(calls[0].name === 'new_page', 'First call should be navigation');\n    assert.ok(calls[1].name === 'new_page', 'Second call should be navigation');\n    assert.ok(\n      calls[2].name === 'select_page',\n      'Third call should be select_page',\n    );\n    assert.strictEqual(\n      calls[2].args.pageId,\n      2,\n      'PageId has to be set to 2. about:blank is 1, <TEST_URL> is 2, https://developers.chrome.com is 3.',\n    );\n    assert.strictEqual(\n      calls[2].args.bringToFront,\n      undefined,\n      'bringToFront should use the default value.',\n    );\n  },\n};\n"
  },
  {
    "path": "scripts/eval_scenarios/snapshot_test.ts",
    "content": "/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport assert from 'node:assert';\n\nimport type {TestScenario} from '../eval_gemini.ts';\n\nexport const scenario: TestScenario = {\n  prompt: 'Read the content of <TEST_URL>',\n  maxTurns: 3,\n  htmlRoute: {\n    path: '/test.html',\n    htmlContent: '<h1>Hello World</h1><p>This is a test.</p>',\n  },\n  expectations: calls => {\n    assert.strictEqual(calls.length, 2);\n    assert.ok(\n      calls[0].name === 'navigate_page' || calls[0].name === 'new_page',\n    );\n    assert.ok(calls[1].name === 'take_snapshot');\n  },\n};\n"
  },
  {
    "path": "scripts/generate-cli.ts",
    "content": "/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport fs from 'node:fs';\nimport path from 'node:path';\n\nimport {Client} from '@modelcontextprotocol/sdk/client/index.js';\nimport {StdioClientTransport} from '@modelcontextprotocol/sdk/client/stdio.js';\n\nimport {parseArguments} from '../build/src/bin/chrome-devtools-mcp-cli-options.js';\nimport {labels} from '../build/src/tools/categories.js';\nimport {createTools} from '../build/src/tools/tools.js';\n\nconst OUTPUT_PATH = path.join(\n  import.meta.dirname,\n  '../src/bin/cliDefinitions.ts',\n);\n\nasync function fetchTools() {\n  console.log('Connecting to chrome-devtools-mcp to fetch tools...');\n  // Use the local build of the server\n  const serverPath = path.join(\n    import.meta.dirname,\n    '../build/src/bin/chrome-devtools-mcp.js',\n  );\n\n  const transport = new StdioClientTransport({\n    command: 'node',\n    args: [serverPath],\n    env: {...process.env, CHROME_DEVTOOLS_MCP_NO_USAGE_STATISTICS: 'true'},\n  });\n\n  const client = new Client(\n    {\n      name: 'chrome-devtools-cli-generator',\n      version: '0.1.0',\n    },\n    {\n      capabilities: {},\n    },\n  );\n\n  await client.connect(transport);\n  try {\n    const toolsResponse = await client.listTools();\n    if (!toolsResponse.tools?.length) {\n      throw new Error(`No tools were fetched`);\n    }\n    const tools = toolsResponse.tools || [];\n    console.log(`Fetched ${tools.length} tools`);\n    return tools;\n  } finally {\n    await client.close();\n  }\n}\n\ninterface CliOption {\n  name: string;\n  type: string;\n  description: string;\n  required: boolean;\n  default?: unknown;\n  enum?: unknown[];\n}\n\ninterface JsonSchema {\n  type?: string | string[];\n  description?: string;\n  properties?: Record<string, JsonSchema>;\n  required?: string[];\n  default?: unknown;\n  enum?: unknown[];\n}\n\nfunction schemaToCLIOptions(schema: JsonSchema): CliOption[] {\n  if (!schema || !schema.properties) {\n    return [];\n  }\n  const required = schema.required || [];\n  const properties = schema.properties;\n  return Object.entries(properties).map(([name, prop]) => {\n    const isRequired = required.includes(name);\n    const description = prop.description || '';\n    if (typeof prop.type !== 'string') {\n      throw new Error(\n        `Property ${name} has a complex type not supported by CLI.`,\n      );\n    }\n    return {\n      name,\n      type: prop.type,\n      description,\n      required: isRequired,\n      default: prop.default,\n      enum: prop.enum,\n    };\n  });\n}\n\nasync function generateCli() {\n  const tools = await fetchTools();\n\n  // Sort tools by name\n  const sortedTools = tools\n    .sort((a, b) => a.name.localeCompare(b.name))\n    .filter(tool => {\n      // Skipping fill_form because it is not relevant in shell scripts\n      // and CLI does not handle array/JSON args well.\n      if (tool.name === 'fill_form') {\n        return false;\n      }\n      // Skipping wait_for because CLI does not handle array/JSON args well\n      // and shell scripts have many mechanisms for waiting.\n      if (tool.name === 'wait_for') {\n        return false;\n      }\n      return true;\n    });\n\n  const staticTools = createTools(parseArguments());\n  const toolNameToCategory = new Map<string, string>();\n  for (const tool of staticTools) {\n    toolNameToCategory.set(\n      tool.name,\n      labels[tool.annotations.category as keyof typeof labels],\n    );\n  }\n\n  const commands: Record<\n    string,\n    {description: string; category: string; args: Record<string, CliOption>}\n  > = {};\n\n  for (const tool of sortedTools) {\n    const options = schemaToCLIOptions(tool.inputSchema);\n    const args: Record<string, CliOption> = {};\n    for (const opt of options) {\n      args[opt.name] = opt;\n    }\n    const category = toolNameToCategory.get(tool.name);\n    if (!category) {\n      throw new Error(`Tool ${tool.name} has no category.`);\n    }\n    if (!tool.description) {\n      throw new Error(`Tool ${tool.name} is missing descripttion`);\n    }\n    commands[tool.name] = {\n      description: tool.description,\n      category,\n      args,\n    };\n  }\n\n  const lines: string[] = [];\n  lines.push(`/**\n * @license\n * Copyright ${new Date().getFullYear()} Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\n// NOTE: do not edit manually. Auto-generated by 'npm run cli:generate'.\n\nexport interface ArgDef {\n  name: string;\n  type: string;\n  description: string;\n  required: boolean;\n  default?: string | number | boolean;\n  enum?: ReadonlyArray<string | number>;\n}\nexport type Commands = Record<\n  string,\n  {\n    description: string;\n    category: string;\n    args: Record<string, ArgDef>\n  }\n>;\nexport const commands: Commands = ${JSON.stringify(commands, null, 2)} as const;\n`);\n\n  fs.mkdirSync(path.dirname(OUTPUT_PATH), {recursive: true});\n  fs.writeFileSync(OUTPUT_PATH, lines.join(''));\n  console.log(`Generated CLI at ${OUTPUT_PATH}`);\n}\n\ngenerateCli().catch(err => {\n  console.error('Error during generation:', err);\n  process.exit(1);\n});\n"
  },
  {
    "path": "scripts/generate-docs.ts",
    "content": "/**\n * @license\n * Copyright 2025 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport fs from 'node:fs';\n\nimport {Client} from '@modelcontextprotocol/sdk/client/index.js';\nimport {StdioClientTransport} from '@modelcontextprotocol/sdk/client/stdio.js';\nimport type {Tool} from '@modelcontextprotocol/sdk/types.js';\nimport {get_encoding} from 'tiktoken';\n\nimport {cliOptions} from '../build/src/bin/chrome-devtools-mcp-cli-options.js';\nimport type {ParsedArguments} from '../build/src/bin/chrome-devtools-mcp-cli-options.js';\nimport {ToolCategory, labels} from '../build/src/tools/categories.js';\nimport {createTools} from '../build/src/tools/tools.js';\n\nconst OUTPUT_PATH = './docs/tool-reference.md';\nconst SLIM_OUTPUT_PATH = './docs/slim-tool-reference.md';\nconst README_PATH = './README.md';\n\nasync function measureServer(args: string[]) {\n  // 1. Connect to your actual MCP server\n  const transport = new StdioClientTransport({\n    command: 'node',\n    args: ['./build/src/bin/chrome-devtools-mcp.js', ...args], // Point to your built MCP server\n  });\n\n  const client = new Client(\n    {name: 'measurer', version: '1.0.0'},\n    {capabilities: {}},\n  );\n  await client.connect(transport);\n\n  // 2. Fetch all tools\n  const toolsList = await client.listTools();\n\n  // 3. Serialize exactly how an LLM would see it (JSON)\n  const jsonString = JSON.stringify(toolsList.tools, null, 2);\n\n  // 4. Count tokens (using cl100k_base which is standard for GPT-4/Claude-3.5 approximation)\n  const enc = get_encoding('cl100k_base');\n  const tokenCount = enc.encode(jsonString).length;\n\n  console.log(`--- Measurement Results ---`);\n  console.log(`Total Tools: ${toolsList.tools.length}`);\n  console.log(`JSON Character Count: ${jsonString.length}`);\n  console.log(`Estimated Token Count: ~${tokenCount}`);\n\n  // Clean up\n  enc.free();\n  await client.close();\n  return {\n    tokenCount,\n  };\n}\n\n// Extend the MCP Tool type to include our annotations\ninterface ToolWithAnnotations extends Tool {\n  annotations?: {\n    title?: string;\n    category?: typeof ToolCategory;\n    conditions?: string[];\n  };\n}\n\ninterface ZodCheck {\n  kind: string;\n}\n\ninterface ZodDef {\n  typeName: string;\n  checks?: ZodCheck[];\n  values?: string[];\n  type?: ZodSchema;\n  innerType?: ZodSchema;\n  schema?: ZodSchema;\n  defaultValue?: () => unknown;\n}\n\ninterface ZodSchema {\n  _def: ZodDef;\n  description?: string;\n}\n\ninterface TypeInfo {\n  type: string;\n  enum?: string[];\n  items?: TypeInfo;\n  description?: string;\n  default?: unknown;\n}\n\nfunction escapeHtmlTags(text: string): string {\n  return text\n    .replace(/&(?![a-zA-Z]+;)/g, '&amp;')\n    .replace(/<([a-zA-Z][^>]*)>/g, '&lt;$1&gt;');\n}\n\nfunction addCrossLinks(text: string, tools: ToolWithAnnotations[]): string {\n  let result = text;\n\n  // Create a set of all tool names for efficient lookup\n  const toolNames = new Set(tools.map(tool => tool.name));\n\n  // Sort tool names by length (descending) to match longer names first\n  const sortedToolNames = Array.from(toolNames).sort(\n    (a, b) => b.length - a.length,\n  );\n\n  for (const toolName of sortedToolNames) {\n    // Create regex to match tool name (case insensitive, word boundaries)\n    const regex = new RegExp(`\\\\b${toolName}\\\\b`, 'gi');\n\n    result = result.replace(regex, match => {\n      // Only create link if the match isn't already inside a link\n      if (result.indexOf(`[${match}]`) !== -1) {\n        return match; // Already linked\n      }\n      const anchorLink = toolName.toLowerCase();\n      return `[\\`${match}\\`](#${anchorLink})`;\n    });\n  }\n\n  return result;\n}\n\nfunction generateToolsTOC(\n  categories: Record<string, ToolWithAnnotations[]>,\n  sortedCategories: string[],\n): string {\n  let toc = '';\n\n  for (const category of sortedCategories) {\n    const categoryTools = categories[category];\n    const categoryName = labels[category];\n    toc += `- **${categoryName}** (${categoryTools.length} tools)\\n`;\n\n    // Sort tools within category for TOC\n    categoryTools.sort((a: Tool, b: Tool) => a.name.localeCompare(b.name));\n    for (const tool of categoryTools) {\n      const anchorLink = tool.name.toLowerCase();\n      toc += `  - [\\`${tool.name}\\`](docs/tool-reference.md#${anchorLink})\\n`;\n    }\n  }\n\n  return toc;\n}\n\nfunction updateReadmeWithToolsTOC(toolsTOC: string): void {\n  const readmeContent = fs.readFileSync(README_PATH, 'utf8');\n\n  const beginMarker = '<!-- BEGIN AUTO GENERATED TOOLS -->';\n  const endMarker = '<!-- END AUTO GENERATED TOOLS -->';\n\n  const beginIndex = readmeContent.indexOf(beginMarker);\n  const endIndex = readmeContent.indexOf(endMarker);\n\n  if (beginIndex === -1 || endIndex === -1) {\n    console.warn('Could not find auto-generated tools markers in README.md');\n    return;\n  }\n\n  const before = readmeContent.substring(0, beginIndex + beginMarker.length);\n  const after = readmeContent.substring(endIndex);\n\n  const updatedContent = before + '\\n\\n' + toolsTOC + '\\n' + after;\n\n  fs.writeFileSync(README_PATH, updatedContent);\n  console.log('Updated README.md with tools table of contents');\n}\n\nfunction generateConfigOptionsMarkdown(): string {\n  let markdown = '';\n\n  for (const [optionName, optionConfig] of Object.entries(cliOptions)) {\n    // Skip hidden options\n    if (optionConfig.hidden) {\n      continue;\n    }\n\n    const aliasText = optionConfig.alias ? `, \\`-${optionConfig.alias}\\`` : '';\n    const description = optionConfig.description || optionConfig.describe || '';\n\n    // Convert camelCase to dash-case\n    const dashCaseName = optionName\n      .replace(/([a-z])([A-Z])/g, '$1-$2')\n      .toLowerCase();\n    const nameDisplay =\n      dashCaseName !== optionName\n        ? `\\`--${optionName}\\`/ \\`--${dashCaseName}\\``\n        : `\\`--${optionName}\\``;\n\n    // Start with option name and description\n    markdown += `- **${nameDisplay}${aliasText}**\\n`;\n    markdown += `  ${description}\\n`;\n\n    // Add type information\n    markdown += `  - **Type:** ${optionConfig.type}\\n`;\n\n    // Add choices if available\n    if (optionConfig.choices) {\n      markdown += `  - **Choices:** ${optionConfig.choices.map(c => `\\`${c}\\``).join(', ')}\\n`;\n    }\n\n    // Add default if available\n    if (optionConfig.default !== undefined) {\n      markdown += `  - **Default:** \\`${optionConfig.default}\\`\\n`;\n    }\n\n    markdown += '\\n';\n  }\n\n  return markdown.trim();\n}\n\nfunction updateReadmeWithOptionsMarkdown(optionsMarkdown: string): void {\n  const readmeContent = fs.readFileSync(README_PATH, 'utf8');\n\n  const beginMarker = '<!-- BEGIN AUTO GENERATED OPTIONS -->';\n  const endMarker = '<!-- END AUTO GENERATED OPTIONS -->';\n\n  const beginIndex = readmeContent.indexOf(beginMarker);\n  const endIndex = readmeContent.indexOf(endMarker);\n\n  if (beginIndex === -1 || endIndex === -1) {\n    console.warn('Could not find auto-generated options markers in README.md');\n    return;\n  }\n\n  const before = readmeContent.substring(0, beginIndex + beginMarker.length);\n  const after = readmeContent.substring(endIndex);\n\n  const updatedContent = before + '\\n\\n' + optionsMarkdown + '\\n\\n' + after;\n\n  fs.writeFileSync(README_PATH, updatedContent);\n  console.log('Updated README.md with options markdown');\n}\n\n// Helper to convert Zod schema to JSON schema-like object for docs\nfunction getZodTypeInfo(schema: ZodSchema): TypeInfo {\n  let description = schema.description;\n  let def = schema._def;\n  let defaultValue: unknown;\n\n  // Unwrap optional/default/effects\n  while (\n    def.typeName === 'ZodOptional' ||\n    def.typeName === 'ZodDefault' ||\n    def.typeName === 'ZodEffects'\n  ) {\n    if (def.typeName === 'ZodDefault' && def.defaultValue) {\n      defaultValue = def.defaultValue();\n    }\n    const next = def.innerType || def.schema;\n    if (!next) {\n      break;\n    }\n    schema = next;\n    def = schema._def;\n    if (!description && schema.description) {\n      description = schema.description;\n    }\n  }\n\n  const result: TypeInfo = {type: 'unknown'};\n  if (description) {\n    result.description = description;\n  }\n  if (defaultValue !== undefined) {\n    result.default = defaultValue;\n  }\n\n  switch (def.typeName) {\n    case 'ZodString':\n      result.type = 'string';\n      break;\n    case 'ZodNumber':\n      result.type = def.checks?.some((c: ZodCheck) => c.kind === 'int')\n        ? 'integer'\n        : 'number';\n      break;\n    case 'ZodBoolean':\n      result.type = 'boolean';\n      break;\n    case 'ZodEnum':\n      result.type = 'string';\n      result.enum = def.values;\n      break;\n    case 'ZodArray':\n      result.type = 'array';\n      if (def.type) {\n        result.items = getZodTypeInfo(def.type);\n      }\n      break;\n    default:\n      result.type = 'unknown';\n  }\n  return result;\n}\n\nfunction isRequired(schema: ZodSchema): boolean {\n  let def = schema._def;\n  while (def.typeName === 'ZodEffects') {\n    if (!def.schema) {\n      break;\n    }\n    schema = def.schema;\n    def = schema._def;\n  }\n  return def.typeName !== 'ZodOptional' && def.typeName !== 'ZodDefault';\n}\n\nasync function generateReference(\n  title: string,\n  outputPath: string,\n  toolsWithAnnotations: ToolWithAnnotations[],\n  categories: Record<string, ToolWithAnnotations[]>,\n  sortedCategories: string[],\n  serverArgs: string[],\n) {\n  console.log(`Found ${toolsWithAnnotations.length} tools`);\n\n  // Generate markdown documentation\n  let markdown = `<!-- AUTO GENERATED DO NOT EDIT - run 'npm run gen' to update-->\n\n# ${title} (~${(await measureServer(serverArgs)).tokenCount} cl100k_base tokens)\n\n`;\n  // Generate table of contents\n  for (const category of sortedCategories) {\n    const categoryTools = categories[category];\n    const categoryName = labels[category];\n    const anchorName = categoryName.toLowerCase().replace(/\\s+/g, '-');\n    markdown += `- **[${categoryName}](#${anchorName})** (${categoryTools.length} tools)\\n`;\n\n    // Sort tools within category for TOC\n    categoryTools.sort((a: Tool, b: Tool) => a.name.localeCompare(b.name));\n    for (const tool of categoryTools) {\n      // Generate proper markdown anchor link: backticks are removed, keep underscores, lowercase\n      const anchorLink = tool.name.toLowerCase();\n      markdown += `  - [\\`${tool.name}\\`](#${anchorLink})\\n`;\n    }\n  }\n  markdown += '\\n';\n\n  for (const category of sortedCategories) {\n    const categoryTools = categories[category];\n    const categoryName = labels[category];\n\n    markdown += `## ${categoryName}\\n\\n`;\n\n    // Sort tools within category\n    categoryTools.sort((a: Tool, b: Tool) => a.name.localeCompare(b.name));\n\n    for (const tool of categoryTools) {\n      markdown += `### \\`${tool.name}\\`\\n\\n`;\n\n      if (tool.description) {\n        // Escape HTML tags but preserve JS function syntax\n        let escapedDescription = escapeHtmlTags(tool.description);\n\n        // Add cross-links to mentioned tools\n        escapedDescription = addCrossLinks(\n          escapedDescription,\n          toolsWithAnnotations,\n        );\n        markdown += `**Description:** ${escapedDescription}\\n\\n`;\n      }\n\n      // Handle input schema\n      if (\n        tool.inputSchema &&\n        tool.inputSchema.properties &&\n        Object.keys(tool.inputSchema.properties).length > 0\n      ) {\n        const properties = tool.inputSchema.properties;\n        const required = tool.inputSchema.required || [];\n\n        markdown += '**Parameters:**\\n\\n';\n\n        const propertyNames = Object.keys(properties).sort((a, b) => {\n          const aRequired = required.includes(a);\n          const bRequired = required.includes(b);\n          if (aRequired && !bRequired) {\n            return -1;\n          }\n          if (!aRequired && bRequired) {\n            return 1;\n          }\n          return a.localeCompare(b);\n        });\n        for (const propName of propertyNames) {\n          const prop = properties[propName] as TypeInfo;\n          const isRequired = required.includes(propName);\n          const requiredText = isRequired ? ' **(required)**' : ' _(optional)_';\n\n          let typeInfo = prop.type || 'unknown';\n          if (prop.enum) {\n            typeInfo = `enum: ${prop.enum.map((v: string) => `\"${v}\"`).join(', ')}`;\n          }\n\n          markdown += `- **${propName}** (${typeInfo})${requiredText}`;\n          if (prop.description) {\n            let escapedParamDesc = escapeHtmlTags(prop.description);\n\n            // Add cross-links to mentioned tools\n            escapedParamDesc = addCrossLinks(\n              escapedParamDesc,\n              toolsWithAnnotations,\n            );\n            markdown += `: ${escapedParamDesc}`;\n          }\n          markdown += '\\n';\n        }\n        markdown += '\\n';\n      } else {\n        markdown += '**Parameters:** None\\n\\n';\n      }\n\n      markdown += '---\\n\\n';\n    }\n  }\n\n  // Write the documentation to file\n  fs.writeFileSync(outputPath, markdown.trim() + '\\n');\n\n  console.log(\n    `Generated documentation for ${toolsWithAnnotations.length} tools in ${outputPath}`,\n  );\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction getToolsAndCategories(tools: any) {\n  // Convert ToolDefinitions to ToolWithAnnotations\n  const toolsWithAnnotations: ToolWithAnnotations[] = tools\n    .filter(tool => {\n      if (!tool.annotations.conditions) {\n        return true;\n      }\n\n      // Only include unconditional tools.\n      return tool.annotations.conditions.length === 0;\n    })\n    .map(tool => {\n      const properties: Record<string, TypeInfo> = {};\n      const required: string[] = [];\n\n      for (const [key, schema] of Object.entries(\n        tool.schema as unknown as Record<string, ZodSchema>,\n      )) {\n        const info = getZodTypeInfo(schema);\n        properties[key] = info;\n        if (isRequired(schema)) {\n          required.push(key);\n        }\n      }\n\n      return {\n        name: tool.name,\n        description: tool.description,\n        inputSchema: {\n          type: 'object',\n          properties,\n          required,\n        },\n        annotations: tool.annotations,\n      };\n    });\n  // Group tools by category (based on annotations)\n  const categories: Record<string, ToolWithAnnotations[]> = {};\n  toolsWithAnnotations.forEach((tool: ToolWithAnnotations) => {\n    const category = tool.annotations?.category || 'Uncategorized';\n    if (!categories[category]) {\n      categories[category] = [];\n    }\n    categories[category].push(tool);\n  });\n\n  // Sort categories using the enum order\n  const categoryOrder = Object.values(ToolCategory);\n  const sortedCategories = Object.keys(categories).sort((a, b) => {\n    const aIndex = categoryOrder.indexOf(a);\n    const bIndex = categoryOrder.indexOf(b);\n    // Put known categories first, unknown categories last\n    if (aIndex === -1 && bIndex === -1) {\n      return a.localeCompare(b);\n    }\n    if (aIndex === -1) {\n      return 1;\n    }\n    if (bIndex === -1) {\n      return -1;\n    }\n    return aIndex - bIndex;\n  });\n  return {toolsWithAnnotations, categories, sortedCategories};\n}\n\nasync function generateToolDocumentation(): Promise<void> {\n  try {\n    console.log('Generating tool documentation from definitions...');\n\n    {\n      const {toolsWithAnnotations, categories, sortedCategories} =\n        getToolsAndCategories(createTools({slim: false} as ParsedArguments));\n      await generateReference(\n        'Chrome DevTools MCP Tool Reference',\n        OUTPUT_PATH,\n        toolsWithAnnotations,\n        categories,\n        sortedCategories,\n        [],\n      );\n\n      // Generate tools TOC and update README\n      const toolsTOC = generateToolsTOC(categories, sortedCategories);\n      updateReadmeWithToolsTOC(toolsTOC);\n    }\n\n    {\n      const {toolsWithAnnotations, categories, sortedCategories} =\n        getToolsAndCategories(createTools({slim: true} as ParsedArguments));\n      await generateReference(\n        'Chrome DevTools MCP Slim Tool Reference',\n        SLIM_OUTPUT_PATH,\n        toolsWithAnnotations,\n        categories,\n        sortedCategories,\n        ['--slim'],\n      );\n    }\n\n    // Generate and update configuration options\n    const optionsMarkdown = generateConfigOptionsMarkdown();\n    updateReadmeWithOptionsMarkdown(optionsMarkdown);\n    process.exit(0);\n  } catch (error) {\n    console.error('Error generating documentation:', error);\n    process.exit(1);\n  }\n}\n\n// Run the documentation generator\ngenerateToolDocumentation().catch(console.error);\n"
  },
  {
    "path": "scripts/post-build.ts",
    "content": "/**\n * @license\n * Copyright 2025 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\n\nconst BUILD_DIR = path.join(process.cwd(), 'build');\n\n/**\n * Writes content to a file.\n * @param filePath The path to the file.\n * @param content The content to write.\n */\nfunction writeFile(filePath: string, content: string): void {\n  fs.writeFileSync(filePath, content, 'utf-8');\n}\n\nfunction main(): void {\n  const devtoolsThirdPartyPath =\n    'node_modules/chrome-devtools-frontend/front_end/third_party';\n  const devtoolsFrontEndCorePath =\n    'node_modules/chrome-devtools-frontend/front_end/core';\n\n  // Create i18n mock\n  const i18nDir = path.join(BUILD_DIR, devtoolsFrontEndCorePath, 'i18n');\n  const localesFile = path.join(i18nDir, 'locales.js');\n  const localesContent = `\nexport const LOCALES = [\n  'en-US',\n];\n\nexport const BUNDLED_LOCALES = [\n  'en-US',\n];\n\nexport const DEFAULT_LOCALE = 'en-US';\n\nexport const REMOTE_FETCH_PATTERN = '@HOST@/remote/serve_file/@VERSION@/core/i18n/locales/@LOCALE@.json';\n\nexport const LOCAL_FETCH_PATTERN = './locales/@LOCALE@.json';`;\n  writeFile(localesFile, localesContent);\n\n  // Create codemirror.next mock.\n  const codeMirrorDir = path.join(\n    BUILD_DIR,\n    devtoolsThirdPartyPath,\n    'codemirror.next',\n  );\n  fs.mkdirSync(codeMirrorDir, {recursive: true});\n  const codeMirrorFile = path.join(codeMirrorDir, 'codemirror.next.js');\n  const codeMirrorContent = `export default {}`;\n  writeFile(codeMirrorFile, codeMirrorContent);\n\n  // Create root mock\n  const rootDir = path.join(BUILD_DIR, devtoolsFrontEndCorePath, 'root');\n  fs.mkdirSync(rootDir, {recursive: true});\n  const runtimeFile = path.join(rootDir, 'Runtime.js');\n  const runtimeContent = `\nexport function getChromeVersion() { return ''; };\nexport const hostConfig = {};\nexport const Runtime = {\n  isDescriptorEnabled: () => true,\n  queryParam: () => null,\n}\nexport const experiments = {\n  isEnabled: () => false,\n}\nexport const ExperimentName = {\n  ALL: '*',\n  CAPTURE_NODE_CREATION_STACKS: 'capture-node-creation-stacks',\n  LIVE_HEAP_PROFILE: 'live-heap-profile',\n  PROTOCOL_MONITOR: 'protocol-monitor',\n  SAMPLING_HEAP_PROFILER_TIMELINE: 'sampling-heap-profiler-timeline',\n  SHOW_OPTION_TO_EXPOSE_INTERNALS_IN_HEAP_SNAPSHOT: 'show-option-to-expose-internals-in-heap-snapshot',\n  TIMELINE_INVALIDATION_TRACKING: 'timeline-invalidation-tracking',\n  TIMELINE_SHOW_ALL_EVENTS: 'timeline-show-all-events',\n  TIMELINE_V8_RUNTIME_CALL_STATS: 'timeline-v8-runtime-call-stats',\n  APCA: 'apca',\n  FONT_EDITOR: 'font-editor',\n  FULL_ACCESSIBILITY_TREE: 'full-accessibility-tree',\n  CONTRAST_ISSUES: 'contrast-issues',\n  EXPERIMENTAL_COOKIE_FEATURES: 'experimental-cookie-features',\n  INSTRUMENTATION_BREAKPOINTS: 'instrumentation-breakpoints',\n  AUTHORED_DEPLOYED_GROUPING: 'authored-deployed-grouping',\n  JUST_MY_CODE: 'just-my-code',\n  USE_SOURCE_MAP_SCOPES: 'use-source-map-scopes',\n  TIMELINE_SHOW_POST_MESSAGE_EVENTS: 'timeline-show-postmessage-events',\n  TIMELINE_DEBUG_MODE: 'timeline-debug-mode',\n}\n  `;\n  writeFile(runtimeFile, runtimeContent);\n\n  copyDevToolsDescriptionFiles();\n}\n\nfunction copyDevToolsDescriptionFiles() {\n  const devtoolsIssuesDescriptionPath =\n    'node_modules/chrome-devtools-frontend/front_end/models/issues_manager/descriptions';\n  const sourceDir = path.join(process.cwd(), devtoolsIssuesDescriptionPath);\n  const destDir = path.join(\n    BUILD_DIR,\n    'src',\n    'third_party',\n    'issue-descriptions',\n  );\n  fs.cpSync(sourceDir, destDir, {recursive: true});\n}\n\nmain();\n"
  },
  {
    "path": "scripts/prepare.ts",
    "content": "/**\n * @license\n * Copyright 2025 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport {readFileSync, writeFileSync} from 'node:fs';\nimport {rm} from 'node:fs/promises';\nimport {resolve} from 'node:path';\n\nconst projectRoot = process.cwd();\n\nconst filesToRemove = [\n  'node_modules/chrome-devtools-frontend/package.json',\n  'node_modules/chrome-devtools-frontend/front_end/models/trace/lantern/testing',\n  'node_modules/chrome-devtools-frontend/front_end/third_party/intl-messageformat/package/package.json',\n];\n\n/**\n * Removes the conflicting global HTMLElementEventMap declaration from\n * @paulirish/trace_engine/models/trace/ModelImpl.d.ts to avoid TS2717 error\n * when both chrome-devtools-frontend and @paulirish/trace_engine declare\n * the same property.\n */\nfunction removeConflictingGlobalDeclaration(): void {\n  const filePath = resolve(\n    projectRoot,\n    'node_modules/@paulirish/trace_engine/models/trace/ModelImpl.d.ts',\n  );\n  console.log(\n    'Removing conflicting global declaration from @paulirish/trace_engine...',\n  );\n  const content = readFileSync(filePath, 'utf-8');\n  // Remove the declare global block using regex\n  // Matches: declare global { ... interface HTMLElementEventMap { ... } ... }\n  const newContent = content.replace(\n    /declare global\\s*\\{\\s*interface HTMLElementEventMap\\s*\\{[^}]*\\[ModelUpdateEvent\\.eventName\\]:\\s*ModelUpdateEvent;\\s*\\}\\s*\\}/s,\n    '',\n  );\n  writeFileSync(filePath, newContent, 'utf-8');\n  console.log('Successfully removed conflicting global declaration.');\n}\n\nasync function main() {\n  console.log('Running prepare script to clean up chrome-devtools-frontend...');\n  for (const file of filesToRemove) {\n    const fullPath = resolve(projectRoot, file);\n    console.log(`Removing: ${file}`);\n    try {\n      await rm(fullPath, {recursive: true, force: true});\n    } catch (error) {\n      console.error(`Failed to remove ${file}:`, error);\n      process.exit(1);\n    }\n  }\n  console.log('Clean up of chrome-devtools-frontend complete.');\n\n  removeConflictingGlobalDeclaration();\n}\n\nvoid main();\n"
  },
  {
    "path": "scripts/test.mjs",
    "content": "/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\n// Note: can be converted to ts file once node 20 support is dropped.\n// Node 20 does not support --experimental-strip-types flag.\n\nimport {spawn, execSync} from 'node:child_process';\nimport path from 'node:path';\nimport process from 'node:process';\n\nconst args = process.argv.slice(2);\nconst userArgs = args.filter(arg => !arg.startsWith('-'));\nconst flags = args.filter(arg => arg.startsWith('-'));\n\nconst files = [];\n\nlet shouldRetry = false;\nconst retryIndex = flags.indexOf('--retry');\nif (retryIndex !== -1) {\n  shouldRetry = true;\n  flags.splice(retryIndex, 1);\n}\n\nif (userArgs.length > 0) {\n  for (const arg of userArgs) {\n    // Map .ts files to build/ .js files\n    let testPath = arg;\n    if (testPath.endsWith('.ts')) {\n      testPath = testPath.replace(/\\.ts$/, '.js');\n      if (!testPath.startsWith('build/')) {\n        testPath = path.join('build', testPath);\n      }\n    }\n    files.push(testPath);\n  }\n} else {\n  const isNode20 = process.version.startsWith('v20.');\n  if (isNode20) {\n    files.push('build/tests');\n  } else {\n    files.push('build/tests/**/*.test.js');\n  }\n}\n\nconst nodeArgs = [\n  '--import',\n  './build/tests/setup.js',\n  '--no-warnings=ExperimentalWarning',\n  '--test-reporter',\n  (process.env['NODE_TEST_REPORTER'] ?? process.env['CI']) ? 'spec' : 'dot',\n  '--test-force-exit',\n  '--test-concurrency=1',\n  '--test',\n  '--test-timeout=60000',\n  ...flags,\n  ...files,\n];\n\nfunction installChrome(version) {\n  try {\n    return execSync(\n      `npx puppeteer browsers install chrome@${version} --format \"{{path}}\"`,\n    )\n      .toString()\n      .trim();\n  } catch (e) {\n    console.error(`Failed to install Chrome ${version}:`, e);\n    process.exit(1);\n  }\n}\n\nasync function runTests(attempt) {\n  if (attempt > 1) {\n    console.log(`\\nRun attempt ${attempt}...\\n`);\n  }\n  return new Promise(resolve => {\n    const child = spawn('node', nodeArgs, {\n      stdio: 'inherit',\n      env: {\n        ...process.env,\n        CHROME_DEVTOOLS_MCP_NO_USAGE_STATISTICS: true,\n        CHROME_DEVTOOLS_MCP_CRASH_ON_UNCAUGHT: true,\n      },\n    });\n\n    child.on('close', code => {\n      resolve(code);\n    });\n  });\n}\n\nconst chromePath = installChrome('146.0.7680.31');\nprocess.env.CHROME_M146_EXECUTABLE_PATH = chromePath;\n\nconst maxAttempts = shouldRetry ? 3 : 1;\nlet exitCode = 1;\n\nfor (let i = 1; i <= maxAttempts; i++) {\n  exitCode = await runTests(i);\n  if (exitCode === 0) {\n    break;\n  }\n}\n\nprocess.exit(exitCode ?? 1);\n"
  },
  {
    "path": "scripts/tsconfig.json",
    "content": "{\n  \"extends\": \"../tsconfig.json\",\n  \"compilerOptions\": {\n    \"target\": \"esnext\",\n    \"module\": \"nodenext\",\n    \"moduleResolution\": \"nodenext\",\n    \"outDir\": \"./ignored\",\n    \"rootDir\": \".\",\n    \"strict\": true,\n    \"esModuleInterop\": true,\n    \"skipLibCheck\": true,\n    \"forceConsistentCasingInFileNames\": true,\n    \"noImplicitReturns\": true,\n    \"noImplicitOverride\": true,\n    \"noFallthroughCasesInSwitch\": true,\n    \"incremental\": true,\n    \"allowJs\": true,\n    \"allowImportingTsExtensions\": true,\n    \"noEmit\": true,\n    \"useUnknownInCatchVariables\": false\n  },\n  \"include\": [\"./**/*.ts\", \"./**/*.js\", \"./**/*.mjs\"]\n}\n"
  },
  {
    "path": "scripts/update-lighthouse.ts",
    "content": "/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport {execSync} from 'node:child_process';\nimport fs from 'node:fs';\nimport path from 'node:path';\n\nconst ROOT_DIR = process.cwd();\nconst LIGHTHOUSE_DIR = path.resolve(ROOT_DIR, '../lighthouse');\nconst DEST_DIR = path.join(ROOT_DIR, 'src/third_party');\n\nfunction main() {\n  if (!fs.existsSync(LIGHTHOUSE_DIR)) {\n    console.error(`Lighthouse directory not found at ${LIGHTHOUSE_DIR}`);\n    process.exit(1);\n  }\n\n  console.log('Running yarn in lighthouse directory...');\n  execSync('yarn', {cwd: LIGHTHOUSE_DIR, stdio: 'inherit'});\n\n  console.log('Building lighthouse-devtools-mcp bundle...');\n  execSync('yarn build-devtools-mcp', {cwd: LIGHTHOUSE_DIR, stdio: 'inherit'});\n\n  const bundlePath = path.join(\n    LIGHTHOUSE_DIR,\n    'dist',\n    'lighthouse-devtools-mcp-bundle.js',\n  );\n\n  console.log(`Copying bundle from ${bundlePath} to ${DEST_DIR}...`);\n  fs.copyFileSync(\n    bundlePath,\n    path.join(DEST_DIR, 'lighthouse-devtools-mcp-bundle.js'),\n  );\n\n  const noticesPath = path.join(\n    LIGHTHOUSE_DIR,\n    'dist',\n    'LIGHTHOUSE_MCP_BUNDLE_THIRD_PARTY_NOTICES',\n  );\n\n  console.log(`Copying notices from ${noticesPath} to ${DEST_DIR}...`);\n  fs.copyFileSync(\n    noticesPath,\n    path.join(DEST_DIR, 'LIGHTHOUSE_MCP_BUNDLE_THIRD_PARTY_NOTICES'),\n  );\n\n  console.log('Done.');\n}\n\nmain();\n"
  },
  {
    "path": "scripts/verify-npm-package.mjs",
    "content": "/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport {execSync} from 'node:child_process';\n\n// Checks that the select build files are present using `npm publish --dry-run`.\nfunction verifyPackageContents() {\n  try {\n    const output = execSync('npm publish --dry-run --json --silent', {\n      encoding: 'utf8',\n    });\n    // skip non-JSON output from prepare.\n    const data = JSON.parse(output.substring(output.indexOf('{')));\n    const files = data.files.map(f => f.path);\n    // Check some important files.\n    const requiredPaths = [\n      'build/src/index.js',\n      'build/src/third_party/index.js',\n    ];\n    for (const requiredPath of requiredPaths) {\n      const hasBuildFolder = files.some(path => path.startsWith(requiredPath));\n      if (!hasBuildFolder) {\n        console.error(\n          `Assertion Failed: \"${requiredPath}\" not found in tarball.`,\n        );\n        process.exit(1);\n      }\n    }\n    console.log(\n      `npm publish --dry-run contained ${JSON.stringify(requiredPaths)}`,\n    );\n  } catch (err) {\n    console.error('failed to parse npm publish output', err);\n    process.exit(1);\n  }\n}\n\nverifyPackageContents();\n"
  },
  {
    "path": "scripts/verify-server-json-version.ts",
    "content": "/**\n * @license\n * Copyright 2025 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport {execSync} from 'node:child_process';\nimport fs from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\n\nconst serverJsonFilePath = path.join(process.cwd(), 'server.json');\nconst serverJson = JSON.parse(fs.readFileSync(serverJsonFilePath, 'utf-8'));\n\nconst tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'mcp-verify-'));\n\ntry {\n  const osName = os.platform();\n  const arch = os.arch();\n  let platform = '';\n  if (osName === 'darwin') {\n    platform = 'darwin';\n  } else if (osName === 'linux') {\n    platform = 'linux';\n  }\n  // mcp-publisher does not support windows\n  else {\n    throw new Error(`Unsupported platform: ${osName}`);\n  }\n\n  let archName = '';\n  if (arch === 'x64') {\n    archName = 'amd64';\n  } else if (arch === 'arm64') {\n    archName = 'arm64';\n  } else {\n    throw new Error(`Unsupported architecture: ${arch}`);\n  }\n\n  const osArch = `${platform}_${archName}`;\n  const binName = 'mcp-publisher';\n  const downloadUrl = `https://github.com/modelcontextprotocol/registry/releases/latest/download/${binName}_${osArch}.tar.gz`;\n\n  console.log(`Downloading ${binName} from ${downloadUrl}`);\n  const downloadCmd = `curl -L \"${downloadUrl}\" | tar xz -C \"${tmpDir}\" ${binName}`;\n  execSync(downloadCmd, {stdio: 'inherit'});\n\n  const publisherPath = path.join(tmpDir, binName);\n  fs.chmodSync(publisherPath, 0o755);\n  console.log(`Downloaded to ${publisherPath}`);\n\n  // Create the new server.json in the temporary directory\n  execSync(`${publisherPath} init`, {cwd: tmpDir, stdio: 'inherit'});\n\n  const newServerJsonPath = path.join(tmpDir, 'server.json');\n  const newServerJson = JSON.parse(fs.readFileSync(newServerJsonPath, 'utf-8'));\n\n  const propertyToVerify = ['$schema'];\n  const diffProps = [];\n\n  for (const prop of propertyToVerify) {\n    if (serverJson[prop] !== newServerJson[prop]) {\n      diffProps.push(prop);\n    }\n  }\n\n  if (diffProps.length) {\n    throw new Error(\n      `The following props in ${serverJsonFilePath} did not match the latest init value:\\n${diffProps.map(\n        prop =>\n          `- \"${prop}\": expected \"${newServerJson[prop]}\", got \"${serverJson[prop]}\"`,\n      )}`,\n    );\n  }\n} finally {\n  fs.rmSync(tmpDir, {recursive: true, force: true});\n}\n"
  },
  {
    "path": "server.json",
    "content": "{\n  \"$schema\": \"https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json\",\n  \"name\": \"io.github.ChromeDevTools/chrome-devtools-mcp\",\n  \"title\": \"Chrome DevTools MCP\",\n  \"description\": \"MCP server for Chrome DevTools\",\n  \"repository\": {\n    \"url\": \"https://github.com/ChromeDevTools/chrome-devtools-mcp\",\n    \"source\": \"github\"\n  },\n  \"version\": \"0.20.2\",\n  \"packages\": [\n    {\n      \"registryType\": \"npm\",\n      \"registryBaseUrl\": \"https://registry.npmjs.org\",\n      \"identifier\": \"chrome-devtools-mcp\",\n      \"version\": \"0.20.2\",\n      \"transport\": {\n        \"type\": \"stdio\"\n      },\n      \"environmentVariables\": []\n    }\n  ]\n}\n"
  },
  {
    "path": "skills/a11y-debugging/SKILL.md",
    "content": "---\nname: a11y-debugging\ndescription: Uses Chrome DevTools MCP for accessibility (a11y) debugging and auditing based on web.dev guidelines. Use when testing semantic HTML, ARIA labels, focus states, keyboard navigation, tap targets, and color contrast.\n---\n\n## Core Concepts\n\n**Accessibility Tree vs DOM**: Visually hiding an element (e.g., `CSS opacity: 0`) behaves differently for screen readers than `display: none` or `aria-hidden=\"true\"`. The `take_snapshot` tool returns the accessibility tree of the page, which represents what assistive technologies \"see\", making it the most reliable source of truth for semantic structure.\n\n**Reading web.dev documentation**: If you need to research specific accessibility guidelines (like `https://web.dev/articles/accessible-tap-targets`), you can append `.md.txt` to the URL (e.g., `https://web.dev/articles/accessible-tap-targets.md.txt`) to fetch the clean, raw markdown version. This is much easier to read!\n\n## Workflow Patterns\n\n### 1. Automated Audit (Lighthouse)\n\nStart by running a Lighthouse accessibility audit to get a comprehensive baseline. This tool provides a high-level score and lists specific failing elements with remediation advice.\n\n1.  Run the audit:\n    - Set `mode` to `\"navigation\"` to refresh the page and capture load issues.\n    - Set `outputDirPath` (e.g., `/tmp/lh-report`) to save the full JSON report.\n2.  **Analyze the Summary**:\n    - Check `scores` (0-1 scale). A score < 1 indicates violations.\n    - Review `audits.failed` count.\n3.  **Review the Report (CRITICAL)**:\n    - **Parsing**: Do not read the entire file line-by-line. Use a CLI tool like `jq` or a Node.js one-liner to filter for failures:\n      ```bash\n      # Extract failing audits with their details\n      node -e \"const r=require('./report.json'); Object.values(r.audits).filter(a=>a.score!==null && a.score<1).forEach(a=>console.log(JSON.stringify({id:a.id, title:a.title, items:a.details?.items})))\"\n      ```\n    - This efficiently extracts the `selector` and `snippet` of failing elements without loading the full report into context.\n\n### 2. Browser Issues & Audits\n\nChrome automatically checks for common accessibility problems. Use `list_console_messages` to check for these native audits:\n\n- `types`: `[\"issue\"]`\n- `includePreservedMessages`: `true` (to catch issues that occurred during page load)\n\nThis often reveals missing labels, invalid ARIA attributes, and other critical errors without manual investigation.\n\n### 3. Semantics & Structure\n\nThe accessibility tree exposes the heading hierarchy and semantic landmarks.\n\n1.  Navigate to the page.\n2.  Use `take_snapshot` to capture the accessibility tree.\n3.  **Check Heading Levels**: Ensure heading levels (`h1`, `h2`, `h3`, etc.) are logical and do not skip levels. The snapshot will include heading roles.\n4.  **Content Reordering**: Verify that the DOM order (which drives the accessibility tree) matches the visual reading order. Use `take_screenshot` to inspect the visual layout and compare it against the snapshot structure to catch CSS floats or absolute positioning that jumbles the logical flow.\n\n### 4. Labels, Forms & Text Alternatives\n\n1.  Locate buttons, inputs, and images in the `take_snapshot` output.\n2.  Ensure interactive elements have an accessible name (e.g., a button should not just say `\"\"` if it only contains an icon).\n3.  **Orphaned Inputs**: Verify that all form inputs have associated labels. Use `evaluate_script` with the **\"Find Orphaned Form Inputs\" snippet** found in [references/a11y-snippets.md](references/a11y-snippets.md).\n4.  Check images for `alt` text.\n\n### 5. Focus & Keyboard Navigation\n\nTesting \"keyboard traps\" and proper focus management without visual feedback relies on tracking the focused element.\n\n1.  Use the `press_key` tool with `\"Tab\"` or `\"Shift+Tab\"` to move focus.\n2.  Use `take_snapshot` to capture the updated accessibility tree.\n3.  Locate the element marked as focused in the snapshot to verify focus moved to the expected interactive element.\n4.  If a modal opens, focus must move into the modal and \"trap\" within it until closed.\n\n### 6. Tap Targets and Visuals\n\nAccording to web.dev, tap targets should be at least 48x48 pixels with sufficient spacing. Since the accessibility tree doesn't show sizes, use `evaluate_script` with the **\"Measure Tap Target Size\" snippet** found in [references/a11y-snippets.md](references/a11y-snippets.md).\n\n_Pass the element's `uid` from the snapshot as an argument to `evaluate_script`._\n\n### 7. Color Contrast\n\nTo verify color contrast ratios, start by checking for native accessibility issues:\n\n1.  Call `list_console_messages` with `types: [\"issue\"]`.\n2.  Look for \"Low Contrast\" issues in the output.\n\nIf native audits do not report issues (which may happen in some headless environments) or if you need to check a specific element manually, use `evaluate_script` with the **\"Check Color Contrast\" snippet** found in [references/a11y-snippets.md](references/a11y-snippets.md).\n\n### 8. Global Page Checks\n\nVerify document-level accessibility settings often missed in component testing using the **\"Global Page Checks\" snippet** found in [references/a11y-snippets.md](references/a11y-snippets.md).\n\n## Troubleshooting\n\nIf standard a11y queries fail or the `evaluate_script` snippets return unexpected results:\n\n- **Visual Inspection**: If automated scripts cannot determine contrast (e.g., text over gradient images or complex backgrounds), use `take_screenshot` to capture the element. While models cannot measure exact contrast ratios from images, they can visually assess legibility and identify obvious issues.\n"
  },
  {
    "path": "skills/a11y-debugging/references/a11y-snippets.md",
    "content": "# Accessibility Debugging Snippets\n\nUse these JavaScript snippets with the `evaluate_script` tool.\n\n## 1. Find Orphaned Form Inputs\n\nFinds form inputs that lack an associated label (no `label[for]`, `aria-label`, `aria-labelledby`, or wrapping `<label>`).\n\n```js\n() =>\n  Array.from(document.querySelectorAll('input, select, textarea'))\n    .filter(i => {\n      const hasId = i.id && document.querySelector(`label[for=\"${i.id}\"]`);\n      const hasAria =\n        i.getAttribute('aria-label') || i.getAttribute('aria-labelledby');\n      return !hasId && !hasAria && !i.closest('label');\n    })\n    .map(i => ({\n      tag: i.tagName,\n      id: i.id,\n      name: i.name,\n      placeholder: i.placeholder,\n    }));\n```\n\n## 2. Measure Tap Target Size\n\nReturns the bounding box dimensions of an element. Pass the element's `uid` from the snapshot as an argument to `evaluate_script`.\n\n```js\nel => {\n  const rect = el.getBoundingClientRect();\n  return {width: rect.width, height: rect.height};\n};\n```\n\n## 3. Check Color Contrast\n\nApproximates the contrast ratio between an element's text color and background color. Pass the element's `uid` to test against WCAG AA (4.5:1 for normal text, 3:1 for large text).\n\n**Note**: This uses a simplified algorithm and may not account for transparency, gradients, or background images. For production-grade auditing, consider injecting `axe-core`.\n\n```js\nel => {\n  function getRGB(colorStr) {\n    const match = colorStr.match(/rgba?\\((\\d+),\\s*(\\d+),\\s*(\\d+)/);\n    return match\n      ? [parseInt(match[1]), parseInt(match[2]), parseInt(match[3])]\n      : [255, 255, 255];\n  }\n  function luminance(r, g, b) {\n    const a = [r, g, b].map(function (v) {\n      v /= 255;\n      return v <= 0.03928 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4);\n    });\n    return a[0] * 0.2126 + a[1] * 0.7152 + a[2] * 0.0722;\n  }\n\n  const style = window.getComputedStyle(el);\n  const fg = getRGB(style.color);\n  let bg = getRGB(style.backgroundColor);\n\n  const l1 = luminance(fg[0], fg[1], fg[2]);\n  const l2 = luminance(bg[0], bg[1], bg[2]);\n  const ratio = (Math.max(l1, l2) + 0.05) / (Math.min(l1, l2) + 0.05);\n\n  return {\n    color: style.color,\n    bg: style.backgroundColor,\n    contrastRatio: ratio.toFixed(2),\n  };\n};\n```\n\n## 4. Global Page Checks\n\nChecks document-level accessibility settings often missed in component testing.\n\n```js\n() => ({\n  lang:\n    document.documentElement.lang ||\n    'MISSING - Screen readers need this for pronunciation',\n  title: document.title || 'MISSING - Required for context',\n  viewport:\n    document.querySelector('meta[name=\"viewport\"]')?.content ||\n    'MISSING - Check for user-scalable=no (bad practice)',\n  reducedMotion: window.matchMedia('(prefers-reduced-motion: reduce)').matches\n    ? 'Enabled'\n    : 'Disabled',\n});\n```\n"
  },
  {
    "path": "skills/chrome-devtools/SKILL.md",
    "content": "---\nname: chrome-devtools\ndescription: Uses Chrome DevTools via MCP for efficient debugging, troubleshooting and browser automation. Use when debugging web pages, automating browser interactions, analyzing performance, or inspecting network requests. This skill does not apply to `--slim` mode (MCP configuration).\n---\n\n## Core Concepts\n\n**Browser lifecycle**: Browser starts automatically on first tool call using a persistent Chrome profile. Configure via CLI args in the MCP server configuration: `npx chrome-devtools-mcp@latest --help`.\n\n**Page selection**: Tools operate on the currently selected page. Use `list_pages` to see available pages, then `select_page` to switch context.\n\n**Element interaction**: Use `take_snapshot` to get page structure with element `uid`s. Each element has a unique `uid` for interaction. If an element isn't found, take a fresh snapshot - the element may have been removed or the page changed.\n\n## Workflow Patterns\n\n### Before interacting with a page\n\n1. Navigate: `navigate_page` or `new_page`\n2. Wait: `wait_for` to ensure content is loaded if you know what you look for.\n3. Snapshot: `take_snapshot` to understand page structure\n4. Interact: Use element `uid`s from snapshot for `click`, `fill`, etc.\n\n### Efficient data retrieval\n\n- Use `filePath` parameter for large outputs (screenshots, snapshots, traces)\n- Use pagination (`pageIdx`, `pageSize`) and filtering (`types`) to minimize data\n- Set `includeSnapshot: false` on input actions unless you need updated page state\n\n### Tool selection\n\n- **Automation/interaction**: `take_snapshot` (text-based, faster, better for automation)\n- **Visual inspection**: `take_screenshot` (when user needs to see visual state)\n- **Additional details**: `evaluate_script` for data not in accessibility tree\n\n### Parallel execution\n\nYou can send multiple tool calls in parallel, but maintain correct order: navigate → wait → snapshot → interact.\n\n## Troubleshooting\n\nIf `chrome-devtools-mcp` is insufficient, guide users to use Chrome DevTools UI:\n\n- https://developer.chrome.com/docs/devtools\n- https://developer.chrome.com/docs/devtools/ai-assistance\n\nIf there are errors launching `chrome-devtools-mcp` or Chrome, refer to https://github.com/ChromeDevTools/chrome-devtools-mcp/blob/main/docs/troubleshooting.md.\n"
  },
  {
    "path": "skills/chrome-devtools-cli/SKILL.md",
    "content": "---\nname: chrome-devtools-cli\ndescription: Use this to skill to write shell scripts or run shell commands to automate tasks in the browser or otherwise use Chrome DevTools via CLI.\n---\n\nThe `chrome-devtools-mcp` CLI lets you interact with the browser from your terminal.\n\n## Setup\n\n_Note: If this is your very first time using the CLI, see [references/installation.md](references/installation.md) for setup. Installation is a one-time prerequisite and is **not** part of the regular AI workflow._\n\n## AI Workflow\n\n1. **Execute**: Run tools directly (e.g., `chrome-devtools list_pages`). The background server starts implicitly; **do not** run `start`/`status`/`stop` before each use.\n2. **Inspect**: Use `take_snapshot` to get an element `<uid>`.\n3. **Act**: Use `click`, `fill`, etc. State persists across commands.\n\nSnapshot example:\n\n```\nuid=1_0 RootWebArea \"Example Domain\" url=\"https://example.com/\"\n  uid=1_1 heading \"Example Domain\" level=\"1\"\n```\n\n## Command Usage\n\n```sh\nchrome-devtools <tool> [arguments] [flags]\n```\n\nUse `--help` on any command. Output defaults to Markdown, use `--output-format=json` for JSON.\n\n## Input Automation (<uid> from snapshot)\n\n```bash\nchrome-devtools take_snapshot --help # Help message for commands, works for any command.\nchrome-devtools take_snapshot # Take a text snapshot of the page to get UIDs for elements\nchrome-devtools click \"id\" # Clicks on the provided element\nchrome-devtools click \"id\" --dblClick true --includeSnapshot true # Double clicks and returns a snapshot\nchrome-devtools drag \"src\" \"dst\" # Drag an element onto another element\nchrome-devtools drag \"src\" \"dst\" --includeSnapshot true # Drag an element and return a snapshot\nchrome-devtools fill \"id\" \"text\" # Type text into an input or select an option\nchrome-devtools fill \"id\" \"text\" --includeSnapshot true # Fill an element and return a snapshot\nchrome-devtools handle_dialog accept # Handle a browser dialog\nchrome-devtools handle_dialog dismiss --promptText \"hi\" # Dismiss a dialog with prompt text\nchrome-devtools hover \"id\" # Hover over the provided element\nchrome-devtools hover \"id\" --includeSnapshot true # Hover over an element and return a snapshot\nchrome-devtools press_key \"Enter\" # Press a key or key combination\nchrome-devtools press_key \"Control+A\" --includeSnapshot true # Press a key and return a snapshot\nchrome-devtools type_text \"hello\" # Type text using keyboard into a focused input\nchrome-devtools type_text \"hello\" --submitKey \"Enter\" # Type text and press a submit key\nchrome-devtools upload_file \"id\" \"file.txt\" # Upload a file through a provided element\nchrome-devtools upload_file \"id\" \"file.txt\" --includeSnapshot true # Upload a file and return a snapshot\n```\n\n## Navigation\n\n```bash\nchrome-devtools close_page 1 # Closes the page by its index\nchrome-devtools list_pages # Get a list of pages open in the browser\nchrome-devtools navigate_page --url \"https://example.com\" # Navigates the currently selected page to a URL\nchrome-devtools navigate_page --type \"reload\" --ignoreCache true # Reload page ignoring cache\nchrome-devtools navigate_page --url \"https://example.com\" --timeout 5000 # Navigate with a timeout\nchrome-devtools navigate_page --handleBeforeUnload \"accept\" # Handle before unload dialog\nchrome-devtools navigate_page --type \"back\" --initScript \"foo()\" # Navigate back and run an init script\nchrome-devtools new_page \"https://example.com\" # Creates a new page\nchrome-devtools new_page \"https://example.com\" --background true --timeout 5000 # Create new page in background\nchrome-devtools new_page \"https://example.com\" --isolatedContext \"ctx\" # Create new page with isolated context\nchrome-devtools select_page 1 # Select a page as a context for future tool calls\nchrome-devtools select_page 1 --bringToFront true # Select a page and bring it to front\n```\n\n## Emulation\n\n```bash\nchrome-devtools emulate --networkConditions \"Offline\" # Emulate network conditions\nchrome-devtools emulate --cpuThrottlingRate 4 --geolocation \"0,0\" # Emulate CPU throttling and geolocation\nchrome-devtools emulate --colorScheme \"dark\" --viewport \"1920x1080\" # Emulate color scheme and viewport\nchrome-devtools emulate --userAgent \"Mozilla/5.0...\" # Emulate user agent\nchrome-devtools resize_page 1920 1080 # Resizes the selected page's window\n```\n\n## Performance\n\n```bash\nchrome-devtools performance_analyze_insight \"1\" \"LCPBreakdown\" # Get more details on a specific Performance Insight\nchrome-devtools performance_start_trace true false # Starts a performance trace recording\nchrome-devtools performance_start_trace true true --filePath t.gz # Start trace and save to a file\nchrome-devtools performance_stop_trace # Stops the active performance trace\nchrome-devtools performance_stop_trace --filePath \"t.json\" # Stop trace and save to a file\nchrome-devtools take_memory_snapshot \"./snap.heapsnapshot\" # Capture a memory heapsnapshot\n```\n\n## Network\n\n```bash\nchrome-devtools get_network_request # Get the currently selected network request\nchrome-devtools get_network_request --reqid 1 --requestFilePath req.md # Get request by id and save to file\nchrome-devtools get_network_request --responseFilePath res.md # Save response body to file\nchrome-devtools list_network_requests # List all network requests\nchrome-devtools list_network_requests --pageSize 50 --pageIdx 0 # List network requests with pagination\nchrome-devtools list_network_requests --resourceTypes Fetch # Filter requests by resource type\nchrome-devtools list_network_requests --includePreservedRequests true # Include preserved requests\n```\n\n## Debugging & Inspection\n\n```bash\nchrome-devtools evaluate_script \"() => document.title\" # Evaluate a JavaScript function on the page\nevaluate_script \"(a) => a.innerText\" --args 1_4 # Evaluate JS with UID arguments\nchrome-devtools get_console_message 1 # Gets a console message by its ID\nchrome-devtools lighthouse_audit --mode \"navigation\" # Run Lighthouse audit for navigation\nchrome-devtools lighthouse_audit --mode \"snapshot\" --device \"mobile\" # Run Lighthouse audit for a snapshot on mobile\nchrome-devtools lighthouse_audit --outputDirPath ./out # Run Lighthouse audit and save reports\nchrome-devtools list_console_messages # List all console messages\nchrome-devtools list_console_messages --pageSize 20 --pageIdx 1 # List console messages with pagination\nchrome-devtools list_console_messages --types error --types info # Filter console messages by type\nchrome-devtools list_console_messages --includePreservedMessages true # Include preserved messages\nchrome-devtools take_screenshot # Take a screenshot of the page viewport\nchrome-devtools take_screenshot --fullPage true --format \"jpeg\" --quality 80 # Take a full page screenshot as JPEG with quality\nchrome-devtools take_screenshot --uid \"id\" --filePath \"s.png\" # Take a screenshot of an element\nchrome-devtools take_snapshot # Take a text snapshot of the page from the a11y tree\nchrome-devtools take_snapshot --verbose true --filePath \"s.txt\" # Take a verbose snapshot and save to file\n```\n\n## Service Management\n\n```bash\nchrome-devtools start   # Start or restart chrome-devtools-mcp\nchrome-devtools status  # Checks if chrome-devtools-mcp is running\nchrome-devtools stop    # Stop chrome-devtools-mcp if any\n```\n"
  },
  {
    "path": "skills/chrome-devtools-cli/references/installation.md",
    "content": "# Installation\n\nInstall the package globally to make the `chrome-devtools` command available. You only need to do this the first time you use it.\n\n```sh\nnpm i chrome-devtools-mcp@latest -g\nchrome-devtools status # check if install worked.\n```\n\n## Troubleshooting\n\n- **Command not found:** If `chrome-devtools` is not recognized, ensure your global npm `bin` directory is in your system's `PATH`. Restart your terminal or source your shell configuration file (e.g., `.bashrc`, `.zshrc`).\n- **Permission errors:** If you encounter `EACCES` or permission errors during installation, avoid using `sudo`. Instead, use a node version manager like `nvm`, or configure npm to use a different global directory.\n- **Old version running:** Run `chrome-devtools stop && npm uninstall -g chrome-devtools-mcp` before reinstalling, or ensure the latest version is being picked up by your path.\n"
  },
  {
    "path": "skills/debug-optimize-lcp/SKILL.md",
    "content": "---\nname: debug-optimize-lcp\ndescription: Guides debugging and optimizing Largest Contentful Paint (LCP) using Chrome DevTools MCP tools. Use this skill whenever the user asks about LCP performance, slow page loads, Core Web Vitals optimization, or wants to understand why their page's main content takes too long to appear. Also use when the user mentions \"largest contentful paint\", \"page load speed\", \"CWV\", or wants to improve how fast their hero image or main content renders.\n---\n\n## What is LCP and why it matters\n\nLargest Contentful Paint (LCP) measures how quickly a page's main content becomes visible. It's the time from navigation start until the largest image or text block renders in the viewport.\n\n- **Good**: 2.5 seconds or less\n- **Needs improvement**: 2.5–4.0 seconds\n- **Poor**: greater than 4.0 seconds\n\nLCP is a Core Web Vital that directly affects user experience and search ranking. On 73% of mobile pages, the LCP element is an image.\n\n## LCP Subparts Breakdown\n\nEvery page's LCP breaks down into four sequential subparts with no gaps or overlaps. Understanding which subpart is the bottleneck is the key to effective optimization.\n\n| Subpart                       | Ideal % of LCP | What it measures                               |\n| ----------------------------- | -------------- | ---------------------------------------------- |\n| **Time to First Byte (TTFB)** | ~40%           | Navigation start → first byte of HTML received |\n| **Resource load delay**       | <10%           | TTFB → browser starts loading the LCP resource |\n| **Resource load duration**    | ~40%           | Time to download the LCP resource              |\n| **Element render delay**      | <10%           | LCP resource downloaded → LCP element rendered |\n\nThe \"delay\" subparts should be as close to zero as possible. If either delay subpart is large relative to the total LCP, that's the first place to optimize.\n\n**Common Pitfall**: Optimizing one subpart (like compressing an image to reduce load duration) without checking others. If render delay is the real bottleneck, a smaller image won't help — the saved time just shifts to render delay.\n\n## Debugging Workflow\n\nFollow these steps in order. Each step builds on the previous one.\n\n### Step 1: Record a Performance Trace\n\nNavigate to the page, then record a trace with reload to capture the full page load including LCP:\n\n1. `navigate_page` to the target URL.\n2. `performance_start_trace` with `reload: true` and `autoStop: true`.\n\nThe trace results will include LCP timing and available insight sets. Note the insight set IDs from the output — you'll need them in the next step.\n\n### Step 2: Analyze LCP Insights\n\nUse `performance_analyze_insight` to drill into LCP-specific insights. Look for these insight names in the trace results:\n\n- **LCPBreakdown** — Shows the four LCP subparts with timing for each.\n- **DocumentLatency** — Server response time issues affecting TTFB.\n- **RenderBlocking** — Resources blocking the LCP element from rendering.\n- **LCPDiscovery** — Whether the LCP resource was discoverable early.\n\nCall `performance_analyze_insight` with the insight name and the insight set ID from the trace results.\n\n### Step 3: Identify the LCP Element\n\nUse `evaluate_script` with the **\"Identify LCP Element\" snippet** found in [references/lcp-snippets.md](references/lcp-snippets.md) to reveal the LCP element's tag, resource URL, and raw timing data.\n\nThe `url` field tells you what resource to look for in the network waterfall. If `url` is empty, the LCP element is text-based (no resource to load).\n\n### Step 4: Check the Network Waterfall\n\nUse `list_network_requests` to see when the LCP resource loaded relative to other resources:\n\n- Call `list_network_requests` filtered by `resourceTypes: [\"Image\", \"Font\"]` (adjust based on Step 3).\n- Then use `get_network_request` with the LCP resource's request ID for full details.\n\n**Key Checks:**\n\n- **Start Time**: Compare against the HTML document and the first resource. If the LCP resource starts much later than the first resource, there's resource load delay to eliminate.\n- **Duration**: A large resource load duration suggests the file is too big or the server is slow.\n\n### Step 5: Inspect HTML for Common Issues\n\nUse `evaluate_script` with the **\"Audit Common Issues\" snippet** found in [references/lcp-snippets.md](references/lcp-snippets.md) to check for lazy-loaded images in the viewport, missing fetchpriority, and render-blocking scripts.\n\n## Optimization Strategies\n\nAfter identifying the bottleneck subpart, apply these prioritized fixes.\n\n### 1. Eliminate Resource Load Delay (target: <10%)\n\nThe most common bottleneck. The LCP resource should start loading immediately.\n\n- **Root Cause**: LCP image loaded via JS/CSS, `data-src` usage, or `loading=\"lazy\"`.\n- **Fix**: Use standard `<img>` with `src`. **Never** lazy-load the LCP image.\n- **Fix**: Add `<link rel=\"preload\" fetchpriority=\"high\">` if the image isn't discoverable in HTML.\n- **Fix**: Add `fetchpriority=\"high\"` to the LCP `<img>` tag.\n\n### 2. Eliminate Element Render Delay (target: <10%)\n\nThe element should render immediately after loading.\n\n- **Root Cause**: Large stylesheets, synchronous scripts in `<head>`, or main thread blocking.\n- **Fix**: Inline critical CSS, defer non-critical CSS/JS.\n- **Fix**: Break up long tasks blocking the main thread.\n- **Fix**: Use Server-Side Rendering (SSR) so the element exists in initial HTML.\n\n### 3. Reduce Resource Load Duration (target: ~40%)\n\nMake the resource smaller or faster to deliver.\n\n- **Fix**: Use modern formats (WebP, AVIF) and responsive images (`srcset`).\n- **Fix**: Serve from a CDN.\n- **Fix**: Set `Cache-Control` headers.\n- **Fix**: Use `font-display: swap` if LCP is text blocked by a web font.\n\n### 4. Reduce TTFB (target: ~40%)\n\nThe HTML document itself takes too long to arrive.\n\n- **Fix**: Minimize redirects and optimize server response time.\n- **Fix**: Cache HTML at the edge (CDN).\n- **Fix**: Ensure pages are eligible for back/forward cache (bfcache).\n\n## Verifying Fixes & Emulation\n\n- **Verification**: Re-run the trace (`performance_start_trace` with `reload: true`) and compare the new subpart breakdown. The bottleneck should shrink.\n- **Emulation**: Lab measurements differ from real-world experience. Use `emulate` to test under constraints:\n  - `emulate` with `networkConditions: \"Fast 3G\"` and `cpuThrottlingRate: 4`.\n  - This surfaces issues visible only on slower connections/devices.\n"
  },
  {
    "path": "skills/debug-optimize-lcp/references/elements-and-size.md",
    "content": "# Elements and Size for LCP\n\n## What Elements are Considered?\n\nThe types of elements considered for Largest Contentful Paint (LCP) are:\n\n- **`<img>` elements**: The first frame presentation time is used for animated content like GIFs.\n- **`<image>` elements** inside an `<svg>` element.\n- **`<video>` elements**: The poster image load time or first frame presentation time, whichever is earlier.\n- **Background images**: Elements with a background image loaded using `url()`.\n- **Block-level elements**: Containing text nodes or other inline-level text element children.\n\n## Heuristics to Exclude Non-Contentful Elements\n\nChromium-based browsers use heuristics to exclude:\n\n- Elements with **opacity of 0**.\n- Elements that **cover the full viewport** (likely background).\n- **Placeholder images** or low-entropy images.\n\n## How is an Element's Size Determined?\n\n- **Visible Area**: Typically the size visible within the viewport. Extending outside, clipped, or overflow portions don't count.\n- **Image Elements**: Either the visible size or the intrinsic size, whichever is smaller.\n- **Text Elements**: The smallest rectangle containing all text nodes.\n- **Exclusions**: Margin, padding, and borders are not considered toward the size.\n- **Containment**: Every text node belongs to its closest block-level ancestor element.\n"
  },
  {
    "path": "skills/debug-optimize-lcp/references/lcp-breakdown.md",
    "content": "# Largest Contentful Paint (LCP) Breakdown\n\nLCP measures the time from when the user initiates loading the page until the largest image or text block is rendered within the viewport. To provide a good user experience, sites should strive to have an LCP of 2.5 seconds or less for at least 75% of page visits.\n\n## The Four Subparts of LCP\n\nEvery page's LCP consists of these four subcategories. There's no gap or overlap between them, and they add up to the full LCP time.\n\n| LCP subpart                   | % of LCP (Optimal) | Description                                                                                                                                                              |\n| ----------------------------- | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n| **Time to First Byte (TTFB)** | ~40%               | The time from when the user initiates loading the page until the browser receives the first byte of the HTML document response.                                          |\n| **Resource load delay**       | <10%               | The time between TTFB and when the browser starts loading the LCP resource. If the LCP element doesn't require a resource load (e.g., system font text), this time is 0. |\n| **Resource load duration**    | ~40%               | The duration of time it takes to load the LCP resource itself. If the LCP element doesn't require a resource load, this time is 0.                                       |\n| **Element render delay**      | <10%               | The time between when the LCP resource finishes loading and the LCP element rendering fully.                                                                             |\n\n## Why the Breakdown Matters\n\nOptimizing for LCP requires identifying which of these subparts is the bottleneck:\n\n- **Large delta between TTFB and FCP**: Indicates the browser needs to download a lot of render-blocking assets or complete a lot of work (e.g., client-side rendering).\n- **Large delta between FCP and LCP**: Indicates the LCP resource is not immediately available for the browser to prioritize or the browser is completing other work before it can display the LCP content.\n- **Large resource load delay**: Indicates the resource is not discoverable early or is deprioritized.\n- **Large element render delay**: Indicates rendering is blocked by stylesheets, scripts, or long tasks.\n"
  },
  {
    "path": "skills/debug-optimize-lcp/references/lcp-snippets.md",
    "content": "# LCP Debugging Snippets\n\nUse these JavaScript snippets with the `evaluate_script` tool to extract deep insights from the page.\n\n## 1. Identify LCP Element\n\nUse this snippet to identify the LCP element and get raw timing data from the Performance API.\n\n```javascript\nasync () => {\n  return await new Promise(resolve => {\n    new PerformanceObserver(list => {\n      const entries = list.getEntries();\n      const last = entries[entries.length - 1];\n      resolve({\n        element: last.element?.tagName,\n        id: last.element?.id,\n        className: last.element?.className,\n        url: last.url,\n        startTime: last.startTime,\n        renderTime: last.renderTime,\n        loadTime: last.loadTime,\n        size: last.size,\n      });\n    }).observe({type: 'largest-contentful-paint', buffered: true});\n  });\n};\n```\n\n## 2. Audit Common Issues\n\nUse this snippet to check for common DOM-based LCP issues (lazy loading, priority).\n\n```javascript\n() => {\n  const issues = [];\n\n  // Check for lazy-loaded images in viewport\n  document.querySelectorAll('img[loading=\"lazy\"]').forEach(img => {\n    const rect = img.getBoundingClientRect();\n    if (rect.top < window.innerHeight) {\n      issues.push({\n        issue: 'lazy-loaded image in viewport',\n        element: img.outerHTML.substring(0, 200),\n        fix: 'Remove loading=\"lazy\" from this image — it is in the initial viewport and may be the LCP element',\n      });\n    }\n  });\n\n  // Check for LCP-candidate images missing fetchpriority\n  document.querySelectorAll('img:not([fetchpriority])').forEach(img => {\n    const rect = img.getBoundingClientRect();\n    if (rect.top < window.innerHeight && rect.width * rect.height > 50000) {\n      issues.push({\n        issue: 'large viewport image without fetchpriority',\n        element: img.outerHTML.substring(0, 200),\n        fix: 'Add fetchpriority=\"high\" to this image — it is large and visible in the initial viewport',\n      });\n    }\n  });\n\n  // Check for render-blocking scripts in head\n  document\n    .querySelectorAll(\n      'head script:not([async]):not([defer]):not([type=\"module\"])',\n    )\n    .forEach(script => {\n      if (script.src) {\n        issues.push({\n          issue: 'render-blocking script in head',\n          element: script.outerHTML.substring(0, 200),\n          fix: 'Add async or defer attribute, or move to end of body',\n        });\n      }\n    });\n\n  return {issueCount: issues.length, issues};\n};\n```\n"
  },
  {
    "path": "skills/debug-optimize-lcp/references/optimization-strategies.md",
    "content": "# LCP Optimization Strategies\n\n## 1. Eliminate Resource Load Delay\n\n**Goal**: Ensure the LCP resource starts loading as early as possible.\n\n- **Early Discovery**: Ensure the LCP resource is discoverable in the initial HTML document response (not dynamically added by JS or hidden in `data-src`).\n- **Preload**: Use `<link rel=\"preload\">` with `fetchpriority=\"high\"` for critical images or fonts.\n- **Avoid Lazy Loading**: Never set `loading=\"lazy\"` on the LCP image.\n- **Fetch Priority**: Use `fetchpriority=\"high\"` on the `<img>` tag.\n- **Same Origin**: Host critical resources on the same origin or use `<link rel=\"preconnect\">`.\n\n## 2. Eliminate Element Render Delay\n\n**Goal**: Ensure the LCP element can render immediately after its resource has finished loading.\n\n- **Minimize Render-Blocking CSS**: Inline critical CSS and defer non-critical CSS. Ensure the stylesheet is smaller than the LCP resource.\n- **Minimize Render-Blocking JS**: Avoid synchronous scripts in the `<head>`. Inline very small scripts.\n- **Server-Side Rendering (SSR)**: Deliver the full HTML markup from the server so image resources are discoverable immediately.\n- **Break Up Long Tasks**: Prevent large JavaScript tasks from blocking the main thread during rendering.\n\n## 3. Reduce Resource Load Duration\n\n**Goal**: Reduce the time spent transferring the bytes of the resource.\n\n- **Optimize Resource Size**: Serve optimal image sizes, use modern formats (AVIF, WebP), and compress images/fonts.\n- **Geographic Proximity (CDN)**: Use a Content Delivery Network to get servers closer to users.\n- **Reduce Contention**: Use `fetchpriority=\"high\"` to prevent lower-priority resources from competing for bandwidth.\n- **Caching**: Use efficient `Cache-Control` policies.\n\n## 4. Reduce Time to First Byte (TTFB)\n\n**Goal**: Deliver the initial HTML as quickly as possible.\n\n- **Minimize Redirects**: Avoid multiple redirects from advertisements or shortened links.\n- **CDN Caching**: Cache static HTML documents at the edge.\n- **Edge Computing**: Move dynamic logic to the edge to avoid trips to the origin server.\n- **Back/Forward Cache**: Ensure pages are eligible for bfcache.\n"
  },
  {
    "path": "skills/troubleshooting/SKILL.md",
    "content": "---\nname: troubleshooting\ndescription: Uses Chrome DevTools MCP and documentation to troubleshoot connection and target issues. Trigger this skill when list_pages, new_page, or navigate_page fail, or when the server initialization fails.\n---\n\n## Troubleshooting Wizard\n\nYou are acting as a troubleshooting wizard to help the user configure and fix their Chrome DevTools MCP server setup. When this skill is triggered (e.g., because `list_pages`, `new_page`, or `navigate_page` failed, or the server wouldn't start), follow this step-by-step diagnostic process:\n\n### Step 1: Find and Read Configuration\n\nYour first action should be to locate and read the MCP configuration file. Search for the following files in the user's workspace: `.mcp.json`, `gemini-extension.json`, `.claude/settings.json`, `.vscode/launch.json`, or `.gemini/settings.json`.\n\nIf you find a configuration file, read and interpret it to identify potential issues such as:\n\n- Incorrect arguments or flags.\n- Missing environment variables.\n- Usage of `--autoConnect` in incompatible environments.\n\nIf you cannot find any of these files, only then should you ask the user to provide their configuration file content.\n\n### Step 2: Triage Common Connection Errors\n\nBefore reading documentation or suggesting configuration changes, check if the error message matches one of the following common patterns.\n\n#### Error: `Could not find DevToolsActivePort`\n\nThis error is highly specific to the `--autoConnect` feature. It means the MCP server cannot find the file created by a running, debuggable Chrome instance. This is not a generic connection failure.\n\nYour primary goal is to guide the user to ensure Chrome is running and properly configured. Do not immediately suggest switching to `--browserUrl`. Follow this exact sequence:\n\n1. **Ask the user to confirm that the correct Chrome version** (e.g., \"Chrome Canary\" if the error mentions it) is currently running.\n2. **If the user confirms it is running, instruct them to enable remote debugging.** Be very specific about the URL and the action: \"Please open a new tab in Chrome, navigate to `chrome://inspect/#remote-debugging`, and make sure the 'Enable remote debugging' checkbox is checked.\"\n3. **Once the user confirms both steps, your only next action should be to call the `list_pages` tool.** This is the simplest and safest way to verify if the connection is now successful. Do not retry the original, more complex command yet.\n4. **If `list_pages` succeeds, the problem is resolved.** If it still fails with the same error, then you can proceed to the more advanced steps like suggesting `--browserUrl` or checking for sandboxing issues.\n\n#### Symptom: Server starts but creates a new empty profile\n\nIf the server starts successfully but `list_pages` returns an empty list or creates a new profile instead of connecting to the existing Chrome instance, check for typos in the arguments.\n\n- **Check for flag typos:** For example, `--autoBronnect` instead of `--autoConnect`.\n- **Verify the configuration:** Ensure the arguments match the expected flags exactly.\n\n#### Symptom: Missing Tools / Only 9 tools available\n\nIf the server starts successfully but only a limited subset of tools (like `list_pages`, `get_console_message`, `lighthouse_audit`, `take_memory_snapshot`) are available, this is likely because the MCP client is enforcing a **read-only mode**.\n\nAll tools in `chrome-devtools-mcp` are annotated with `readOnlyHint: true` (for safe, non-modifying tools) or `readOnlyHint: false` (for tools that modify browser state, like `emulate`, `click`, `navigate_page`). To access the full suite of tools, the user must disable read-only mode in their MCP client (e.g., by exiting \"Plan Mode\" in Gemini CLI or adjusting their client's tool safety settings).\n\n#### Other Common Errors\n\nIdentify other error messages from the failed tool call or the MCP initialization logs:\n\n- `Target closed`\n- \"Tool not found\" (check if they are using `--slim` which only enables navigation and screenshot tools).\n- `ProtocolError: Network.enable timed out` or `The socket connection was closed unexpectedly`\n- `Error [ERR_MODULE_NOT_FOUND]: Cannot find module`\n- Any sandboxing or host validation errors.\n\n### Step 3: Read Known Issues\n\nRead the contents of https://github.com/ChromeDevTools/chrome-devtools-mcp/blob/main/docs/troubleshooting.md to map the error to a known issue. Pay close attention to:\n\n- Sandboxing restrictions (macOS Seatbelt, Linux containers).\n- WSL requirements.\n- `--autoConnect` handshakes, timeouts, and requirements (requires **running** Chrome 144+).\n\n### Step 4: Formulate a Configuration\n\nBased on the exact error and the user's environment (OS, MCP client), formulate the correct MCP configuration snippet. Check if they need to:\n\n- Pass `--browser-url=http://127.0.0.1:9222` instead of `--autoConnect` (e.g. if they are in a sandboxed environment like Claude Desktop).\n- Enable remote debugging in Chrome (`chrome://inspect/#remote-debugging`) and accept the connection prompt. **Ask the user to verify this is enabled if using `--autoConnect`.**\n- Add `--logFile <absolute_path_to_log_file>` to capture debug logs for analysis.\n- Increase `startup_timeout_ms` (e.g. to 20000) if using Codex on Windows.\n\n_If you are unsure of the user's configuration, ask the user to provide their current MCP server JSON configuration._\n\n### Step 5: Run Diagnostic Commands\n\nIf the issue is still unclear, run diagnostic commands to test the server directly:\n\n- Run `npx chrome-devtools-mcp@latest --help` to verify the installation and Node.js environment.\n- If you need more information, run `DEBUG=* npx chrome-devtools-mcp@latest --logFile=/tmp/cdm-test.log` to capture verbose logs. Analyze the output for errors.\n\n### Step 6: Check GitHub for Existing Issues\n\nIf https://github.com/ChromeDevTools/chrome-devtools-mcp/blob/main/docs/troubleshooting.md does not cover the specific error, check if the `gh` (GitHub CLI) tool is available in the environment. If so, search the GitHub repository for similar issues:\n`gh issue list --repo ChromeDevTools/chrome-devtools-mcp --search \"<error snippet>\" --state all`\n\nAlternatively, you can recommend that the user checks https://github.com/ChromeDevTools/chrome-devtools-mcp/issues and https://github.com/ChromeDevTools/chrome-devtools-mcp/discussions for help.\n"
  },
  {
    "path": "src/DevToolsConnectionAdapter.ts",
    "content": "/**\n * @license\n * Copyright 2025 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport type * as puppeteer from './third_party/index.js';\nimport type {DevTools} from './third_party/index.js';\nimport {CDPSessionEvent} from './third_party/index.js';\n\n/**\n * This class makes a puppeteer connection look like DevTools CDPConnection.\n *\n * Since we connect \"root\" DevTools targets to specific pages, we scope everything to a puppeteer CDP session.\n *\n * We don't have to recursively listen for 'sessionattached' as the \"root\" CDP session sees all child session attached\n * events, regardless how deeply nested they are.\n */\nexport class PuppeteerDevToolsConnection\n  implements DevTools.CDPConnection.CDPConnection\n{\n  readonly #connection: puppeteer.Connection;\n  readonly #observers = new Set<DevTools.CDPConnection.CDPConnectionObserver>();\n  readonly #sessionEventHandlers = new Map<\n    string,\n    puppeteer.Handler<unknown>\n  >();\n\n  constructor(session: puppeteer.CDPSession) {\n    this.#connection = session.connection()!;\n\n    session.on(\n      CDPSessionEvent.SessionAttached,\n      this.#startForwardingCdpEvents.bind(this),\n    );\n    session.on(\n      CDPSessionEvent.SessionDetached,\n      this.#stopForwardingCdpEvents.bind(this),\n    );\n\n    this.#startForwardingCdpEvents(session);\n  }\n\n  send<T extends DevTools.CDPConnection.Command>(\n    method: T,\n    params: DevTools.CDPConnection.CommandParams<T>,\n    sessionId: string | undefined,\n  ): Promise<\n    | {result: DevTools.CDPConnection.CommandResult<T>}\n    | {error: DevTools.CDPConnection.CDPError}\n  > {\n    if (sessionId === undefined) {\n      throw new Error(\n        'Attempting to send on the root session. This must not happen',\n      );\n    }\n    const session = this.#connection.session(sessionId);\n    if (!session) {\n      throw new Error('Unknown session ' + sessionId);\n    }\n    // Rolled protocol version between puppeteer and DevTools doesn't necessarily match\n    /* eslint-disable @typescript-eslint/no-explicit-any */\n    return session\n      .send(method as any, params)\n      .then(result => ({result}))\n      .catch(error => ({error})) as any;\n    /* eslint-enable @typescript-eslint/no-explicit-any */\n  }\n\n  observe(observer: DevTools.CDPConnection.CDPConnectionObserver): void {\n    this.#observers.add(observer);\n  }\n\n  unobserve(observer: DevTools.CDPConnection.CDPConnectionObserver): void {\n    this.#observers.delete(observer);\n  }\n\n  #startForwardingCdpEvents(session: puppeteer.CDPSession): void {\n    const handler = this.#handleEvent.bind(\n      this,\n      session.id(),\n    ) as puppeteer.Handler<unknown>;\n    this.#sessionEventHandlers.set(session.id(), handler);\n    session.on('*', handler);\n  }\n\n  #stopForwardingCdpEvents(session: puppeteer.CDPSession): void {\n    const handler = this.#sessionEventHandlers.get(session.id());\n    if (handler) {\n      session.off('*', handler);\n    }\n  }\n\n  #handleEvent(\n    sessionId: string,\n    type: string | symbol | number,\n    event: any, // eslint-disable-line @typescript-eslint/no-explicit-any\n  ): void {\n    if (\n      typeof type === 'string' &&\n      type !== CDPSessionEvent.SessionAttached &&\n      type !== CDPSessionEvent.SessionDetached\n    ) {\n      this.#observers.forEach(observer =>\n        observer.onEvent({\n          method: type as DevTools.CDPConnection.Event,\n          sessionId,\n          params: event,\n        }),\n      );\n    }\n  }\n}\n"
  },
  {
    "path": "src/DevtoolsUtils.ts",
    "content": "/**\n * @license\n * Copyright 2025 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport {PuppeteerDevToolsConnection} from './DevToolsConnectionAdapter.js';\nimport {Mutex} from './Mutex.js';\nimport {DevTools} from './third_party/index.js';\nimport type {\n  Browser,\n  ConsoleMessage,\n  Page,\n  Protocol,\n  Target as PuppeteerTarget,\n} from './third_party/index.js';\n\nexport function extractUrlLikeFromDevToolsTitle(\n  title: string,\n): string | undefined {\n  const match = title.match(new RegExp(`DevTools - (.*)`));\n  return match?.[1] ?? undefined;\n}\n\nexport function urlsEqual(url1: string, url2: string): boolean {\n  const normalizedUrl1 = normalizeUrl(url1);\n  const normalizedUrl2 = normalizeUrl(url2);\n  return normalizedUrl1 === normalizedUrl2;\n}\n\n/**\n * For the sake of the MCP server, when we determine if two URLs are equal we\n * remove some parts:\n *\n * 1. We do not care about the protocol.\n * 2. We do not care about trailing slashes.\n * 3. We do not care about \"www\".\n * 4. We ignore the hash parts.\n *\n * For example, if the user types \"record a trace on foo.com\", we would want to\n * match a tab in the connected Chrome instance that is showing \"www.foo.com/\"\n */\nfunction normalizeUrl(url: string): string {\n  let result = url.trim();\n\n  // Remove protocols\n  if (result.startsWith('https://')) {\n    result = result.slice(8);\n  } else if (result.startsWith('http://')) {\n    result = result.slice(7);\n  }\n\n  // Remove 'www.'. This ensures that we find the right URL regardless of if the user adds `www` or not.\n  if (result.startsWith('www.')) {\n    result = result.slice(4);\n  }\n\n  // We use target URLs to locate DevTools but those often do\n  // no include hash.\n  const hashIdx = result.lastIndexOf('#');\n  if (hashIdx !== -1) {\n    result = result.slice(0, hashIdx);\n  }\n\n  // Remove trailing slash\n  if (result.endsWith('/')) {\n    result = result.slice(0, -1);\n  }\n\n  return result;\n}\n\n/**\n * A mock implementation of an issues manager that only implements the methods\n * that are actually used by the IssuesAggregator\n */\nexport class FakeIssuesManager extends DevTools.Common.ObjectWrapper\n  .ObjectWrapper<DevTools.IssuesManagerEventTypes> {\n  issues(): DevTools.Issue[] {\n    return [];\n  }\n}\n\n// DevTools CDP errors can get noisy.\nDevTools.ProtocolClient.InspectorBackend.test.suppressRequestErrors = true;\n\nDevTools.I18n.DevToolsLocale.DevToolsLocale.instance({\n  create: true,\n  data: {\n    navigatorLanguage: 'en-US',\n    settingLanguage: 'en-US',\n    lookupClosestDevToolsLocale: l => l,\n  },\n});\nDevTools.I18n.i18n.registerLocaleDataForTest('en-US', {});\n\nDevTools.Formatter.FormatterWorkerPool.FormatterWorkerPool.instance({\n  forceNew: true,\n  entrypointURL: import.meta\n    .resolve('./third_party/devtools-formatter-worker.js'),\n});\n\nexport interface TargetUniverse {\n  /** The DevTools target corresponding to the puppeteer Page */\n  target: DevTools.Target;\n  universe: DevTools.Foundation.Universe.Universe;\n}\nexport type TargetUniverseFactoryFn = (page: Page) => Promise<TargetUniverse>;\n\nexport class UniverseManager {\n  readonly #browser: Browser;\n  readonly #createUniverseFor: TargetUniverseFactoryFn;\n  readonly #universes = new WeakMap<Page, TargetUniverse>();\n\n  /** Guard access to #universes so we don't create unnecessary universes */\n  readonly #mutex = new Mutex();\n\n  constructor(\n    browser: Browser,\n    factory: TargetUniverseFactoryFn = DEFAULT_FACTORY,\n  ) {\n    this.#browser = browser;\n    this.#createUniverseFor = factory;\n  }\n\n  async init(pages: Page[]) {\n    try {\n      await this.#mutex.acquire();\n      const promises = [];\n      for (const page of pages) {\n        promises.push(\n          this.#createUniverseFor(page).then(targetUniverse =>\n            this.#universes.set(page, targetUniverse),\n          ),\n        );\n      }\n\n      this.#browser.on('targetcreated', this.#onTargetCreated);\n      this.#browser.on('targetdestroyed', this.#onTargetDestroyed);\n\n      await Promise.all(promises);\n    } finally {\n      this.#mutex.release();\n    }\n  }\n\n  get(page: Page): TargetUniverse | null {\n    return this.#universes.get(page) ?? null;\n  }\n\n  dispose() {\n    this.#browser.off('targetcreated', this.#onTargetCreated);\n    this.#browser.off('targetdestroyed', this.#onTargetDestroyed);\n  }\n\n  #onTargetCreated = async (target: PuppeteerTarget) => {\n    const page = await target.page();\n    try {\n      await this.#mutex.acquire();\n      if (!page || this.#universes.has(page)) {\n        return;\n      }\n\n      this.#universes.set(page, await this.#createUniverseFor(page));\n    } finally {\n      this.#mutex.release();\n    }\n  };\n\n  #onTargetDestroyed = async (target: PuppeteerTarget) => {\n    const page = await target.page();\n    try {\n      await this.#mutex.acquire();\n      if (!page || !this.#universes.has(page)) {\n        return;\n      }\n      this.#universes.delete(page);\n    } finally {\n      this.#mutex.release();\n    }\n  };\n}\n\nconst DEFAULT_FACTORY: TargetUniverseFactoryFn = async (page: Page) => {\n  const settingStorage = new DevTools.Common.Settings.SettingsStorage({});\n  const universe = new DevTools.Foundation.Universe.Universe({\n    settingsCreationOptions: {\n      syncedStorage: settingStorage,\n      globalStorage: settingStorage,\n      localStorage: settingStorage,\n      settingRegistrations:\n        DevTools.Common.SettingRegistration.getRegisteredSettings(),\n    },\n    overrideAutoStartModels: new Set([DevTools.DebuggerModel]),\n  });\n\n  const session = await page.createCDPSession();\n  const connection = new PuppeteerDevToolsConnection(session);\n\n  const targetManager = universe.context.get(DevTools.TargetManager);\n  targetManager.observeModels(DevTools.DebuggerModel, SKIP_ALL_PAUSES);\n\n  const target = targetManager.createTarget(\n    'main',\n    '',\n    'frame' as any, // eslint-disable-line @typescript-eslint/no-explicit-any\n    /* parentTarget */ null,\n    session.id(),\n    undefined,\n    connection,\n  );\n  return {target, universe};\n};\n\n// We don't want to pause any DevTools universe session ever on the MCP side.\n//\n// Note that calling `setSkipAllPauses` only affects the session on which it was\n// sent. This means DevTools can still pause, step and do whatever. We just won't\n// see the `Debugger.paused`/`Debugger.resumed` events on the MCP side.\nconst SKIP_ALL_PAUSES = {\n  modelAdded(model: DevTools.DebuggerModel): void {\n    void model.agent.invoke_setSkipAllPauses({skip: true});\n  },\n\n  modelRemoved(): void {\n    // Do nothing.\n  },\n};\n\n/**\n * Constructed from Runtime.ExceptionDetails of an uncaught error.\n *\n * TODO: Also construct from a RemoteObject of subtype 'error'.\n *\n * Consists of the message, a fully resolved stack trace and a fully resolved 'cause' chain.\n */\nexport class SymbolizedError {\n  readonly message: string;\n  readonly stackTrace?: DevTools.StackTrace.StackTrace.StackTrace;\n  readonly cause?: SymbolizedError;\n\n  private constructor(\n    message: string,\n    stackTrace?: DevTools.StackTrace.StackTrace.StackTrace,\n    cause?: SymbolizedError,\n  ) {\n    this.message = message;\n    this.stackTrace = stackTrace;\n    this.cause = cause;\n  }\n\n  static async fromDetails(opts: {\n    devTools?: TargetUniverse;\n    details: Protocol.Runtime.ExceptionDetails;\n    targetId: string;\n    includeStackAndCause?: boolean;\n    resolvedStackTraceForTesting?: DevTools.StackTrace.StackTrace.StackTrace;\n    resolvedCauseForTesting?: SymbolizedError;\n  }): Promise<SymbolizedError> {\n    const message = SymbolizedError.#getMessage(opts.details);\n    if (!opts.includeStackAndCause || !opts.devTools) {\n      return new SymbolizedError(\n        message,\n        opts.resolvedStackTraceForTesting,\n        opts.resolvedCauseForTesting,\n      );\n    }\n\n    let stackTrace: DevTools.StackTrace.StackTrace.StackTrace | undefined;\n    if (opts.resolvedStackTraceForTesting) {\n      stackTrace = opts.resolvedStackTraceForTesting;\n    } else if (opts.details.stackTrace) {\n      try {\n        stackTrace = await createStackTrace(\n          opts.devTools,\n          opts.details.stackTrace,\n          opts.targetId,\n        );\n      } catch {\n        // ignore\n      }\n    }\n\n    // TODO: Turn opts.details.exception into a JSHandle and retrieve the 'cause' property.\n    //       If its an Error, recursively create a SymbolizedError.\n    let cause: SymbolizedError | undefined;\n    if (opts.resolvedCauseForTesting) {\n      cause = opts.resolvedCauseForTesting;\n    } else if (opts.details.exception) {\n      try {\n        const causeRemoteObj = await SymbolizedError.#lookupCause(\n          opts.devTools,\n          opts.details.exception,\n          opts.targetId,\n        );\n        if (causeRemoteObj) {\n          cause = await SymbolizedError.fromError({\n            devTools: opts.devTools,\n            error: causeRemoteObj,\n            targetId: opts.targetId,\n          });\n        }\n      } catch {\n        // Ignore\n      }\n    }\n    return new SymbolizedError(message, stackTrace, cause);\n  }\n\n  static async fromError(opts: {\n    devTools?: TargetUniverse;\n    error: Protocol.Runtime.RemoteObject;\n    targetId: string;\n  }): Promise<SymbolizedError> {\n    const details = await SymbolizedError.#getExceptionDetails(\n      opts.devTools,\n      opts.error,\n      opts.targetId,\n    );\n    if (details) {\n      return SymbolizedError.fromDetails({\n        details,\n        devTools: opts.devTools,\n        targetId: opts.targetId,\n        includeStackAndCause: true,\n      });\n    }\n\n    return new SymbolizedError(\n      SymbolizedError.#getMessageFromException(opts.error),\n    );\n  }\n\n  static #getMessage(details: Protocol.Runtime.ExceptionDetails): string {\n    // For Runtime.exceptionThrown with a present exception object, `details.text` will be \"Uncaught\" and\n    // we have to manually parse out the error text from the exception description.\n    // In the case of Runtime.getExceptionDetails, `details.text` has the Error.message.\n    if (details.text === 'Uncaught' && details.exception) {\n      return (\n        'Uncaught ' +\n        SymbolizedError.#getMessageFromException(details.exception)\n      );\n    }\n    return details.text;\n  }\n\n  static #getMessageFromException(\n    error: Protocol.Runtime.RemoteObject,\n  ): string {\n    const messageWithRest = error.description?.split('\\n    at ', 2) ?? [];\n    return messageWithRest[0] ?? '';\n  }\n\n  static async #getExceptionDetails(\n    devTools: TargetUniverse | undefined,\n    error: Protocol.Runtime.RemoteObject,\n    targetId: string,\n  ): Promise<Protocol.Runtime.ExceptionDetails | null> {\n    if (!devTools || (error.type !== 'object' && error.subtype !== 'error')) {\n      return null;\n    }\n\n    const targetManager = devTools.universe.context.get(DevTools.TargetManager);\n    const target = targetId\n      ? targetManager.targetById(targetId) || devTools.target\n      : devTools.target;\n    const model = target.model(DevTools.RuntimeModel) as DevTools.RuntimeModel;\n    return (\n      (await model.getExceptionDetails(\n        error.objectId as DevTools.Protocol.Runtime.RemoteObjectId,\n      )) ?? null\n    );\n  }\n\n  static async #lookupCause(\n    devTools: TargetUniverse | undefined,\n    error: Protocol.Runtime.RemoteObject,\n    targetId: string,\n  ): Promise<Protocol.Runtime.RemoteObject | null> {\n    if (!devTools || (error.type !== 'object' && error.subtype !== 'error')) {\n      return null;\n    }\n\n    const targetManager = devTools.universe.context.get(DevTools.TargetManager);\n    const target = targetId\n      ? targetManager.targetById(targetId) || devTools.target\n      : devTools.target;\n\n    const properties = await target.runtimeAgent().invoke_getProperties({\n      objectId: error.objectId as DevTools.Protocol.Runtime.RemoteObjectId,\n    });\n    if (properties.getError()) {\n      return null;\n    }\n\n    return properties.result.find(prop => prop.name === 'cause')?.value ?? null;\n  }\n\n  static createForTesting(\n    message: string,\n    stackTrace?: DevTools.StackTrace.StackTrace.StackTrace,\n    cause?: SymbolizedError,\n  ) {\n    return new SymbolizedError(message, stackTrace, cause);\n  }\n}\n\nexport async function createStackTraceForConsoleMessage(\n  devTools: TargetUniverse,\n  consoleMessage: ConsoleMessage,\n): Promise<DevTools.StackTrace.StackTrace.StackTrace | undefined> {\n  const message = consoleMessage as ConsoleMessage & {\n    _rawStackTrace(): Protocol.Runtime.StackTrace | undefined;\n    _targetId(): string | undefined;\n  };\n  const rawStackTrace = message._rawStackTrace();\n  if (rawStackTrace) {\n    return createStackTrace(devTools, rawStackTrace, message._targetId());\n  }\n  return undefined;\n}\n\nexport async function createStackTrace(\n  devTools: TargetUniverse,\n  rawStackTrace: Protocol.Runtime.StackTrace,\n  targetId: string | undefined,\n): Promise<DevTools.StackTrace.StackTrace.StackTrace> {\n  const targetManager = devTools.universe.context.get(DevTools.TargetManager);\n  const target = targetId\n    ? targetManager.targetById(targetId) || devTools.target\n    : devTools.target;\n  const model = target.model(DevTools.DebuggerModel) as DevTools.DebuggerModel;\n\n  // DevTools doesn't wait for source maps to attach before building a stack trace, rather it'll send\n  // an update event once a source map was attached and the stack trace retranslated. This doesn't\n  // work in the MCP case, so we'll collect all script IDs upfront and wait for any pending source map\n  // loads before creating the stack trace. We might also have to wait for Debugger.ScriptParsed events if\n  // the stack trace is created particularly early.\n  const scriptIds = new Set<Protocol.Runtime.ScriptId>();\n  for (const frame of rawStackTrace.callFrames) {\n    scriptIds.add(frame.scriptId);\n  }\n  for (\n    let asyncStack = rawStackTrace.parent;\n    asyncStack;\n    asyncStack = asyncStack.parent\n  ) {\n    for (const frame of asyncStack.callFrames) {\n      scriptIds.add(frame.scriptId);\n    }\n  }\n\n  const signal = AbortSignal.timeout(1_000);\n  await Promise.all(\n    [...scriptIds].map(id =>\n      waitForScript(model, id, signal)\n        .then(script =>\n          model.sourceMapManager().sourceMapForClientPromise(script),\n        )\n        .catch(),\n    ),\n  );\n\n  const binding = devTools.universe.context.get(\n    DevTools.DebuggerWorkspaceBinding,\n  );\n  // DevTools uses branded types for ScriptId and others. Casting the puppeteer protocol type to the DevTools protocol type is safe.\n  return binding.createStackTraceFromProtocolRuntime(\n    rawStackTrace as Parameters<\n      DevTools.DebuggerWorkspaceBinding['createStackTraceFromProtocolRuntime']\n    >[0],\n    target,\n  );\n}\n\n// Waits indefinitely for the script so pair it with Promise.race.\nasync function waitForScript(\n  model: DevTools.DebuggerModel,\n  scriptId: Protocol.Runtime.ScriptId,\n  signal: AbortSignal,\n) {\n  while (true) {\n    if (signal.aborted) {\n      throw signal.reason;\n    }\n\n    const script = model.scriptForId(scriptId);\n    if (script) {\n      return script;\n    }\n\n    await new Promise((resolve, reject) => {\n      signal.addEventListener('abort', () => reject(signal.reason), {\n        once: true,\n      });\n      void model\n        .once(\n          'ParsedScriptSource' as Parameters<DevTools.DebuggerModel['once']>[0],\n        )\n        .then(resolve);\n    });\n  }\n}\n"
  },
  {
    "path": "src/McpContext.ts",
    "content": "/**\n * @license\n * Copyright 2025 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport fs from 'node:fs/promises';\nimport path from 'node:path';\n\nimport type {TargetUniverse} from './DevtoolsUtils.js';\nimport {\n  extractUrlLikeFromDevToolsTitle,\n  UniverseManager,\n  urlsEqual,\n} from './DevtoolsUtils.js';\nimport {McpPage} from './McpPage.js';\nimport type {ListenerMap, UncaughtError} from './PageCollector.js';\nimport {NetworkCollector, ConsoleCollector} from './PageCollector.js';\nimport type {DevTools} from './third_party/index.js';\nimport type {\n  Browser,\n  BrowserContext,\n  ConsoleMessage,\n  Debugger,\n  HTTPRequest,\n  Page,\n  ScreenRecorder,\n  SerializedAXNode,\n  Viewport,\n  Target,\n} from './third_party/index.js';\nimport {Locator} from './third_party/index.js';\nimport {PredefinedNetworkConditions} from './third_party/index.js';\nimport {listPages} from './tools/pages.js';\nimport {CLOSE_PAGE_ERROR} from './tools/ToolDefinition.js';\nimport type {Context, DevToolsData} from './tools/ToolDefinition.js';\nimport type {TraceResult} from './trace-processing/parse.js';\nimport type {\n  EmulationSettings,\n  GeolocationOptions,\n  TextSnapshot,\n  TextSnapshotNode,\n  ExtensionServiceWorker,\n} from './types.js';\nimport {\n  ExtensionRegistry,\n  type InstalledExtension,\n} from './utils/ExtensionRegistry.js';\nimport {saveTemporaryFile} from './utils/files.js';\nimport {WaitForHelper} from './WaitForHelper.js';\n\nexport type {\n  EmulationSettings,\n  GeolocationOptions,\n  TextSnapshot,\n  TextSnapshotNode,\n} from './types.js';\n\ninterface McpContextOptions {\n  // Whether the DevTools windows are exposed as pages for debugging of DevTools.\n  experimentalDevToolsDebugging: boolean;\n  // Whether all page-like targets are exposed as pages.\n  experimentalIncludeAllPages?: boolean;\n  // Whether CrUX data should be fetched.\n  performanceCrux: boolean;\n}\n\nconst DEFAULT_TIMEOUT = 5_000;\nconst NAVIGATION_TIMEOUT = 10_000;\n\nfunction getNetworkMultiplierFromString(condition: string | null): number {\n  const puppeteerCondition =\n    condition as keyof typeof PredefinedNetworkConditions;\n\n  switch (puppeteerCondition) {\n    case 'Fast 4G':\n      return 1;\n    case 'Slow 4G':\n      return 2.5;\n    case 'Fast 3G':\n      return 5;\n    case 'Slow 3G':\n      return 10;\n  }\n  return 1;\n}\n\nexport class McpContext implements Context {\n  browser: Browser;\n  logger: Debugger;\n\n  // Maps LLM-provided isolatedContext name → Puppeteer BrowserContext.\n  #isolatedContexts = new Map<string, BrowserContext>();\n  // Auto-generated name counter for when no name is provided.\n  #nextIsolatedContextId = 1;\n\n  #pages: Page[] = [];\n  #extensionServiceWorkers: ExtensionServiceWorker[] = [];\n\n  #mcpPages = new Map<Page, McpPage>();\n  #selectedPage?: McpPage;\n  #networkCollector: NetworkCollector;\n  #consoleCollector: ConsoleCollector;\n  #devtoolsUniverseManager: UniverseManager;\n  #extensionRegistry = new ExtensionRegistry();\n\n  #isRunningTrace = false;\n  #screenRecorderData: {recorder: ScreenRecorder; filePath: string} | null =\n    null;\n\n  #nextPageId = 1;\n  #extensionPages = new WeakMap<Target, Page>();\n\n  #extensionServiceWorkerMap = new WeakMap<Target, string>();\n  #nextExtensionServiceWorkerId = 1;\n\n  #nextSnapshotId = 1;\n  #traceResults: TraceResult[] = [];\n\n  #locatorClass: typeof Locator;\n  #options: McpContextOptions;\n\n  private constructor(\n    browser: Browser,\n    logger: Debugger,\n    options: McpContextOptions,\n    locatorClass: typeof Locator,\n  ) {\n    this.browser = browser;\n    this.logger = logger;\n    this.#locatorClass = locatorClass;\n    this.#options = options;\n\n    this.#networkCollector = new NetworkCollector(this.browser);\n\n    this.#consoleCollector = new ConsoleCollector(this.browser, collect => {\n      return {\n        console: event => {\n          collect(event);\n        },\n        uncaughtError: event => {\n          collect(event);\n        },\n        issue: event => {\n          collect(event);\n        },\n      } as ListenerMap;\n    });\n    this.#devtoolsUniverseManager = new UniverseManager(this.browser);\n  }\n\n  async #init() {\n    const pages = await this.createPagesSnapshot();\n    await this.createExtensionServiceWorkersSnapshot();\n    await this.#networkCollector.init(pages);\n    await this.#consoleCollector.init(pages);\n    await this.#devtoolsUniverseManager.init(pages);\n  }\n\n  dispose() {\n    this.#networkCollector.dispose();\n    this.#consoleCollector.dispose();\n    this.#devtoolsUniverseManager.dispose();\n    for (const mcpPage of this.#mcpPages.values()) {\n      mcpPage.dispose();\n    }\n    this.#mcpPages.clear();\n    // Isolated contexts are intentionally not closed here.\n    // Either the entire browser will be closed or we disconnect\n    // without destroying browser state.\n    this.#isolatedContexts.clear();\n  }\n\n  static async from(\n    browser: Browser,\n    logger: Debugger,\n    opts: McpContextOptions,\n    /* Let tests use unbundled Locator class to avoid overly strict checks within puppeteer that fail when mixing bundled and unbundled class instances */\n    locatorClass: typeof Locator = Locator,\n  ) {\n    const context = new McpContext(browser, logger, opts, locatorClass);\n    await context.#init();\n    return context;\n  }\n\n  resolveCdpRequestId(page: McpPage, cdpRequestId: string): number | undefined {\n    if (!cdpRequestId) {\n      this.logger('no network request');\n      return;\n    }\n    const request = this.#networkCollector.find(page.pptrPage, request => {\n      // @ts-expect-error id is internal.\n      return request.id === cdpRequestId;\n    });\n    if (!request) {\n      this.logger('no network request for ' + cdpRequestId);\n      return;\n    }\n    return this.#networkCollector.getIdForResource(request);\n  }\n\n  resolveCdpElementId(\n    page: McpPage,\n    cdpBackendNodeId: number,\n  ): string | undefined {\n    if (!cdpBackendNodeId) {\n      this.logger('no cdpBackendNodeId');\n      return;\n    }\n    const snapshot = page.textSnapshot;\n    if (!snapshot) {\n      this.logger('no text snapshot');\n      return;\n    }\n    // TODO: index by backendNodeId instead.\n    const queue = [snapshot.root];\n    while (queue.length) {\n      const current = queue.pop()!;\n      if (current.backendNodeId === cdpBackendNodeId) {\n        return current.id;\n      }\n      for (const child of current.children) {\n        queue.push(child);\n      }\n    }\n    return;\n  }\n\n  getNetworkRequests(\n    page: McpPage,\n    includePreservedRequests?: boolean,\n  ): HTTPRequest[] {\n    return this.#networkCollector.getData(\n      page.pptrPage,\n      includePreservedRequests,\n    );\n  }\n\n  getConsoleData(\n    page: McpPage,\n    includePreservedMessages?: boolean,\n  ): Array<ConsoleMessage | Error | DevTools.AggregatedIssue | UncaughtError> {\n    return this.#consoleCollector.getData(\n      page.pptrPage,\n      includePreservedMessages,\n    );\n  }\n\n  getDevToolsUniverse(page: McpPage): TargetUniverse | null {\n    return this.#devtoolsUniverseManager.get(page.pptrPage);\n  }\n\n  getConsoleMessageStableId(\n    message: ConsoleMessage | Error | DevTools.AggregatedIssue | UncaughtError,\n  ): number {\n    return this.#consoleCollector.getIdForResource(message);\n  }\n\n  getConsoleMessageById(\n    page: McpPage,\n    id: number,\n  ): ConsoleMessage | Error | DevTools.AggregatedIssue | UncaughtError {\n    return this.#consoleCollector.getById(page.pptrPage, id);\n  }\n\n  async newPage(\n    background?: boolean,\n    isolatedContextName?: string,\n  ): Promise<McpPage> {\n    let page: Page;\n    if (isolatedContextName !== undefined) {\n      let ctx = this.#isolatedContexts.get(isolatedContextName);\n      if (!ctx) {\n        ctx = await this.browser.createBrowserContext();\n        this.#isolatedContexts.set(isolatedContextName, ctx);\n      }\n      page = await ctx.newPage();\n    } else {\n      page = await this.browser.newPage({background});\n    }\n    await this.createPagesSnapshot();\n    this.selectPage(this.#getMcpPage(page));\n    this.#networkCollector.addPage(page);\n    this.#consoleCollector.addPage(page);\n    return this.#getMcpPage(page);\n  }\n  async closePage(pageId: number): Promise<void> {\n    if (this.#pages.length === 1) {\n      throw new Error(CLOSE_PAGE_ERROR);\n    }\n    const page = this.getPageById(pageId);\n    if (page) {\n      page.dispose();\n      this.#mcpPages.delete(page.pptrPage);\n    }\n    await page.pptrPage.close({runBeforeUnload: false});\n  }\n\n  getNetworkRequestById(page: McpPage, reqid: number): HTTPRequest {\n    return this.#networkCollector.getById(page.pptrPage, reqid);\n  }\n\n  async restoreEmulation(page: McpPage) {\n    const currentSetting = page.emulationSettings;\n    await this.emulate(currentSetting, page.pptrPage);\n  }\n\n  async emulate(\n    options: {\n      networkConditions?: string;\n      cpuThrottlingRate?: number;\n      geolocation?: GeolocationOptions;\n      userAgent?: string;\n      colorScheme?: 'dark' | 'light' | 'auto';\n      viewport?: Viewport;\n    },\n    targetPage?: Page,\n  ): Promise<void> {\n    const page = targetPage ?? this.getSelectedPptrPage();\n    const mcpPage = this.#getMcpPage(page);\n    const newSettings: EmulationSettings = {...mcpPage.emulationSettings};\n\n    if (!options.networkConditions) {\n      await page.emulateNetworkConditions(null);\n      delete newSettings.networkConditions;\n    } else if (options.networkConditions === 'Offline') {\n      await page.emulateNetworkConditions({\n        offline: true,\n        download: 0,\n        upload: 0,\n        latency: 0,\n      });\n      newSettings.networkConditions = 'Offline';\n    } else if (options.networkConditions in PredefinedNetworkConditions) {\n      const networkCondition =\n        PredefinedNetworkConditions[\n          options.networkConditions as keyof typeof PredefinedNetworkConditions\n        ];\n      await page.emulateNetworkConditions(networkCondition);\n      newSettings.networkConditions = options.networkConditions;\n    }\n\n    if (!options.cpuThrottlingRate) {\n      await page.emulateCPUThrottling(1);\n      delete newSettings.cpuThrottlingRate;\n    } else {\n      await page.emulateCPUThrottling(options.cpuThrottlingRate);\n      newSettings.cpuThrottlingRate = options.cpuThrottlingRate;\n    }\n\n    if (!options.geolocation) {\n      await page.setGeolocation({latitude: 0, longitude: 0});\n      delete newSettings.geolocation;\n    } else {\n      await page.setGeolocation(options.geolocation);\n      newSettings.geolocation = options.geolocation;\n    }\n\n    if (!options.userAgent) {\n      await page.setUserAgent({userAgent: undefined});\n      delete newSettings.userAgent;\n    } else {\n      await page.setUserAgent({userAgent: options.userAgent});\n      newSettings.userAgent = options.userAgent;\n    }\n\n    if (!options.colorScheme || options.colorScheme === 'auto') {\n      await page.emulateMediaFeatures([\n        {name: 'prefers-color-scheme', value: ''},\n      ]);\n      delete newSettings.colorScheme;\n    } else {\n      await page.emulateMediaFeatures([\n        {name: 'prefers-color-scheme', value: options.colorScheme},\n      ]);\n      newSettings.colorScheme = options.colorScheme;\n    }\n\n    if (!options.viewport) {\n      await page.setViewport(null);\n      delete newSettings.viewport;\n    } else {\n      const defaults = {\n        deviceScaleFactor: 1,\n        isMobile: false,\n        hasTouch: false,\n        isLandscape: false,\n      };\n      const viewport = {...defaults, ...options.viewport};\n      await page.setViewport(viewport);\n      newSettings.viewport = viewport;\n    }\n\n    mcpPage.emulationSettings = Object.keys(newSettings).length\n      ? newSettings\n      : {};\n\n    this.#updateSelectedPageTimeouts();\n  }\n\n  setIsRunningPerformanceTrace(x: boolean): void {\n    this.#isRunningTrace = x;\n  }\n\n  isRunningPerformanceTrace(): boolean {\n    return this.#isRunningTrace;\n  }\n\n  getScreenRecorder(): {recorder: ScreenRecorder; filePath: string} | null {\n    return this.#screenRecorderData;\n  }\n\n  setScreenRecorder(\n    data: {recorder: ScreenRecorder; filePath: string} | null,\n  ): void {\n    this.#screenRecorderData = data;\n  }\n\n  isCruxEnabled(): boolean {\n    return this.#options.performanceCrux;\n  }\n\n  getSelectedPptrPage(): Page {\n    const page = this.#selectedPage;\n    if (!page) {\n      throw new Error('No page selected');\n    }\n    if (page.pptrPage.isClosed()) {\n      throw new Error(\n        `The selected page has been closed. Call ${listPages().name} to see open pages.`,\n      );\n    }\n    return page.pptrPage;\n  }\n\n  getSelectedMcpPage(): McpPage {\n    const page = this.getSelectedPptrPage();\n    return this.#getMcpPage(page);\n  }\n\n  getPageById(pageId: number): McpPage {\n    const page = this.#mcpPages.values().find(mcpPage => mcpPage.id === pageId);\n    if (!page) {\n      throw new Error('No page found');\n    }\n    return page;\n  }\n\n  getPageId(page: Page): number | undefined {\n    return this.#mcpPages.get(page)?.id;\n  }\n\n  #getMcpPage(page: Page): McpPage {\n    const mcpPage = this.#mcpPages.get(page);\n    if (!mcpPage) {\n      throw new Error('No McpPage found for the given page.');\n    }\n    return mcpPage;\n  }\n\n  #getSelectedMcpPage(): McpPage {\n    return this.#getMcpPage(this.getSelectedPptrPage());\n  }\n\n  isPageSelected(page: Page): boolean {\n    return this.#selectedPage?.pptrPage === page;\n  }\n\n  selectPage(newPage: McpPage): void {\n    this.#selectedPage = newPage;\n    this.#updateSelectedPageTimeouts();\n  }\n\n  #updateSelectedPageTimeouts() {\n    const page = this.#getSelectedMcpPage();\n    // For waiters 5sec timeout should be sufficient.\n    // Increased in case we throttle the CPU\n    const cpuMultiplier = page.cpuThrottlingRate;\n    page.pptrPage.setDefaultTimeout(DEFAULT_TIMEOUT * cpuMultiplier);\n    // 10sec should be enough for the load event to be emitted during\n    // navigations.\n    // Increased in case we throttle the network requests\n    const networkMultiplier = getNetworkMultiplierFromString(\n      page.networkConditions,\n    );\n    page.pptrPage.setDefaultNavigationTimeout(\n      NAVIGATION_TIMEOUT * networkMultiplier,\n    );\n  }\n\n  // Linear scan over per-page snapshots. The page count is small (typically\n  // 2-10) so a reverse index isn't worthwhile given the uid-reuse lifecycle\n  // complexity it would introduce.\n  getAXNodeByUid(uid: string) {\n    for (const mcpPage of this.#mcpPages.values()) {\n      const node = mcpPage.textSnapshot?.idToNode.get(uid);\n      if (node) {\n        return node;\n      }\n    }\n    return undefined;\n  }\n\n  /**\n   * Creates a snapshot of the extension service workers.\n   */\n  async createExtensionServiceWorkersSnapshot(): Promise<\n    ExtensionServiceWorker[]\n  > {\n    const allTargets = await this.browser.targets();\n\n    const serviceWorkers = allTargets.filter(target => {\n      return (\n        target.type() === 'service_worker' &&\n        target.url().includes('chrome-extension://')\n      );\n    });\n\n    for (const serviceWorker of serviceWorkers) {\n      if (!this.#extensionServiceWorkerMap.has(serviceWorker)) {\n        this.#extensionServiceWorkerMap.set(\n          serviceWorker,\n          'sw-' + this.#nextExtensionServiceWorkerId++,\n        );\n      }\n    }\n\n    this.#extensionServiceWorkers = serviceWorkers.map(serviceWorker => {\n      return {\n        target: serviceWorker,\n        id: this.#extensionServiceWorkerMap.get(serviceWorker)!,\n        url: serviceWorker.url(),\n      };\n    });\n\n    return this.#extensionServiceWorkers;\n  }\n\n  async createPagesSnapshot(): Promise<Page[]> {\n    const {pages: allPages, isolatedContextNames} = await this.#getAllPages();\n\n    for (const page of allPages) {\n      let mcpPage = this.#mcpPages.get(page);\n      if (!mcpPage) {\n        mcpPage = new McpPage(page, this.#nextPageId++);\n        this.#mcpPages.set(page, mcpPage);\n        // We emulate a focused page for all pages to support multi-agent workflows.\n        void page.emulateFocusedPage(true).catch(error => {\n          this.logger('Error turning on focused page emulation', error);\n        });\n      }\n      mcpPage.isolatedContextName = isolatedContextNames.get(page);\n    }\n\n    // Prune orphaned #mcpPages entries (pages that no longer exist).\n    const currentPages = new Set(allPages);\n    for (const [page, mcpPage] of this.#mcpPages) {\n      if (!currentPages.has(page)) {\n        mcpPage.dispose();\n        this.#mcpPages.delete(page);\n      }\n    }\n\n    this.#pages = allPages.filter(page => {\n      return (\n        this.#options.experimentalDevToolsDebugging ||\n        !page.url().startsWith('devtools://')\n      );\n    });\n\n    if (\n      (!this.#selectedPage ||\n        this.#pages.indexOf(this.#selectedPage.pptrPage) === -1) &&\n      this.#pages[0]\n    ) {\n      this.selectPage(this.#getMcpPage(this.#pages[0]));\n    }\n\n    await this.detectOpenDevToolsWindows();\n\n    return this.#pages;\n  }\n\n  async #getAllPages(): Promise<{\n    pages: Page[];\n    isolatedContextNames: Map<Page, string>;\n  }> {\n    const defaultCtx = this.browser.defaultBrowserContext();\n    const allPages = await this.browser.pages(\n      this.#options.experimentalIncludeAllPages,\n    );\n\n    const allTargets = this.browser.targets();\n    const extensionTargets = allTargets.filter(target => {\n      return (\n        target.url().startsWith('chrome-extension://') &&\n        target.type() === 'page'\n      );\n    });\n\n    for (const target of extensionTargets) {\n      // Right now target.page() returns null for popup and side panel pages.\n      let page = await target.page();\n      if (!page) {\n        // We need to cache pages instances for targets because target.asPage()\n        // returns a new page instance every time.\n        page = this.#extensionPages.get(target) ?? null;\n        if (!page) {\n          try {\n            page = await target.asPage();\n            this.#extensionPages.set(target, page);\n          } catch (e) {\n            this.logger('Failed to get page for extension target', e);\n          }\n        }\n      }\n\n      if (page && !allPages.includes(page)) {\n        allPages.push(page);\n      }\n    }\n\n    // Build a reverse lookup from BrowserContext instance → name.\n    const contextToName = new Map<BrowserContext, string>();\n    for (const [name, ctx] of this.#isolatedContexts) {\n      contextToName.set(ctx, name);\n    }\n\n    // Auto-discover BrowserContexts not in our mapping (e.g., externally\n    // created incognito contexts) and assign generated names.\n    const knownContexts = new Set(this.#isolatedContexts.values());\n    for (const ctx of this.browser.browserContexts()) {\n      if (ctx !== defaultCtx && !ctx.closed && !knownContexts.has(ctx)) {\n        const name = `isolated-context-${this.#nextIsolatedContextId++}`;\n        this.#isolatedContexts.set(name, ctx);\n        contextToName.set(ctx, name);\n      }\n    }\n\n    // Map each page to its isolated context name (if any).\n    const isolatedContextNames = new Map<Page, string>();\n    for (const page of allPages) {\n      const ctx = page.browserContext();\n      const name = contextToName.get(ctx);\n      if (name) {\n        isolatedContextNames.set(page, name);\n      }\n    }\n\n    return {pages: allPages, isolatedContextNames};\n  }\n\n  async detectOpenDevToolsWindows() {\n    this.logger('Detecting open DevTools windows');\n    const {pages} = await this.#getAllPages();\n    // Clear all devToolsPage references before re-detecting.\n    for (const mcpPage of this.#mcpPages.values()) {\n      mcpPage.devToolsPage = undefined;\n    }\n    for (const devToolsPage of pages) {\n      if (devToolsPage.url().startsWith('devtools://')) {\n        try {\n          this.logger('Calling getTargetInfo for ' + devToolsPage.url());\n          const data = await devToolsPage\n            // @ts-expect-error no types for _client().\n            ._client()\n            .send('Target.getTargetInfo');\n          const devtoolsPageTitle = data.targetInfo.title;\n          const urlLike = extractUrlLikeFromDevToolsTitle(devtoolsPageTitle);\n          if (!urlLike) {\n            continue;\n          }\n          // TODO: lookup without a loop.\n          for (const page of this.#pages) {\n            if (urlsEqual(page.url(), urlLike)) {\n              const mcpPage = this.#mcpPages.get(page);\n              if (mcpPage) {\n                mcpPage.devToolsPage = devToolsPage;\n              }\n            }\n          }\n        } catch (error) {\n          this.logger('Issue occurred while trying to find DevTools', error);\n        }\n      }\n    }\n  }\n\n  getExtensionServiceWorkers(): ExtensionServiceWorker[] {\n    return this.#extensionServiceWorkers;\n  }\n\n  getExtensionServiceWorkerId(\n    extensionServiceWorker: ExtensionServiceWorker,\n  ): string | undefined {\n    return this.#extensionServiceWorkerMap.get(extensionServiceWorker.target);\n  }\n\n  getPages(): Page[] {\n    return this.#pages;\n  }\n\n  getIsolatedContextName(page: Page): string | undefined {\n    return this.#mcpPages.get(page)?.isolatedContextName;\n  }\n\n  getDevToolsPage(page: Page): Page | undefined {\n    return this.#mcpPages.get(page)?.devToolsPage;\n  }\n\n  async getDevToolsData(page: McpPage): Promise<DevToolsData> {\n    try {\n      this.logger('Getting DevTools UI data');\n      const devtoolsPage = this.getDevToolsPage(page.pptrPage);\n      if (!devtoolsPage) {\n        this.logger('No DevTools page detected');\n        return {};\n      }\n      const {cdpRequestId, cdpBackendNodeId} = await devtoolsPage.evaluate(\n        async () => {\n          // @ts-expect-error no types\n          const UI = await import('/bundled/ui/legacy/legacy.js');\n          // @ts-expect-error no types\n          const SDK = await import('/bundled/core/sdk/sdk.js');\n          const request = UI.Context.Context.instance().flavor(\n            SDK.NetworkRequest.NetworkRequest,\n          );\n          const node = UI.Context.Context.instance().flavor(\n            SDK.DOMModel.DOMNode,\n          );\n          return {\n            cdpRequestId: request?.requestId(),\n            cdpBackendNodeId: node?.backendNodeId(),\n          };\n        },\n      );\n      return {cdpBackendNodeId, cdpRequestId};\n    } catch (err) {\n      this.logger('error getting devtools data', err);\n    }\n    return {};\n  }\n\n  /**\n   * Creates a text snapshot of a page.\n   */\n  async createTextSnapshot(\n    page: McpPage,\n    verbose = false,\n    devtoolsData: DevToolsData | undefined = undefined,\n  ): Promise<void> {\n    const rootNode = await page.pptrPage.accessibility.snapshot({\n      includeIframes: true,\n      interestingOnly: !verbose,\n    });\n    if (!rootNode) {\n      return;\n    }\n\n    const {uniqueBackendNodeIdToMcpId} = page;\n\n    const snapshotId = this.#nextSnapshotId++;\n    // Iterate through the whole accessibility node tree and assign node ids that\n    // will be used for the tree serialization and mapping ids back to nodes.\n    let idCounter = 0;\n    const idToNode = new Map<string, TextSnapshotNode>();\n    const seenUniqueIds = new Set<string>();\n    const assignIds = (node: SerializedAXNode): TextSnapshotNode => {\n      let id = '';\n      // @ts-expect-error untyped loaderId & backendNodeId.\n      const uniqueBackendId = `${node.loaderId}_${node.backendNodeId}`;\n      if (uniqueBackendNodeIdToMcpId.has(uniqueBackendId)) {\n        // Re-use MCP exposed ID if the uniqueId is the same.\n        id = uniqueBackendNodeIdToMcpId.get(uniqueBackendId)!;\n      } else {\n        // Only generate a new ID if we have not seen the node before.\n        id = `${snapshotId}_${idCounter++}`;\n        uniqueBackendNodeIdToMcpId.set(uniqueBackendId, id);\n      }\n      seenUniqueIds.add(uniqueBackendId);\n\n      const nodeWithId: TextSnapshotNode = {\n        ...node,\n        id,\n        children: node.children\n          ? node.children.map(child => assignIds(child))\n          : [],\n      };\n\n      // The AXNode for an option doesn't contain its `value`.\n      // Therefore, set text content of the option as value.\n      if (node.role === 'option') {\n        const optionText = node.name;\n        if (optionText) {\n          nodeWithId.value = optionText.toString();\n        }\n      }\n\n      idToNode.set(nodeWithId.id, nodeWithId);\n      return nodeWithId;\n    };\n\n    const rootNodeWithId = assignIds(rootNode);\n    const snapshot: TextSnapshot = {\n      root: rootNodeWithId,\n      snapshotId: String(snapshotId),\n      idToNode,\n      hasSelectedElement: false,\n      verbose,\n    };\n    page.textSnapshot = snapshot;\n    const data = devtoolsData ?? (await this.getDevToolsData(page));\n    if (data?.cdpBackendNodeId) {\n      snapshot.hasSelectedElement = true;\n      snapshot.selectedElementUid = this.resolveCdpElementId(\n        page,\n        data?.cdpBackendNodeId,\n      );\n    }\n\n    // Clean up unique IDs that we did not see anymore.\n    for (const key of uniqueBackendNodeIdToMcpId.keys()) {\n      if (!seenUniqueIds.has(key)) {\n        uniqueBackendNodeIdToMcpId.delete(key);\n      }\n    }\n  }\n\n  async saveTemporaryFile(\n    data: Uint8Array<ArrayBufferLike>,\n    filename: string,\n  ): Promise<{filepath: string}> {\n    return await saveTemporaryFile(data, filename);\n  }\n  async saveFile(\n    data: Uint8Array<ArrayBufferLike>,\n    filename: string,\n  ): Promise<{filename: string}> {\n    try {\n      const filePath = path.resolve(filename);\n      await fs.mkdir(path.dirname(filePath), {recursive: true});\n      await fs.writeFile(filePath, data);\n      return {filename: filePath};\n    } catch (err) {\n      this.logger(err);\n      throw new Error('Could not save a file', {cause: err});\n    }\n  }\n\n  storeTraceRecording(result: TraceResult): void {\n    // Clear the trace results because we only consume the latest trace currently.\n    this.#traceResults = [];\n    this.#traceResults.push(result);\n  }\n\n  recordedTraces(): TraceResult[] {\n    return this.#traceResults;\n  }\n\n  getWaitForHelper(\n    page: Page,\n    cpuMultiplier: number,\n    networkMultiplier: number,\n  ) {\n    return new WaitForHelper(page, cpuMultiplier, networkMultiplier);\n  }\n\n  waitForEventsAfterAction(\n    action: () => Promise<unknown>,\n    options?: {timeout?: number},\n  ): Promise<void> {\n    const page = this.#getSelectedMcpPage();\n    const cpuMultiplier = page.cpuThrottlingRate;\n    const networkMultiplier = getNetworkMultiplierFromString(\n      page.networkConditions,\n    );\n    const waitForHelper = this.getWaitForHelper(\n      page.pptrPage,\n      cpuMultiplier,\n      networkMultiplier,\n    );\n    return waitForHelper.waitForEventsAfterAction(action, options);\n  }\n\n  getNetworkRequestStableId(request: HTTPRequest): number {\n    return this.#networkCollector.getIdForResource(request);\n  }\n\n  waitForTextOnPage(\n    text: string[],\n    timeout?: number,\n    targetPage?: Page,\n  ): Promise<Element> {\n    const page = targetPage ?? this.getSelectedPptrPage();\n    const frames = page.frames();\n\n    let locator = this.#locatorClass.race(\n      frames.flatMap(frame =>\n        text.flatMap(value => [\n          frame.locator(`aria/${value}`),\n          frame.locator(`text/${value}`),\n        ]),\n      ),\n    );\n\n    if (timeout) {\n      locator = locator.setTimeout(timeout);\n    }\n\n    return locator.wait();\n  }\n\n  /**\n   * We need to ignore favicon request as they make our test flaky\n   */\n  async setUpNetworkCollectorForTesting() {\n    this.#networkCollector = new NetworkCollector(this.browser, collect => {\n      return {\n        request: req => {\n          if (req.url().includes('favicon.ico')) {\n            return;\n          }\n          collect(req);\n        },\n      } as ListenerMap;\n    });\n    const {pages} = await this.#getAllPages();\n    await this.#networkCollector.init(pages);\n  }\n\n  async installExtension(extensionPath: string): Promise<string> {\n    const id = await this.browser.installExtension(extensionPath);\n    await this.#extensionRegistry.registerExtension(id, extensionPath);\n    return id;\n  }\n\n  async uninstallExtension(id: string): Promise<void> {\n    await this.browser.uninstallExtension(id);\n    this.#extensionRegistry.remove(id);\n  }\n\n  async triggerExtensionAction(id: string): Promise<void> {\n    const page = this.getSelectedPptrPage();\n    // @ts-expect-error internal puppeteer api is needed since we don't have a way to get\n    // a tab id at the moment\n    const theTarget = page._tabId;\n    const session = await this.browser.target().createCDPSession();\n\n    try {\n      await session.send('Extensions.triggerAction', {\n        id,\n        targetId: theTarget,\n      });\n    } finally {\n      await session.detach();\n    }\n  }\n\n  listExtensions(): InstalledExtension[] {\n    return this.#extensionRegistry.list();\n  }\n\n  getExtension(id: string): InstalledExtension | undefined {\n    return this.#extensionRegistry.getById(id);\n  }\n}\n"
  },
  {
    "path": "src/McpPage.ts",
    "content": "/**\n * @license\n * Copyright 2025 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport type {\n  Dialog,\n  ElementHandle,\n  Page,\n  Viewport,\n} from './third_party/index.js';\nimport {takeSnapshot} from './tools/snapshot.js';\nimport type {ContextPage} from './tools/ToolDefinition.js';\nimport type {\n  EmulationSettings,\n  GeolocationOptions,\n  TextSnapshot,\n  TextSnapshotNode,\n} from './types.js';\n\n/**\n * Per-page state wrapper. Consolidates dialog, snapshot, emulation,\n * and metadata that were previously scattered across Maps in McpContext.\n *\n * Internal class consumed only by McpContext. Fields are public for direct\n * read/write access. The dialog field is private because it requires an\n * event listener lifecycle managed by the constructor/dispose pair.\n */\nexport class McpPage implements ContextPage {\n  readonly pptrPage: Page;\n  readonly id: number;\n\n  // Snapshot\n  textSnapshot: TextSnapshot | null = null;\n  uniqueBackendNodeIdToMcpId = new Map<string, string>();\n\n  // Emulation\n  emulationSettings: EmulationSettings = {};\n\n  // Metadata\n  isolatedContextName?: string;\n  devToolsPage?: Page;\n\n  // Dialog\n  #dialog?: Dialog;\n  #dialogHandler: (dialog: Dialog) => void;\n\n  constructor(page: Page, id: number) {\n    this.pptrPage = page;\n    this.id = id;\n    this.#dialogHandler = (dialog: Dialog): void => {\n      this.#dialog = dialog;\n    };\n    page.on('dialog', this.#dialogHandler);\n  }\n\n  get dialog(): Dialog | undefined {\n    return this.#dialog;\n  }\n\n  getDialog(): Dialog | undefined {\n    return this.dialog;\n  }\n\n  clearDialog(): void {\n    this.#dialog = undefined;\n  }\n\n  get networkConditions(): string | null {\n    return this.emulationSettings.networkConditions ?? null;\n  }\n\n  get cpuThrottlingRate(): number {\n    return this.emulationSettings.cpuThrottlingRate ?? 1;\n  }\n\n  get geolocation(): GeolocationOptions | null {\n    return this.emulationSettings.geolocation ?? null;\n  }\n\n  get viewport(): Viewport | null {\n    return this.emulationSettings.viewport ?? null;\n  }\n\n  get userAgent(): string | null {\n    return this.emulationSettings.userAgent ?? null;\n  }\n\n  get colorScheme(): 'dark' | 'light' | null {\n    return this.emulationSettings.colorScheme ?? null;\n  }\n\n  dispose(): void {\n    this.pptrPage.off('dialog', this.#dialogHandler);\n  }\n\n  async getElementByUid(uid: string): Promise<ElementHandle<Element>> {\n    if (!this.textSnapshot) {\n      throw new Error(\n        `No snapshot found for page ${this.id ?? '?'}. Use ${takeSnapshot.name} to capture one.`,\n      );\n    }\n    const node = this.textSnapshot.idToNode.get(uid);\n    if (!node) {\n      throw new Error(`Element uid \"${uid}\" not found on page ${this.id}.`);\n    }\n    return this.#resolveElementHandle(node, uid);\n  }\n\n  async #resolveElementHandle(\n    node: TextSnapshotNode,\n    uid: string,\n  ): Promise<ElementHandle<Element>> {\n    const message = `Element with uid ${uid} no longer exists on the page.`;\n    try {\n      const handle = await node.elementHandle();\n      if (!handle) {\n        throw new Error(message);\n      }\n      return handle;\n    } catch (error) {\n      throw new Error(message, {\n        cause: error,\n      });\n    }\n  }\n\n  getAXNodeByUid(uid: string) {\n    return this.textSnapshot?.idToNode.get(uid);\n  }\n}\n"
  },
  {
    "path": "src/McpResponse.ts",
    "content": "/**\n * @license\n * Copyright 2025 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport type {ParsedArguments} from './bin/chrome-devtools-mcp-cli-options.js';\nimport {ConsoleFormatter} from './formatters/ConsoleFormatter.js';\nimport {IssueFormatter} from './formatters/IssueFormatter.js';\nimport {NetworkFormatter} from './formatters/NetworkFormatter.js';\nimport {SnapshotFormatter} from './formatters/SnapshotFormatter.js';\nimport type {McpContext} from './McpContext.js';\nimport type {McpPage} from './McpPage.js';\nimport {UncaughtError} from './PageCollector.js';\nimport {DevTools} from './third_party/index.js';\nimport type {\n  ConsoleMessage,\n  ImageContent,\n  Page,\n  ResourceType,\n  TextContent,\n} from './third_party/index.js';\nimport {handleDialog} from './tools/pages.js';\nimport type {\n  DevToolsData,\n  ImageContentData,\n  LighthouseData,\n  Response,\n  SnapshotParams,\n} from './tools/ToolDefinition.js';\nimport type {InsightName, TraceResult} from './trace-processing/parse.js';\nimport {getInsightOutput, getTraceSummary} from './trace-processing/parse.js';\nimport type {InstalledExtension} from './utils/ExtensionRegistry.js';\nimport {paginate} from './utils/pagination.js';\nimport type {PaginationOptions} from './utils/types.js';\n\ninterface TraceInsightData {\n  trace: TraceResult;\n  insightSetId: string;\n  insightName: InsightName;\n}\n\nexport class McpResponse implements Response {\n  #includePages = false;\n  #includeExtensionServiceWorkers = false;\n  #includeExtensionPages = false;\n  #snapshotParams?: SnapshotParams;\n  #attachedNetworkRequestId?: number;\n  #attachedNetworkRequestOptions?: {\n    requestFilePath?: string;\n    responseFilePath?: string;\n  };\n  #attachedConsoleMessageId?: number;\n  #attachedTraceSummary?: TraceResult;\n  #attachedTraceInsight?: TraceInsightData;\n  #attachedLighthouseResult?: LighthouseData;\n  #textResponseLines: string[] = [];\n  #images: ImageContentData[] = [];\n  #networkRequestsOptions?: {\n    include: boolean;\n    pagination?: PaginationOptions;\n    resourceTypes?: ResourceType[];\n    includePreservedRequests?: boolean;\n    networkRequestIdInDevToolsUI?: number;\n  };\n  #consoleDataOptions?: {\n    include: boolean;\n    pagination?: PaginationOptions;\n    types?: string[];\n    includePreservedMessages?: boolean;\n  };\n  #listExtensions?: boolean;\n  #devToolsData?: DevToolsData;\n  #tabId?: string;\n  #args: ParsedArguments;\n  #page?: McpPage;\n\n  constructor(args: ParsedArguments) {\n    this.#args = args;\n  }\n\n  setPage(page: McpPage): void {\n    this.#page = page;\n  }\n\n  attachDevToolsData(data: DevToolsData): void {\n    this.#devToolsData = data;\n  }\n\n  setTabId(tabId: string): void {\n    this.#tabId = tabId;\n  }\n\n  setIncludePages(value: boolean): void {\n    this.#includePages = value;\n\n    if (this.#args.categoryExtensions) {\n      this.#includeExtensionServiceWorkers = value;\n      this.#includeExtensionPages = value;\n    }\n  }\n\n  includeSnapshot(params?: SnapshotParams): void {\n    this.#snapshotParams = params ?? {\n      verbose: false,\n    };\n  }\n\n  setListExtensions(): void {\n    this.#listExtensions = true;\n  }\n\n  setIncludeNetworkRequests(\n    value: boolean,\n    options?: PaginationOptions & {\n      resourceTypes?: ResourceType[];\n      includePreservedRequests?: boolean;\n      networkRequestIdInDevToolsUI?: number;\n    },\n  ): void {\n    if (!value) {\n      this.#networkRequestsOptions = undefined;\n      return;\n    }\n\n    this.#networkRequestsOptions = {\n      include: value,\n      pagination:\n        options?.pageSize || options?.pageIdx\n          ? {\n              pageSize: options.pageSize,\n              pageIdx: options.pageIdx,\n            }\n          : undefined,\n      resourceTypes: options?.resourceTypes,\n      includePreservedRequests: options?.includePreservedRequests,\n      networkRequestIdInDevToolsUI: options?.networkRequestIdInDevToolsUI,\n    };\n  }\n\n  setIncludeConsoleData(\n    value: boolean,\n    options?: PaginationOptions & {\n      types?: string[];\n      includePreservedMessages?: boolean;\n    },\n  ): void {\n    if (!value) {\n      this.#consoleDataOptions = undefined;\n      return;\n    }\n\n    this.#consoleDataOptions = {\n      include: value,\n      pagination:\n        options?.pageSize || options?.pageIdx\n          ? {\n              pageSize: options.pageSize,\n              pageIdx: options.pageIdx,\n            }\n          : undefined,\n      types: options?.types,\n      includePreservedMessages: options?.includePreservedMessages,\n    };\n  }\n\n  attachNetworkRequest(\n    reqid: number,\n    options?: {requestFilePath?: string; responseFilePath?: string},\n  ): void {\n    this.#attachedNetworkRequestId = reqid;\n    this.#attachedNetworkRequestOptions = options;\n  }\n\n  attachConsoleMessage(msgid: number): void {\n    this.#attachedConsoleMessageId = msgid;\n  }\n\n  attachTraceSummary(result: TraceResult): void {\n    this.#attachedTraceSummary = result;\n  }\n\n  attachTraceInsight(\n    trace: TraceResult,\n    insightSetId: string,\n    insightName: InsightName,\n  ): void {\n    this.#attachedTraceInsight = {\n      trace,\n      insightSetId,\n      insightName,\n    };\n  }\n\n  attachLighthouseResult(result: LighthouseData): void {\n    this.#attachedLighthouseResult = result;\n  }\n\n  get includePages(): boolean {\n    return this.#includePages;\n  }\n\n  get attachedTraceSummary(): TraceResult | undefined {\n    return this.#attachedTraceSummary;\n  }\n\n  get attachedTracedInsight(): TraceInsightData | undefined {\n    return this.#attachedTraceInsight;\n  }\n\n  get attachedLighthouseResult(): LighthouseData | undefined {\n    return this.#attachedLighthouseResult;\n  }\n\n  get includeNetworkRequests(): boolean {\n    return this.#networkRequestsOptions?.include ?? false;\n  }\n\n  get includeConsoleData(): boolean {\n    return this.#consoleDataOptions?.include ?? false;\n  }\n  get attachedNetworkRequestId(): number | undefined {\n    return this.#attachedNetworkRequestId;\n  }\n  get networkRequestsPageIdx(): number | undefined {\n    return this.#networkRequestsOptions?.pagination?.pageIdx;\n  }\n  get consoleMessagesPageIdx(): number | undefined {\n    return this.#consoleDataOptions?.pagination?.pageIdx;\n  }\n  get consoleMessagesTypes(): string[] | undefined {\n    return this.#consoleDataOptions?.types;\n  }\n\n  appendResponseLine(value: string): void {\n    this.#textResponseLines.push(value);\n  }\n\n  attachImage(value: ImageContentData): void {\n    this.#images.push(value);\n  }\n\n  get responseLines(): readonly string[] {\n    return this.#textResponseLines;\n  }\n\n  get images(): ImageContentData[] {\n    return this.#images;\n  }\n\n  get snapshotParams(): SnapshotParams | undefined {\n    return this.#snapshotParams;\n  }\n\n  async handle(\n    toolName: string,\n    context: McpContext,\n  ): Promise<{\n    content: Array<TextContent | ImageContent>;\n    structuredContent: object;\n  }> {\n    if (this.#includePages) {\n      await context.createPagesSnapshot();\n    }\n\n    if (this.#includeExtensionServiceWorkers) {\n      await context.createExtensionServiceWorkersSnapshot();\n    }\n\n    let snapshot: SnapshotFormatter | string | undefined;\n    if (this.#snapshotParams) {\n      if (!this.#page) {\n        throw new Error('Response must have a page');\n      }\n      await context.createTextSnapshot(\n        this.#page,\n        this.#snapshotParams.verbose,\n        this.#devToolsData,\n      );\n      const textSnapshot = this.#page.textSnapshot;\n      if (textSnapshot) {\n        const formatter = new SnapshotFormatter(textSnapshot);\n        if (this.#snapshotParams.filePath) {\n          await context.saveFile(\n            new TextEncoder().encode(formatter.toString()),\n            this.#snapshotParams.filePath,\n          );\n          snapshot = this.#snapshotParams.filePath;\n        } else {\n          snapshot = formatter;\n        }\n      }\n    }\n\n    let detailedNetworkRequest: NetworkFormatter | undefined;\n    if (this.#attachedNetworkRequestId) {\n      if (!this.#page) {\n        throw new Error(`Response must have an McpPage`);\n      }\n      const request = context.getNetworkRequestById(\n        this.#page,\n        this.#attachedNetworkRequestId,\n      );\n      const formatter = await NetworkFormatter.from(request, {\n        requestId: this.#attachedNetworkRequestId,\n        requestIdResolver: req => context.getNetworkRequestStableId(req),\n        fetchData: true,\n        requestFilePath: this.#attachedNetworkRequestOptions?.requestFilePath,\n        responseFilePath: this.#attachedNetworkRequestOptions?.responseFilePath,\n        saveFile: (data, filename) => context.saveFile(data, filename),\n      });\n      detailedNetworkRequest = formatter;\n    }\n\n    let detailedConsoleMessage: ConsoleFormatter | IssueFormatter | undefined;\n\n    if (this.#attachedConsoleMessageId) {\n      if (!this.#page) {\n        throw new Error(`Response must have an McpPage`);\n      }\n\n      const message = context.getConsoleMessageById(\n        this.#page,\n        this.#attachedConsoleMessageId,\n      );\n      const consoleMessageStableId = this.#attachedConsoleMessageId;\n      if ('args' in message || message instanceof UncaughtError) {\n        const consoleMessage = message as ConsoleMessage | UncaughtError;\n        const devTools = context.getDevToolsUniverse(this.#page);\n        detailedConsoleMessage = await ConsoleFormatter.from(consoleMessage, {\n          id: consoleMessageStableId,\n          fetchDetailedData: true,\n          devTools: devTools ?? undefined,\n        });\n      } else if (message instanceof DevTools.AggregatedIssue) {\n        const formatter = new IssueFormatter(message, {\n          id: consoleMessageStableId,\n          requestIdResolver: context.resolveCdpRequestId.bind(\n            context,\n            this.#page,\n          ),\n          elementIdResolver: context.resolveCdpElementId.bind(\n            context,\n            this.#page,\n          ),\n        });\n        if (!formatter.isValid()) {\n          throw new Error(\n            \"Can't provide detals for the msgid \" + consoleMessageStableId,\n          );\n        }\n        detailedConsoleMessage = formatter;\n      }\n    }\n\n    let extensions: InstalledExtension[] | undefined;\n    if (this.#listExtensions) {\n      extensions = context.listExtensions();\n    }\n    let consoleMessages: Array<ConsoleFormatter | IssueFormatter> | undefined;\n    if (this.#consoleDataOptions?.include) {\n      if (!this.#page) {\n        throw new Error(`Response must have an McpPage`);\n      }\n      const page = this.#page;\n      let messages = context.getConsoleData(\n        this.#page,\n        this.#consoleDataOptions.includePreservedMessages,\n      );\n\n      if (this.#consoleDataOptions.types?.length) {\n        const normalizedTypes = new Set(this.#consoleDataOptions.types);\n        messages = messages.filter(message => {\n          if ('type' in message) {\n            return normalizedTypes.has(message.type());\n          }\n          if (message instanceof DevTools.AggregatedIssue) {\n            return normalizedTypes.has('issue');\n          }\n          return normalizedTypes.has('error');\n        });\n      }\n\n      consoleMessages = (\n        await Promise.all(\n          messages.map(\n            async (item): Promise<ConsoleFormatter | IssueFormatter | null> => {\n              const consoleMessageStableId =\n                context.getConsoleMessageStableId(item);\n              if ('args' in item || item instanceof UncaughtError) {\n                const consoleMessage = item as ConsoleMessage | UncaughtError;\n                const devTools = context.getDevToolsUniverse(page);\n                return await ConsoleFormatter.from(consoleMessage, {\n                  id: consoleMessageStableId,\n                  fetchDetailedData: false,\n                  devTools: devTools ?? undefined,\n                });\n              }\n              if (item instanceof DevTools.AggregatedIssue) {\n                const formatter = new IssueFormatter(item, {\n                  id: consoleMessageStableId,\n                });\n                if (!formatter.isValid()) {\n                  return null;\n                }\n                return formatter;\n              }\n              return null;\n            },\n          ),\n        )\n      ).filter(item => item !== null);\n    }\n\n    let networkRequests: NetworkFormatter[] | undefined;\n    if (this.#networkRequestsOptions?.include) {\n      if (!this.#page) {\n        throw new Error(`Response must have an McpPage`);\n      }\n      let requests = context.getNetworkRequests(\n        this.#page,\n        this.#networkRequestsOptions?.includePreservedRequests,\n      );\n\n      // Apply resource type filtering if specified\n      if (this.#networkRequestsOptions.resourceTypes?.length) {\n        const normalizedTypes = new Set(\n          this.#networkRequestsOptions.resourceTypes,\n        );\n        requests = requests.filter(request => {\n          const type = request.resourceType();\n          return normalizedTypes.has(type);\n        });\n      }\n\n      if (requests.length) {\n        networkRequests = await Promise.all(\n          requests.map(request =>\n            NetworkFormatter.from(request, {\n              requestId: context.getNetworkRequestStableId(request),\n              selectedInDevToolsUI:\n                context.getNetworkRequestStableId(request) ===\n                this.#networkRequestsOptions?.networkRequestIdInDevToolsUI,\n              fetchData: false,\n              saveFile: (data, filename) => context.saveFile(data, filename),\n            }),\n          ),\n        );\n      }\n    }\n\n    return this.format(toolName, context, {\n      detailedConsoleMessage,\n      consoleMessages,\n      snapshot,\n      detailedNetworkRequest,\n      networkRequests,\n      traceInsight: this.#attachedTraceInsight,\n      traceSummary: this.#attachedTraceSummary,\n      extensions,\n      lighthouseResult: this.#attachedLighthouseResult,\n    });\n  }\n\n  format(\n    toolName: string,\n    context: McpContext,\n    data: {\n      detailedConsoleMessage: ConsoleFormatter | IssueFormatter | undefined;\n      consoleMessages: Array<ConsoleFormatter | IssueFormatter> | undefined;\n      snapshot: SnapshotFormatter | string | undefined;\n      detailedNetworkRequest?: NetworkFormatter;\n      networkRequests?: NetworkFormatter[];\n      traceSummary?: TraceResult;\n      traceInsight?: TraceInsightData;\n      extensions?: InstalledExtension[];\n      lighthouseResult?: LighthouseData;\n    },\n  ): {content: Array<TextContent | ImageContent>; structuredContent: object} {\n    const structuredContent: {\n      snapshot?: object;\n      snapshotFilePath?: string;\n      tabId?: string;\n      networkRequest?: object;\n      networkRequests?: object[];\n      consoleMessage?: object;\n      consoleMessages?: object[];\n      traceSummary?: string;\n      traceInsights?: Array<{insightName: string; insightKey: string}>;\n      lighthouseResult?: object;\n      extensions?: object[];\n      message?: string;\n      networkConditions?: string;\n      navigationTimeout?: number;\n      viewport?: object;\n      userAgent?: string;\n      cpuThrottlingRate?: number;\n      colorScheme?: string;\n      dialog?: {\n        type: string;\n        message: string;\n        defaultValue?: string;\n      };\n      pages?: object[];\n      pagination?: object;\n      extensionServiceWorkers?: object[];\n      extensionPages?: object[];\n    } = {};\n\n    const response = [];\n    if (this.#textResponseLines.length) {\n      structuredContent.message = this.#textResponseLines.join('\\n');\n      response.push(...this.#textResponseLines);\n    }\n\n    const networkConditions = this.#page?.networkConditions;\n    if (networkConditions) {\n      const timeout = this.#page!.pptrPage.getDefaultNavigationTimeout();\n      response.push(`Emulating network conditions: ${networkConditions}`);\n      response.push(`Default navigation timeout set to ${timeout} ms`);\n      structuredContent.networkConditions = networkConditions;\n      structuredContent.navigationTimeout = timeout;\n    }\n\n    const viewport = this.#page?.viewport;\n    if (viewport) {\n      response.push(`Emulating viewport: ${JSON.stringify(viewport)}`);\n      structuredContent.viewport = viewport;\n    }\n\n    const userAgent = this.#page?.userAgent;\n    if (userAgent) {\n      response.push(`Emulating user agent: ${userAgent}`);\n      structuredContent.userAgent = userAgent;\n    }\n\n    const cpuThrottlingRate = this.#page?.cpuThrottlingRate ?? 1;\n    if (cpuThrottlingRate > 1) {\n      response.push(`Emulating CPU throttling: ${cpuThrottlingRate}x slowdown`);\n      structuredContent.cpuThrottlingRate = cpuThrottlingRate;\n    }\n\n    const colorScheme = this.#page?.colorScheme;\n    if (colorScheme) {\n      response.push(`Emulating color scheme: ${colorScheme}`);\n      structuredContent.colorScheme = colorScheme;\n    }\n\n    const dialog = this.#page?.getDialog();\n    if (dialog) {\n      const defaultValueIfNeeded =\n        dialog.type() === 'prompt'\n          ? ` (default value: \"${dialog.defaultValue()}\")`\n          : '';\n      response.push(`# Open dialog\n${dialog.type()}: ${dialog.message()}${defaultValueIfNeeded}.\nCall ${handleDialog.name} to handle it before continuing.`);\n      structuredContent.dialog = {\n        type: dialog.type(),\n        message: dialog.message(),\n        defaultValue: dialog.defaultValue(),\n      };\n    }\n\n    if (this.#includePages) {\n      const allPages = context.getPages();\n\n      const {regularPages, extensionPages} = allPages.reduce(\n        (acc: {regularPages: Page[]; extensionPages: Page[]}, page: Page) => {\n          if (page.url().startsWith('chrome-extension://')) {\n            acc.extensionPages.push(page);\n          } else {\n            acc.regularPages.push(page);\n          }\n          return acc;\n        },\n        {regularPages: [], extensionPages: []},\n      );\n\n      if (regularPages.length) {\n        const parts = [`## Pages`];\n        const structuredPages = [];\n        for (const page of regularPages) {\n          const isolatedContextName = context.getIsolatedContextName(page);\n          const contextLabel = isolatedContextName\n            ? ` isolatedContext=${isolatedContextName}`\n            : '';\n          parts.push(\n            `${context.getPageId(page)}: ${page.url()}${context.isPageSelected(page) ? ' [selected]' : ''}${contextLabel}`,\n          );\n          structuredPages.push(createStructuredPage(page, context));\n        }\n        response.push(...parts);\n        structuredContent.pages = structuredPages;\n      }\n\n      if (this.#includeExtensionPages) {\n        if (extensionPages.length) {\n          response.push(`## Extension Pages`);\n          const structuredExtensionPages = [];\n          for (const page of extensionPages) {\n            const isolatedContextName = context.getIsolatedContextName(page);\n            const contextLabel = isolatedContextName\n              ? ` isolatedContext=${isolatedContextName}`\n              : '';\n            response.push(\n              `${context.getPageId(page)}: ${page.url()}${context.isPageSelected(page) ? ' [selected]' : ''}${contextLabel}`,\n            );\n            structuredExtensionPages.push(createStructuredPage(page, context));\n          }\n          structuredContent.extensionPages = structuredExtensionPages;\n        }\n      }\n    }\n\n    if (this.#includeExtensionServiceWorkers) {\n      if (context.getExtensionServiceWorkers().length) {\n        response.push(`## Extension Service Workers`);\n      }\n\n      for (const extensionServiceWorker of context.getExtensionServiceWorkers()) {\n        response.push(\n          `${extensionServiceWorker.id}: ${extensionServiceWorker.url}`,\n        );\n      }\n      structuredContent.extensionServiceWorkers = context\n        .getExtensionServiceWorkers()\n        .map(extensionServiceWorker => {\n          return {\n            id: extensionServiceWorker.id,\n            url: extensionServiceWorker.url,\n          };\n        });\n    }\n\n    if (this.#tabId) {\n      structuredContent.tabId = this.#tabId;\n    }\n\n    if (data.traceSummary) {\n      const summary = getTraceSummary(data.traceSummary);\n      response.push(summary);\n      structuredContent.traceSummary = summary;\n      structuredContent.traceInsights = [];\n      for (const insightSet of data.traceSummary.insights?.values() ?? []) {\n        for (const [insightName, model] of Object.entries(insightSet.model)) {\n          structuredContent.traceInsights.push({\n            insightName,\n            insightKey: model.insightKey,\n          });\n        }\n      }\n    }\n\n    if (data.traceInsight) {\n      const insightOutput = getInsightOutput(\n        data.traceInsight.trace,\n        data.traceInsight.insightSetId,\n        data.traceInsight.insightName,\n      );\n      if ('error' in insightOutput) {\n        response.push(insightOutput.error);\n      } else {\n        response.push(insightOutput.output);\n      }\n    }\n\n    if (data.lighthouseResult) {\n      structuredContent.lighthouseResult = data.lighthouseResult;\n      const {summary, reports} = data.lighthouseResult;\n      response.push('## Lighthouse Audit Results');\n      response.push(`Mode: ${summary.mode}`);\n      response.push(`Device: ${summary.device}`);\n      response.push(`URL: ${summary.url}`);\n      response.push('### Category Scores');\n      for (const score of summary.scores) {\n        response.push(\n          `- ${score.title}: ${(score.score ?? 0) * 100} (${score.id})`,\n        );\n      }\n      response.push('### Audit Summary');\n      response.push(`Passed: ${summary.audits.passed}`);\n      response.push(`Failed: ${summary.audits.failed}`);\n      response.push(`Total Timing: ${summary.timing.total}ms`);\n      response.push('### Reports');\n      for (const report of reports) {\n        response.push(`- ${report}`);\n      }\n    }\n\n    if (data.snapshot) {\n      if (typeof data.snapshot === 'string') {\n        response.push(`Saved snapshot to ${data.snapshot}.`);\n        structuredContent.snapshotFilePath = data.snapshot;\n      } else {\n        response.push('## Latest page snapshot');\n        response.push(data.snapshot.toString());\n        structuredContent.snapshot = data.snapshot.toJSON();\n      }\n    }\n\n    if (data.detailedNetworkRequest) {\n      response.push(data.detailedNetworkRequest.toStringDetailed());\n      structuredContent.networkRequest =\n        data.detailedNetworkRequest.toJSONDetailed();\n    }\n\n    if (data.detailedConsoleMessage) {\n      response.push(data.detailedConsoleMessage.toStringDetailed());\n      structuredContent.consoleMessage =\n        data.detailedConsoleMessage.toJSONDetailed();\n    }\n\n    if (data.extensions) {\n      structuredContent.extensions = data.extensions;\n      response.push('## Extensions');\n      if (data.extensions.length === 0) {\n        response.push('No extensions installed.');\n      } else {\n        const extensionsMessage = data.extensions\n          .map(extension => {\n            return `id=${extension.id} \"${extension.name}\" v${extension.version} ${extension.isEnabled ? 'Enabled' : 'Disabled'}`;\n          })\n          .join('\\n');\n        response.push(extensionsMessage);\n      }\n    }\n\n    if (this.#networkRequestsOptions?.include && data.networkRequests) {\n      const requests = data.networkRequests;\n\n      response.push('## Network requests');\n      if (requests.length) {\n        const paginationData = this.#dataWithPagination(\n          requests,\n          this.#networkRequestsOptions.pagination,\n        );\n        structuredContent.pagination = paginationData.pagination;\n        response.push(...paginationData.info);\n        if (data.networkRequests) {\n          structuredContent.networkRequests = [];\n          for (const formatter of paginationData.items) {\n            response.push(formatter.toString());\n            structuredContent.networkRequests.push(formatter.toJSON());\n          }\n        }\n      } else {\n        response.push('No requests found.');\n      }\n    }\n\n    if (this.#consoleDataOptions?.include) {\n      const messages = data.consoleMessages ?? [];\n\n      response.push('## Console messages');\n      if (messages.length) {\n        const paginationData = this.#dataWithPagination(\n          messages,\n          this.#consoleDataOptions.pagination,\n        );\n        structuredContent.pagination = paginationData.pagination;\n        response.push(...paginationData.info);\n        response.push(\n          ...paginationData.items.map(message => message.toString()),\n        );\n        structuredContent.consoleMessages = paginationData.items.map(message =>\n          message.toJSON(),\n        );\n      } else {\n        response.push('<no console messages found>');\n      }\n    }\n\n    const text: TextContent = {\n      type: 'text',\n      text: response.join('\\n'),\n    };\n    const images: ImageContent[] = this.#images.map(imageData => {\n      return {\n        type: 'image',\n        ...imageData,\n      } as const;\n    });\n\n    return {\n      content: [text, ...images],\n      structuredContent,\n    };\n  }\n\n  #dataWithPagination<T>(data: T[], pagination?: PaginationOptions) {\n    const response = [];\n    const paginationResult = paginate<T>(data, pagination);\n    if (paginationResult.invalidPage) {\n      response.push('Invalid page number provided. Showing first page.');\n    }\n\n    const {startIndex, endIndex, currentPage, totalPages} = paginationResult;\n    response.push(\n      `Showing ${startIndex + 1}-${endIndex} of ${data.length} (Page ${currentPage + 1} of ${totalPages}).`,\n    );\n    if (pagination) {\n      if (paginationResult.hasNextPage) {\n        response.push(`Next page: ${currentPage + 1}`);\n      }\n      if (paginationResult.hasPreviousPage) {\n        response.push(`Previous page: ${currentPage - 1}`);\n      }\n    }\n\n    return {\n      info: response,\n      items: paginationResult.items,\n      pagination: {\n        currentPage: paginationResult.currentPage,\n        totalPages: paginationResult.totalPages,\n        hasNextPage: paginationResult.hasNextPage,\n        hasPreviousPage: paginationResult.hasPreviousPage,\n        startIndex: paginationResult.startIndex,\n        endIndex: paginationResult.endIndex,\n        invalidPage: paginationResult.invalidPage,\n      },\n    };\n  }\n\n  resetResponseLineForTesting() {\n    this.#textResponseLines = [];\n  }\n}\nfunction createStructuredPage(page: Page, context: McpContext) {\n  const isolatedContextName = context.getIsolatedContextName(page);\n  const entry: {\n    id: number | undefined;\n    url: string;\n    selected: boolean;\n    isolatedContext?: string;\n  } = {\n    id: context.getPageId(page),\n    url: page.url(),\n    selected: context.isPageSelected(page),\n  };\n  if (isolatedContextName) {\n    entry.isolatedContext = isolatedContextName;\n  }\n  return entry;\n}\n"
  },
  {
    "path": "src/Mutex.ts",
    "content": "/**\n * @license\n * Copyright 2025 Google Inc.\n * SPDX-License-Identifier: Apache-2.0\n */\n\nexport class Mutex {\n  static Guard = class Guard {\n    #mutex: Mutex;\n    constructor(mutex: Mutex) {\n      this.#mutex = mutex;\n    }\n    dispose(): void {\n      return this.#mutex.release();\n    }\n  };\n\n  #locked = false;\n  #acquirers: Array<() => void> = [];\n\n  // This is FIFO.\n  async acquire(): Promise<InstanceType<typeof Mutex.Guard>> {\n    if (!this.#locked) {\n      this.#locked = true;\n      return new Mutex.Guard(this);\n    }\n    const {resolve, promise} = Promise.withResolvers<void>();\n    this.#acquirers.push(resolve);\n    await promise;\n    return new Mutex.Guard(this);\n  }\n\n  release(): void {\n    const resolve = this.#acquirers.shift();\n    if (!resolve) {\n      this.#locked = false;\n      return;\n    }\n    resolve();\n  }\n}\n"
  },
  {
    "path": "src/PageCollector.ts",
    "content": "/**\n * @license\n * Copyright 2025 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport {FakeIssuesManager} from './DevtoolsUtils.js';\nimport {logger} from './logger.js';\nimport type {\n  Target,\n  CDPSession,\n  ConsoleMessage,\n  Protocol,\n} from './third_party/index.js';\nimport {DevTools} from './third_party/index.js';\nimport {\n  type Browser,\n  type Frame,\n  type Handler,\n  type HTTPRequest,\n  type Page,\n  type PageEvents as PuppeteerPageEvents,\n} from './third_party/index.js';\n\nexport class UncaughtError {\n  readonly details: Protocol.Runtime.ExceptionDetails;\n  readonly targetId: string;\n\n  constructor(details: Protocol.Runtime.ExceptionDetails, targetId: string) {\n    this.details = details;\n    this.targetId = targetId;\n  }\n}\n\ninterface PageEvents extends PuppeteerPageEvents {\n  issue: DevTools.AggregatedIssue;\n  uncaughtError: UncaughtError;\n}\n\nexport type ListenerMap<EventMap extends PageEvents = PageEvents> = {\n  [K in keyof EventMap]?: (event: EventMap[K]) => void;\n};\n\nfunction createIdGenerator() {\n  let i = 1;\n  return () => {\n    if (i === Number.MAX_SAFE_INTEGER) {\n      i = 0;\n    }\n    return i++;\n  };\n}\n\nexport const stableIdSymbol = Symbol('stableIdSymbol');\ntype WithSymbolId<T> = T & {\n  [stableIdSymbol]?: number;\n};\n\nexport class PageCollector<T> {\n  #browser: Browser;\n  #listenersInitializer: (\n    collector: (item: T) => void,\n  ) => ListenerMap<PageEvents>;\n  #listeners = new WeakMap<Page, ListenerMap>();\n  #maxNavigationSaved = 3;\n\n  /**\n   * This maps a Page to a list of navigations with a sub-list\n   * of all collected resources.\n   * The newer navigations come first.\n   */\n  protected storage = new WeakMap<Page, Array<Array<WithSymbolId<T>>>>();\n\n  constructor(\n    browser: Browser,\n    listeners: (collector: (item: T) => void) => ListenerMap<PageEvents>,\n  ) {\n    this.#browser = browser;\n    this.#listenersInitializer = listeners;\n  }\n\n  async init(pages: Page[]) {\n    for (const page of pages) {\n      this.addPage(page);\n    }\n\n    this.#browser.on('targetcreated', this.#onTargetCreated);\n    this.#browser.on('targetdestroyed', this.#onTargetDestroyed);\n  }\n\n  dispose() {\n    this.#browser.off('targetcreated', this.#onTargetCreated);\n    this.#browser.off('targetdestroyed', this.#onTargetDestroyed);\n  }\n\n  #onTargetCreated = async (target: Target) => {\n    try {\n      const page = await target.page();\n      if (!page) {\n        return;\n      }\n      this.addPage(page);\n    } catch (err) {\n      logger('Error getting a page for a target onTargetCreated', err);\n    }\n  };\n\n  #onTargetDestroyed = async (target: Target) => {\n    try {\n      const page = await target.page();\n      if (!page) {\n        return;\n      }\n      this.cleanupPageDestroyed(page);\n    } catch (err) {\n      logger('Error getting a page for a target onTargetDestroyed', err);\n    }\n  };\n\n  public addPage(page: Page) {\n    this.#initializePage(page);\n  }\n\n  #initializePage(page: Page) {\n    if (this.storage.has(page)) {\n      return;\n    }\n    const idGenerator = createIdGenerator();\n    const storedLists: Array<Array<WithSymbolId<T>>> = [[]];\n    this.storage.set(page, storedLists);\n\n    const listeners = this.#listenersInitializer(value => {\n      const withId = value as WithSymbolId<T>;\n      withId[stableIdSymbol] = idGenerator();\n\n      const navigations = this.storage.get(page) ?? [[]];\n      navigations[0].push(withId);\n    });\n\n    listeners['framenavigated'] = (frame: Frame) => {\n      // Only split the storage on main frame navigation\n      if (frame !== page.mainFrame()) {\n        return;\n      }\n      this.splitAfterNavigation(page);\n    };\n\n    for (const [name, listener] of Object.entries(listeners)) {\n      page.on(name, listener as Handler<unknown>);\n    }\n\n    this.#listeners.set(page, listeners);\n  }\n\n  protected splitAfterNavigation(page: Page) {\n    const navigations = this.storage.get(page);\n    if (!navigations) {\n      return;\n    }\n    // Add the latest navigation first\n    navigations.unshift([]);\n    navigations.splice(this.#maxNavigationSaved);\n  }\n\n  protected cleanupPageDestroyed(page: Page) {\n    const listeners = this.#listeners.get(page);\n    if (listeners) {\n      for (const [name, listener] of Object.entries(listeners)) {\n        page.off(name, listener as Handler<unknown>);\n      }\n    }\n    this.storage.delete(page);\n  }\n\n  getData(page: Page, includePreservedData?: boolean): T[] {\n    const navigations = this.storage.get(page);\n    if (!navigations) {\n      return [];\n    }\n\n    if (!includePreservedData) {\n      return navigations[0];\n    }\n\n    const data: T[] = [];\n    for (let index = this.#maxNavigationSaved; index >= 0; index--) {\n      if (navigations[index]) {\n        data.push(...navigations[index]);\n      }\n    }\n    return data;\n  }\n\n  getIdForResource(resource: WithSymbolId<T>): number {\n    return resource[stableIdSymbol] ?? -1;\n  }\n\n  getById(page: Page, stableId: number): T {\n    const navigations = this.storage.get(page);\n    if (!navigations) {\n      throw new Error('No requests found for selected page');\n    }\n\n    const item = this.find(page, item => item[stableIdSymbol] === stableId);\n\n    if (item) {\n      return item;\n    }\n\n    throw new Error('Request not found for selected page');\n  }\n\n  find(\n    page: Page,\n    filter: (item: WithSymbolId<T>) => boolean,\n  ): WithSymbolId<T> | undefined {\n    const navigations = this.storage.get(page);\n    if (!navigations) {\n      return;\n    }\n\n    for (const navigation of navigations) {\n      const item = navigation.find(filter);\n      if (item) {\n        return item;\n      }\n    }\n    return;\n  }\n}\n\nexport class ConsoleCollector extends PageCollector<\n  ConsoleMessage | Error | DevTools.AggregatedIssue | UncaughtError\n> {\n  #subscribedPages = new WeakMap<Page, PageEventSubscriber>();\n\n  override addPage(page: Page): void {\n    super.addPage(page);\n    if (!this.#subscribedPages.has(page)) {\n      const subscriber = new PageEventSubscriber(page);\n      this.#subscribedPages.set(page, subscriber);\n      void subscriber.subscribe();\n    }\n  }\n\n  protected override cleanupPageDestroyed(page: Page): void {\n    super.cleanupPageDestroyed(page);\n    this.#subscribedPages.get(page)?.unsubscribe();\n    this.#subscribedPages.delete(page);\n  }\n}\n\nclass PageEventSubscriber {\n  #issueManager = new FakeIssuesManager();\n  #issueAggregator = new DevTools.IssueAggregator(this.#issueManager);\n  #seenKeys = new Set<string>();\n  #seenIssues = new Set<DevTools.AggregatedIssue>();\n  #page: Page;\n  #session: CDPSession;\n  #targetId: string;\n\n  constructor(page: Page) {\n    this.#page = page;\n    // @ts-expect-error use existing CDP client (internal Puppeteer API).\n    this.#session = this.#page._client() as CDPSession;\n    // @ts-expect-error use internal Puppeteer API to get target ID\n    this.#targetId = this.#session.target()._targetId;\n  }\n\n  #resetIssueAggregator() {\n    this.#issueManager = new FakeIssuesManager();\n    if (this.#issueAggregator) {\n      this.#issueAggregator.removeEventListener(\n        DevTools.IssueAggregatorEvents.AGGREGATED_ISSUE_UPDATED,\n        this.#onAggregatedissue,\n      );\n    }\n    this.#issueAggregator = new DevTools.IssueAggregator(this.#issueManager);\n    this.#issueAggregator.addEventListener(\n      DevTools.IssueAggregatorEvents.AGGREGATED_ISSUE_UPDATED,\n      this.#onAggregatedissue,\n    );\n  }\n\n  async subscribe() {\n    this.#resetIssueAggregator();\n    this.#page.on('framenavigated', this.#onFrameNavigated);\n    this.#session.on('Audits.issueAdded', this.#onIssueAdded);\n    this.#session.on('Runtime.exceptionThrown', this.#onExceptionThrown);\n    try {\n      await this.#session.send('Audits.enable');\n    } catch (error) {\n      logger('Error subscribing to issues', error);\n    }\n  }\n\n  unsubscribe() {\n    this.#seenKeys.clear();\n    this.#seenIssues.clear();\n    this.#page.off('framenavigated', this.#onFrameNavigated);\n    this.#session.off('Audits.issueAdded', this.#onIssueAdded);\n    this.#session.off('Runtime.exceptionThrown', this.#onExceptionThrown);\n    if (this.#issueAggregator) {\n      this.#issueAggregator.removeEventListener(\n        DevTools.IssueAggregatorEvents.AGGREGATED_ISSUE_UPDATED,\n        this.#onAggregatedissue,\n      );\n    }\n    void this.#session.send('Audits.disable').catch(() => {\n      // might fail.\n    });\n  }\n\n  #onAggregatedissue = (\n    event: DevTools.Common.EventTarget.EventTargetEvent<DevTools.AggregatedIssue>,\n  ) => {\n    if (this.#seenIssues.has(event.data)) {\n      return;\n    }\n    this.#seenIssues.add(event.data);\n    this.#page.emit('issue', event.data);\n  };\n\n  #onExceptionThrown = (event: Protocol.Runtime.ExceptionThrownEvent) => {\n    this.#page.emit(\n      'uncaughtError',\n      new UncaughtError(event.exceptionDetails, this.#targetId),\n    );\n  };\n\n  // On navigation, we reset issue aggregation.\n  #onFrameNavigated = (frame: Frame) => {\n    // Only split the storage on main frame navigation\n    if (frame !== frame.page().mainFrame()) {\n      return;\n    }\n    this.#seenKeys.clear();\n    this.#seenIssues.clear();\n    this.#resetIssueAggregator();\n  };\n\n  #onIssueAdded = (data: Protocol.Audits.IssueAddedEvent) => {\n    try {\n      const inspectorIssue = data.issue;\n      const issue = DevTools.createIssuesFromProtocolIssue(\n        null,\n        // @ts-expect-error Protocol types diverge.\n        inspectorIssue,\n      )[0];\n      if (!issue) {\n        logger('No issue mapping for for the issue: ', inspectorIssue.code);\n        return;\n      }\n\n      const primaryKey = issue.primaryKey();\n      if (this.#seenKeys.has(primaryKey)) {\n        return;\n      }\n      this.#seenKeys.add(primaryKey);\n      this.#issueManager.dispatchEventToListeners(\n        DevTools.IssuesManagerEvents.ISSUE_ADDED,\n        {\n          issue,\n          // @ts-expect-error We don't care that issues model is null\n          issuesModel: null,\n        },\n      );\n    } catch (error) {\n      logger('Error creating a new issue', error);\n    }\n  };\n}\n\nexport class NetworkCollector extends PageCollector<HTTPRequest> {\n  constructor(\n    browser: Browser,\n    listeners: (\n      collector: (item: HTTPRequest) => void,\n    ) => ListenerMap<PageEvents> = collect => {\n      return {\n        request: req => {\n          collect(req);\n        },\n      } as ListenerMap;\n    },\n  ) {\n    super(browser, listeners);\n  }\n  override splitAfterNavigation(page: Page) {\n    const navigations = this.storage.get(page) ?? [];\n    if (!navigations) {\n      return;\n    }\n\n    const requests = navigations[0];\n\n    const lastRequestIdx = requests.findLastIndex(request => {\n      return request.frame() === page.mainFrame()\n        ? request.isNavigationRequest()\n        : false;\n    });\n\n    // Keep all requests since the last navigation request including that\n    // navigation request itself.\n    // Keep the reference\n    if (lastRequestIdx !== -1) {\n      const fromCurrentNavigation = requests.splice(lastRequestIdx);\n      navigations.unshift(fromCurrentNavigation);\n    } else {\n      navigations.unshift([]);\n    }\n  }\n}\n"
  },
  {
    "path": "src/SlimMcpResponse.ts",
    "content": "/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport type {\n  TextContent,\n  ImageContent,\n} from '@modelcontextprotocol/sdk/types.js';\n\nimport type {McpContext} from './McpContext.js';\nimport {McpResponse} from './McpResponse.js';\n\nexport class SlimMcpResponse extends McpResponse {\n  override async handle(\n    _toolName: string,\n    _context: McpContext,\n  ): Promise<{\n    content: Array<TextContent | ImageContent>;\n    structuredContent: object;\n  }> {\n    const text: TextContent = {\n      type: 'text',\n      text: this.responseLines.join('\\n'),\n    };\n    return {\n      content: [text],\n      structuredContent: text,\n    };\n  }\n}\n"
  },
  {
    "path": "src/WaitForHelper.ts",
    "content": "/**\n * @license\n * Copyright 2025 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport {logger} from './logger.js';\nimport type {Page, Protocol, CdpPage} from './third_party/index.js';\n\nexport class WaitForHelper {\n  #abortController = new AbortController();\n  #page: CdpPage;\n  #stableDomTimeout: number;\n  #stableDomFor: number;\n  #expectNavigationIn: number;\n  #navigationTimeout: number;\n\n  constructor(\n    page: Page,\n    cpuTimeoutMultiplier: number,\n    networkTimeoutMultiplier: number,\n  ) {\n    this.#stableDomTimeout = 3000 * cpuTimeoutMultiplier;\n    this.#stableDomFor = 100 * cpuTimeoutMultiplier;\n    this.#expectNavigationIn = 100 * cpuTimeoutMultiplier;\n    this.#navigationTimeout = 3000 * networkTimeoutMultiplier;\n    this.#page = page as unknown as CdpPage;\n  }\n\n  /**\n   * A wrapper that executes a action and waits for\n   * a potential navigation, after which it waits\n   * for the DOM to be stable before returning.\n   */\n  async waitForStableDom(): Promise<void> {\n    const stableDomObserver = await this.#page.evaluateHandle(timeout => {\n      let timeoutId: ReturnType<typeof setTimeout>;\n      function callback() {\n        clearTimeout(timeoutId);\n        timeoutId = setTimeout(() => {\n          domObserver.resolver.resolve();\n          domObserver.observer.disconnect();\n        }, timeout);\n      }\n      const domObserver = {\n        resolver: Promise.withResolvers<void>(),\n        observer: new MutationObserver(callback),\n      };\n      // It's possible that the DOM is not gonna change so we\n      // need to start the timeout initially.\n      callback();\n\n      domObserver.observer.observe(document.body, {\n        childList: true,\n        subtree: true,\n        attributes: true,\n      });\n\n      return domObserver;\n    }, this.#stableDomFor);\n\n    this.#abortController.signal.addEventListener('abort', async () => {\n      try {\n        await stableDomObserver.evaluate(observer => {\n          observer.observer.disconnect();\n          observer.resolver.resolve();\n        });\n        await stableDomObserver.dispose();\n      } catch {\n        // Ignored cleanup errors\n      }\n    });\n\n    return Promise.race([\n      stableDomObserver.evaluate(async observer => {\n        return await observer.resolver.promise;\n      }),\n      this.timeout(this.#stableDomTimeout).then(() => {\n        throw new Error('Timeout');\n      }),\n    ]);\n  }\n\n  async waitForNavigationStarted() {\n    // Currently Puppeteer does not have API\n    // For when a navigation is about to start\n    const navigationStartedPromise = new Promise<boolean>(resolve => {\n      const listener = (event: Protocol.Page.FrameStartedNavigatingEvent) => {\n        if (\n          [\n            'historySameDocument',\n            'historyDifferentDocument',\n            'sameDocument',\n          ].includes(event.navigationType)\n        ) {\n          resolve(false);\n          return;\n        }\n\n        resolve(true);\n      };\n\n      this.#page._client().on('Page.frameStartedNavigating', listener);\n      this.#abortController.signal.addEventListener('abort', () => {\n        resolve(false);\n        this.#page._client().off('Page.frameStartedNavigating', listener);\n      });\n    });\n\n    return await Promise.race([\n      navigationStartedPromise,\n      this.timeout(this.#expectNavigationIn).then(() => false),\n    ]);\n  }\n\n  timeout(time: number): Promise<void> {\n    return new Promise<void>(res => {\n      const id = setTimeout(res, time);\n      this.#abortController.signal.addEventListener('abort', () => {\n        res();\n        clearTimeout(id);\n      });\n    });\n  }\n\n  async waitForEventsAfterAction(\n    action: () => Promise<unknown>,\n    options?: {timeout?: number},\n  ): Promise<void> {\n    const navigationFinished = this.waitForNavigationStarted()\n      .then(navigationStated => {\n        if (navigationStated) {\n          return this.#page.waitForNavigation({\n            timeout: options?.timeout ?? this.#navigationTimeout,\n            signal: this.#abortController.signal,\n          });\n        }\n        return;\n      })\n      .catch(error => logger(error));\n\n    try {\n      await action();\n    } catch (error) {\n      // Clear up pending promises\n      this.#abortController.abort();\n      throw error;\n    }\n\n    try {\n      await navigationFinished;\n\n      // Wait for stable dom after navigation so we execute in\n      // the correct context\n      await this.waitForStableDom();\n    } catch (error) {\n      logger(error);\n    } finally {\n      this.#abortController.abort();\n    }\n  }\n}\n"
  },
  {
    "path": "src/bin/chrome-devtools-cli-options.ts",
    "content": "/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\n// NOTE: do not edit manually. Auto-generated by 'npm run cli:generate'.\n\nexport interface ArgDef {\n  name: string;\n  type: string;\n  description: string;\n  required: boolean;\n  default?: string | number | boolean;\n  enum?: ReadonlyArray<string | number>;\n}\nexport type Commands = Record<\n  string,\n  {\n    description: string;\n    category: string;\n    args: Record<string, ArgDef>;\n  }\n>;\nexport const commands: Commands = {\n  click: {\n    description: 'Clicks on the provided element',\n    category: 'Input automation',\n    args: {\n      uid: {\n        name: 'uid',\n        type: 'string',\n        description:\n          'The uid of an element on the page from the page content snapshot',\n        required: true,\n      },\n      dblClick: {\n        name: 'dblClick',\n        type: 'boolean',\n        description: 'Set to true for double clicks. Default is false.',\n        required: false,\n      },\n      includeSnapshot: {\n        name: 'includeSnapshot',\n        type: 'boolean',\n        description:\n          'Whether to include a snapshot in the response. Default is false.',\n        required: false,\n      },\n    },\n  },\n  close_page: {\n    description:\n      'Closes the page by its index. The last open page cannot be closed.',\n    category: 'Navigation automation',\n    args: {\n      pageId: {\n        name: 'pageId',\n        type: 'number',\n        description:\n          'The ID of the page to close. Call list_pages to list pages.',\n        required: true,\n      },\n    },\n  },\n  drag: {\n    description: 'Drag an element onto another element',\n    category: 'Input automation',\n    args: {\n      from_uid: {\n        name: 'from_uid',\n        type: 'string',\n        description: 'The uid of the element to drag',\n        required: true,\n      },\n      to_uid: {\n        name: 'to_uid',\n        type: 'string',\n        description: 'The uid of the element to drop into',\n        required: true,\n      },\n      includeSnapshot: {\n        name: 'includeSnapshot',\n        type: 'boolean',\n        description:\n          'Whether to include a snapshot in the response. Default is false.',\n        required: false,\n      },\n    },\n  },\n  emulate: {\n    description: 'Emulates various features on the selected page.',\n    category: 'Emulation',\n    args: {\n      networkConditions: {\n        name: 'networkConditions',\n        type: 'string',\n        description: 'Throttle network. Omit to disable throttling.',\n        required: false,\n        enum: ['Offline', 'Slow 3G', 'Fast 3G', 'Slow 4G', 'Fast 4G'],\n      },\n      cpuThrottlingRate: {\n        name: 'cpuThrottlingRate',\n        type: 'number',\n        description:\n          'Represents the CPU slowdown factor. Omit or set the rate to 1 to disable throttling',\n        required: false,\n      },\n      geolocation: {\n        name: 'geolocation',\n        type: 'string',\n        description:\n          'Geolocation (`<latitude>x<longitude>`) to emulate. Latitude between -90 and 90. Longitude between -180 and 180. Omit clear the geolocation override.',\n        required: false,\n      },\n      userAgent: {\n        name: 'userAgent',\n        type: 'string',\n        description:\n          'User agent to emulate. Set to empty string to clear the user agent override.',\n        required: false,\n      },\n      colorScheme: {\n        name: 'colorScheme',\n        type: 'string',\n        description:\n          'Emulate the dark or the light mode. Set to \"auto\" to reset to the default.',\n        required: false,\n        enum: ['dark', 'light', 'auto'],\n      },\n      viewport: {\n        name: 'viewport',\n        type: 'string',\n        description:\n          \"Emulate device viewports '<width>x<height>x<devicePixelRatio>[,mobile][,touch][,landscape]'. 'touch' and 'mobile' to emulate mobile devices. 'landscape' to emulate landscape mode.\",\n        required: false,\n      },\n    },\n  },\n  evaluate_script: {\n    description:\n      'Evaluate a JavaScript function inside the currently selected page. Returns the response as JSON,\\nso returned values have to be JSON-serializable.',\n    category: 'Debugging',\n    args: {\n      function: {\n        name: 'function',\n        type: 'string',\n        description:\n          'A JavaScript function declaration to be executed by the tool in the currently selected page.\\nExample without arguments: `() => {\\n  return document.title\\n}` or `async () => {\\n  return await fetch(\"example.com\")\\n}`.\\nExample with arguments: `(el) => {\\n  return el.innerText;\\n}`\\n',\n        required: true,\n      },\n      args: {\n        name: 'args',\n        type: 'array',\n        description: 'An optional list of arguments to pass to the function.',\n        required: false,\n      },\n    },\n  },\n  fill: {\n    description:\n      'Type text into a input, text area or select an option from a <select> element.',\n    category: 'Input automation',\n    args: {\n      uid: {\n        name: 'uid',\n        type: 'string',\n        description:\n          'The uid of an element on the page from the page content snapshot',\n        required: true,\n      },\n      value: {\n        name: 'value',\n        type: 'string',\n        description: 'The value to fill in',\n        required: true,\n      },\n      includeSnapshot: {\n        name: 'includeSnapshot',\n        type: 'boolean',\n        description:\n          'Whether to include a snapshot in the response. Default is false.',\n        required: false,\n      },\n    },\n  },\n  fill_form: {\n    description: 'Fill out multiple form elements at once',\n    category: 'Input automation',\n    args: {\n      elements: {\n        name: 'elements',\n        type: 'array',\n        description: 'Elements from snapshot to fill out.',\n        required: true,\n      },\n      includeSnapshot: {\n        name: 'includeSnapshot',\n        type: 'boolean',\n        description:\n          'Whether to include a snapshot in the response. Default is false.',\n        required: false,\n      },\n    },\n  },\n  get_console_message: {\n    description:\n      'Gets a console message by its ID. You can get all messages by calling list_console_messages.',\n    category: 'Debugging',\n    args: {\n      msgid: {\n        name: 'msgid',\n        type: 'number',\n        description:\n          'The msgid of a console message on the page from the listed console messages',\n        required: true,\n      },\n    },\n  },\n  get_network_request: {\n    description:\n      'Gets a network request by an optional reqid, if omitted returns the currently selected request in the DevTools Network panel.',\n    category: 'Network',\n    args: {\n      reqid: {\n        name: 'reqid',\n        type: 'number',\n        description:\n          'The reqid of the network request. If omitted returns the currently selected request in the DevTools Network panel.',\n        required: false,\n      },\n      requestFilePath: {\n        name: 'requestFilePath',\n        type: 'string',\n        description:\n          'The absolute or relative path to save the request body to. If omitted, the body is returned inline.',\n        required: false,\n      },\n      responseFilePath: {\n        name: 'responseFilePath',\n        type: 'string',\n        description:\n          'The absolute or relative path to save the response body to. If omitted, the body is returned inline.',\n        required: false,\n      },\n    },\n  },\n  handle_dialog: {\n    description:\n      'If a browser dialog was opened, use this command to handle it',\n    category: 'Input automation',\n    args: {\n      action: {\n        name: 'action',\n        type: 'string',\n        description: 'Whether to dismiss or accept the dialog',\n        required: true,\n        enum: ['accept', 'dismiss'],\n      },\n      promptText: {\n        name: 'promptText',\n        type: 'string',\n        description: 'Optional prompt text to enter into the dialog.',\n        required: false,\n      },\n    },\n  },\n  hover: {\n    description: 'Hover over the provided element',\n    category: 'Input automation',\n    args: {\n      uid: {\n        name: 'uid',\n        type: 'string',\n        description:\n          'The uid of an element on the page from the page content snapshot',\n        required: true,\n      },\n      includeSnapshot: {\n        name: 'includeSnapshot',\n        type: 'boolean',\n        description:\n          'Whether to include a snapshot in the response. Default is false.',\n        required: false,\n      },\n    },\n  },\n  lighthouse_audit: {\n    description:\n      'Get Lighthouse score and reports for accessibility, SEO and best practices. This excludes performance. For performance audits, run performance_start_trace',\n    category: 'Debugging',\n    args: {\n      mode: {\n        name: 'mode',\n        type: 'string',\n        description:\n          '\"navigation\" reloads & audits. \"snapshot\" analyzes current state.',\n        required: false,\n        default: 'navigation',\n        enum: ['navigation', 'snapshot'],\n      },\n      device: {\n        name: 'device',\n        type: 'string',\n        description: 'Device to emulate.',\n        required: false,\n        default: 'desktop',\n        enum: ['desktop', 'mobile'],\n      },\n      outputDirPath: {\n        name: 'outputDirPath',\n        type: 'string',\n        description: 'Directory for reports. If omitted, uses temporary files.',\n        required: false,\n      },\n    },\n  },\n  list_console_messages: {\n    description:\n      'List all console messages for the currently selected page since the last navigation.',\n    category: 'Debugging',\n    args: {\n      pageSize: {\n        name: 'pageSize',\n        type: 'integer',\n        description:\n          'Maximum number of messages to return. When omitted, returns all requests.',\n        required: false,\n      },\n      pageIdx: {\n        name: 'pageIdx',\n        type: 'integer',\n        description:\n          'Page number to return (0-based). When omitted, returns the first page.',\n        required: false,\n      },\n      types: {\n        name: 'types',\n        type: 'array',\n        description:\n          'Filter messages to only return messages of the specified resource types. When omitted or empty, returns all messages.',\n        required: false,\n      },\n      includePreservedMessages: {\n        name: 'includePreservedMessages',\n        type: 'boolean',\n        description:\n          'Set to true to return the preserved messages over the last 3 navigations.',\n        required: false,\n        default: false,\n      },\n    },\n  },\n  list_network_requests: {\n    description:\n      'List all requests for the currently selected page since the last navigation.',\n    category: 'Network',\n    args: {\n      pageSize: {\n        name: 'pageSize',\n        type: 'integer',\n        description:\n          'Maximum number of requests to return. When omitted, returns all requests.',\n        required: false,\n      },\n      pageIdx: {\n        name: 'pageIdx',\n        type: 'integer',\n        description:\n          'Page number to return (0-based). When omitted, returns the first page.',\n        required: false,\n      },\n      resourceTypes: {\n        name: 'resourceTypes',\n        type: 'array',\n        description:\n          'Filter requests to only return requests of the specified resource types. When omitted or empty, returns all requests.',\n        required: false,\n      },\n      includePreservedRequests: {\n        name: 'includePreservedRequests',\n        type: 'boolean',\n        description:\n          'Set to true to return the preserved requests over the last 3 navigations.',\n        required: false,\n        default: false,\n      },\n    },\n  },\n  list_pages: {\n    description: 'Get a list of pages  open in the browser.',\n    category: 'Navigation automation',\n    args: {},\n  },\n  navigate_page: {\n    description:\n      'Go to a URL, or back, forward, or reload. Use project URL if not specified otherwise.',\n    category: 'Navigation automation',\n    args: {\n      type: {\n        name: 'type',\n        type: 'string',\n        description:\n          'Navigate the page by URL, back or forward in history, or reload.',\n        required: false,\n        enum: ['url', 'back', 'forward', 'reload'],\n      },\n      url: {\n        name: 'url',\n        type: 'string',\n        description: 'Target URL (only type=url)',\n        required: false,\n      },\n      ignoreCache: {\n        name: 'ignoreCache',\n        type: 'boolean',\n        description: 'Whether to ignore cache on reload.',\n        required: false,\n      },\n      handleBeforeUnload: {\n        name: 'handleBeforeUnload',\n        type: 'string',\n        description:\n          'Whether to auto accept or beforeunload dialogs triggered by this navigation. Default is accept.',\n        required: false,\n        enum: ['accept', 'decline'],\n      },\n      initScript: {\n        name: 'initScript',\n        type: 'string',\n        description:\n          'A JavaScript script to be executed on each new document before any other scripts for the next navigation.',\n        required: false,\n      },\n      timeout: {\n        name: 'timeout',\n        type: 'integer',\n        description:\n          'Maximum wait time in milliseconds. If set to 0, the default timeout will be used.',\n        required: false,\n      },\n    },\n  },\n  new_page: {\n    description:\n      'Open a new tab and load a URL. Use project URL if not specified otherwise.',\n    category: 'Navigation automation',\n    args: {\n      url: {\n        name: 'url',\n        type: 'string',\n        description: 'URL to load in a new page.',\n        required: true,\n      },\n      background: {\n        name: 'background',\n        type: 'boolean',\n        description:\n          'Whether to open the page in the background without bringing it to the front. Default is false (foreground).',\n        required: false,\n      },\n      isolatedContext: {\n        name: 'isolatedContext',\n        type: 'string',\n        description:\n          'If specified, the page is created in an isolated browser context with the given name. Pages in the same browser context share cookies and storage. Pages in different browser contexts are fully isolated.',\n        required: false,\n      },\n      timeout: {\n        name: 'timeout',\n        type: 'integer',\n        description:\n          'Maximum wait time in milliseconds. If set to 0, the default timeout will be used.',\n        required: false,\n      },\n    },\n  },\n  performance_analyze_insight: {\n    description:\n      'Provides more detailed information on a specific Performance Insight of an insight set that was highlighted in the results of a trace recording.',\n    category: 'Performance',\n    args: {\n      insightSetId: {\n        name: 'insightSetId',\n        type: 'string',\n        description:\n          'The id for the specific insight set. Only use the ids given in the \"Available insight sets\" list.',\n        required: true,\n      },\n      insightName: {\n        name: 'insightName',\n        type: 'string',\n        description:\n          'The name of the Insight you want more information on. For example: \"DocumentLatency\" or \"LCPBreakdown\"',\n        required: true,\n      },\n    },\n  },\n  performance_start_trace: {\n    description:\n      'Start a performance trace on the selected webpage. Use to find frontend performance issues, Core Web Vitals (LCP, INP, CLS), and improve page load speed.',\n    category: 'Performance',\n    args: {\n      reload: {\n        name: 'reload',\n        type: 'boolean',\n        description:\n          'Determines if, once tracing has started, the current selected page should be automatically reloaded. Navigate the page to the right URL using the navigate_page tool BEFORE starting the trace if reload or autoStop is set to true.',\n        required: false,\n        default: true,\n      },\n      autoStop: {\n        name: 'autoStop',\n        type: 'boolean',\n        description:\n          'Determines if the trace recording should be automatically stopped.',\n        required: false,\n        default: true,\n      },\n      filePath: {\n        name: 'filePath',\n        type: 'string',\n        description:\n          'The absolute file path, or a file path relative to the current working directory, to save the raw trace data. For example, trace.json.gz (compressed) or trace.json (uncompressed).',\n        required: false,\n      },\n    },\n  },\n  performance_stop_trace: {\n    description:\n      'Stop the active performance trace recording on the selected webpage.',\n    category: 'Performance',\n    args: {\n      filePath: {\n        name: 'filePath',\n        type: 'string',\n        description:\n          'The absolute file path, or a file path relative to the current working directory, to save the raw trace data. For example, trace.json.gz (compressed) or trace.json (uncompressed).',\n        required: false,\n      },\n    },\n  },\n  press_key: {\n    description:\n      'Press a key or key combination. Use this when other input methods like fill() cannot be used (e.g., keyboard shortcuts, navigation keys, or special key combinations).',\n    category: 'Input automation',\n    args: {\n      key: {\n        name: 'key',\n        type: 'string',\n        description:\n          'A key or a combination (e.g., \"Enter\", \"Control+A\", \"Control++\", \"Control+Shift+R\"). Modifiers: Control, Shift, Alt, Meta',\n        required: true,\n      },\n      includeSnapshot: {\n        name: 'includeSnapshot',\n        type: 'boolean',\n        description:\n          'Whether to include a snapshot in the response. Default is false.',\n        required: false,\n      },\n    },\n  },\n  resize_page: {\n    description:\n      \"Resizes the selected page's window so that the page has specified dimension\",\n    category: 'Emulation',\n    args: {\n      width: {\n        name: 'width',\n        type: 'number',\n        description: 'Page width',\n        required: true,\n      },\n      height: {\n        name: 'height',\n        type: 'number',\n        description: 'Page height',\n        required: true,\n      },\n    },\n  },\n  select_page: {\n    description: 'Select a page as a context for future tool calls.',\n    category: 'Navigation automation',\n    args: {\n      pageId: {\n        name: 'pageId',\n        type: 'number',\n        description:\n          'The ID of the page to select. Call list_pages to get available pages.',\n        required: true,\n      },\n      bringToFront: {\n        name: 'bringToFront',\n        type: 'boolean',\n        description: 'Whether to focus the page and bring it to the top.',\n        required: false,\n      },\n    },\n  },\n  take_memory_snapshot: {\n    description:\n      'Capture a memory heapsnapshot of the currently selected page to memory leak debugging',\n    category: 'Performance',\n    args: {\n      filePath: {\n        name: 'filePath',\n        type: 'string',\n        description:\n          'A path to a .heapsnapshot file to save the heapsnapshot to.',\n        required: true,\n      },\n    },\n  },\n  take_screenshot: {\n    description: 'Take a screenshot of the page or element.',\n    category: 'Debugging',\n    args: {\n      format: {\n        name: 'format',\n        type: 'string',\n        description:\n          'Type of format to save the screenshot as. Default is \"png\"',\n        required: false,\n        default: 'png',\n        enum: ['png', 'jpeg', 'webp'],\n      },\n      quality: {\n        name: 'quality',\n        type: 'number',\n        description:\n          'Compression quality for JPEG and WebP formats (0-100). Higher values mean better quality but larger file sizes. Ignored for PNG format.',\n        required: false,\n      },\n      uid: {\n        name: 'uid',\n        type: 'string',\n        description:\n          'The uid of an element on the page from the page content snapshot. If omitted takes a pages screenshot.',\n        required: false,\n      },\n      fullPage: {\n        name: 'fullPage',\n        type: 'boolean',\n        description:\n          'If set to true takes a screenshot of the full page instead of the currently visible viewport. Incompatible with uid.',\n        required: false,\n      },\n      filePath: {\n        name: 'filePath',\n        type: 'string',\n        description:\n          'The absolute path, or a path relative to the current working directory, to save the screenshot to instead of attaching it to the response.',\n        required: false,\n      },\n    },\n  },\n  take_snapshot: {\n    description:\n      'Take a text snapshot of the currently selected page based on the a11y tree. The snapshot lists page elements along with a unique\\nidentifier (uid). Always use the latest snapshot. Prefer taking a snapshot over taking a screenshot. The snapshot indicates the element selected\\nin the DevTools Elements panel (if any).',\n    category: 'Debugging',\n    args: {\n      verbose: {\n        name: 'verbose',\n        type: 'boolean',\n        description:\n          'Whether to include all possible information available in the full a11y tree. Default is false.',\n        required: false,\n      },\n      filePath: {\n        name: 'filePath',\n        type: 'string',\n        description:\n          'The absolute path, or a path relative to the current working directory, to save the snapshot to instead of attaching it to the response.',\n        required: false,\n      },\n    },\n  },\n  type_text: {\n    description: 'Type text using keyboard into a previously focused input',\n    category: 'Input automation',\n    args: {\n      text: {\n        name: 'text',\n        type: 'string',\n        description: 'The text to type',\n        required: true,\n      },\n      submitKey: {\n        name: 'submitKey',\n        type: 'string',\n        description:\n          'Optional key to press after typing. E.g., \"Enter\", \"Tab\", \"Escape\"',\n        required: false,\n      },\n    },\n  },\n  upload_file: {\n    description: 'Upload a file through a provided element.',\n    category: 'Input automation',\n    args: {\n      uid: {\n        name: 'uid',\n        type: 'string',\n        description:\n          'The uid of the file input element or an element that will open file chooser on the page from the page content snapshot',\n        required: true,\n      },\n      filePath: {\n        name: 'filePath',\n        type: 'string',\n        description: 'The local path of the file to upload',\n        required: true,\n      },\n      includeSnapshot: {\n        name: 'includeSnapshot',\n        type: 'boolean',\n        description:\n          'Whether to include a snapshot in the response. Default is false.',\n        required: false,\n      },\n    },\n  },\n  wait_for: {\n    description: 'Wait for the specified text to appear on the selected page.',\n    category: 'Navigation automation',\n    args: {\n      text: {\n        name: 'text',\n        type: 'array',\n        description:\n          'Non-empty list of texts. Resolves when any value appears on the page.',\n        required: true,\n      },\n      timeout: {\n        name: 'timeout',\n        type: 'integer',\n        description:\n          'Maximum wait time in milliseconds. If set to 0, the default timeout will be used.',\n        required: false,\n      },\n    },\n  },\n} as const;\n"
  },
  {
    "path": "src/bin/chrome-devtools-mcp-cli-options.ts",
    "content": "/**\n * @license\n * Copyright 2025 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport type {YargsOptions} from '../third_party/index.js';\nimport {yargs, hideBin} from '../third_party/index.js';\n\nexport const cliOptions = {\n  autoConnect: {\n    type: 'boolean',\n    description:\n      'If specified, automatically connects to a browser (Chrome 144+) running locally from the user data directory identified by the channel param (default channel is stable). Requires the remoted debugging server to be started in the Chrome instance via chrome://inspect/#remote-debugging.',\n    conflicts: ['isolated', 'executablePath', 'categoryExtensions'],\n    default: false,\n    coerce: (value: boolean | undefined) => {\n      if (!value) {\n        return;\n      }\n      return value;\n    },\n  },\n  browserUrl: {\n    type: 'string',\n    description:\n      'Connect to a running, debuggable Chrome instance (e.g. `http://127.0.0.1:9222`). For more details see: https://github.com/ChromeDevTools/chrome-devtools-mcp#connecting-to-a-running-chrome-instance.',\n    alias: 'u',\n    conflicts: ['wsEndpoint', 'categoryExtensions'],\n    coerce: (url: string | undefined) => {\n      if (!url) {\n        return;\n      }\n      try {\n        new URL(url);\n      } catch {\n        throw new Error(`Provided browserUrl ${url} is not valid URL.`);\n      }\n      return url;\n    },\n  },\n  wsEndpoint: {\n    type: 'string',\n    description:\n      'WebSocket endpoint to connect to a running Chrome instance (e.g., ws://127.0.0.1:9222/devtools/browser/<id>). Alternative to --browserUrl.',\n    alias: 'w',\n    conflicts: ['browserUrl', 'categoryExtensions'],\n    coerce: (url: string | undefined) => {\n      if (!url) {\n        return;\n      }\n      try {\n        const parsed = new URL(url);\n        if (parsed.protocol !== 'ws:' && parsed.protocol !== 'wss:') {\n          throw new Error(\n            `Provided wsEndpoint ${url} must use ws:// or wss:// protocol.`,\n          );\n        }\n        return url;\n      } catch (error) {\n        if ((error as Error).message.includes('ws://')) {\n          throw error;\n        }\n        throw new Error(`Provided wsEndpoint ${url} is not valid URL.`);\n      }\n    },\n  },\n  wsHeaders: {\n    type: 'string',\n    description:\n      'Custom headers for WebSocket connection in JSON format (e.g., \\'{\"Authorization\":\"Bearer token\"}\\'). Only works with --wsEndpoint.',\n    implies: 'wsEndpoint',\n    coerce: (val: string | undefined) => {\n      if (!val) {\n        return;\n      }\n      try {\n        const parsed = JSON.parse(val);\n        if (typeof parsed !== 'object' || Array.isArray(parsed)) {\n          throw new Error('Headers must be a JSON object');\n        }\n        return parsed as Record<string, string>;\n      } catch (error) {\n        throw new Error(\n          `Invalid JSON for wsHeaders: ${(error as Error).message}`,\n        );\n      }\n    },\n  },\n  headless: {\n    type: 'boolean',\n    description: 'Whether to run in headless (no UI) mode.',\n    default: false,\n  },\n  executablePath: {\n    type: 'string',\n    description: 'Path to custom Chrome executable.',\n    conflicts: ['browserUrl', 'wsEndpoint'],\n    alias: 'e',\n  },\n  isolated: {\n    type: 'boolean',\n    description:\n      'If specified, creates a temporary user-data-dir that is automatically cleaned up after the browser is closed. Defaults to false.',\n  },\n  userDataDir: {\n    type: 'string',\n    description:\n      'Path to the user data directory for Chrome. Default is $HOME/.cache/chrome-devtools-mcp/chrome-profile$CHANNEL_SUFFIX_IF_NON_STABLE',\n    conflicts: ['browserUrl', 'wsEndpoint', 'isolated'],\n  },\n  channel: {\n    type: 'string',\n    description:\n      'Specify a different Chrome channel that should be used. The default is the stable channel version.',\n    choices: ['stable', 'canary', 'beta', 'dev'] as const,\n    conflicts: ['browserUrl', 'wsEndpoint', 'executablePath'],\n  },\n  logFile: {\n    type: 'string',\n    describe:\n      'Path to a file to write debug logs to. Set the env variable `DEBUG` to `*` to enable verbose logs. Useful for submitting bug reports.',\n  },\n  viewport: {\n    type: 'string',\n    describe:\n      'Initial viewport size for the Chrome instances started by the server. For example, `1280x720`. In headless mode, max size is 3840x2160px.',\n    coerce: (arg: string | undefined) => {\n      if (arg === undefined) {\n        return;\n      }\n      const [width, height] = arg.split('x').map(Number);\n      if (!width || !height || Number.isNaN(width) || Number.isNaN(height)) {\n        throw new Error('Invalid viewport. Expected format is `1280x720`.');\n      }\n      return {\n        width,\n        height,\n      };\n    },\n  },\n  proxyServer: {\n    type: 'string',\n    description: `Proxy server configuration for Chrome passed as --proxy-server when launching the browser. See https://www.chromium.org/developers/design-documents/network-settings/ for details.`,\n  },\n  acceptInsecureCerts: {\n    type: 'boolean',\n    description: `If enabled, ignores errors relative to self-signed and expired certificates. Use with caution.`,\n  },\n  experimentalPageIdRouting: {\n    type: 'boolean',\n    describe:\n      'Whether to expose pageId on page-scoped tools and route requests by page ID.',\n    hidden: true,\n  },\n  experimentalDevtools: {\n    type: 'boolean',\n    describe: 'Whether to enable automation over DevTools targets',\n    hidden: true,\n  },\n  experimentalVision: {\n    type: 'boolean',\n    describe: 'Whether to enable vision tools',\n    hidden: true,\n  },\n  experimentalStructuredContent: {\n    type: 'boolean',\n    describe: 'Whether to output structured formatted content.',\n    hidden: true,\n  },\n  experimentalIncludeAllPages: {\n    type: 'boolean',\n    describe:\n      'Whether to include all kinds of pages such as webviews or background pages as pages.',\n    hidden: true,\n  },\n  experimentalInteropTools: {\n    type: 'boolean',\n    describe: 'Whether to enable interoperability tools',\n    hidden: true,\n  },\n  experimentalScreencast: {\n    type: 'boolean',\n    describe:\n      'Exposes experimental screencast tools (requires ffmpeg). Install ffmpeg https://www.ffmpeg.org/download.html and ensure it is available in the MCP server PATH.',\n  },\n  chromeArg: {\n    type: 'array',\n    describe:\n      'Additional arguments for Chrome. Only applies when Chrome is launched by chrome-devtools-mcp.',\n  },\n  ignoreDefaultChromeArg: {\n    type: 'array',\n    describe:\n      'Explicitly disable default arguments for Chrome. Only applies when Chrome is launched by chrome-devtools-mcp.',\n  },\n  categoryEmulation: {\n    type: 'boolean',\n    default: true,\n    describe: 'Set to false to exclude tools related to emulation.',\n  },\n  categoryPerformance: {\n    type: 'boolean',\n    default: true,\n    describe: 'Set to false to exclude tools related to performance.',\n  },\n  categoryNetwork: {\n    type: 'boolean',\n    default: true,\n    describe: 'Set to false to exclude tools related to network.',\n  },\n  categoryExtensions: {\n    type: 'boolean',\n    hidden: true,\n    conflicts: ['browserUrl', 'autoConnect', 'wsEndpoint'],\n    describe:\n      'Set to true to include tools related to extensions. Note: This feature is only supported with a pipe connection. autoConnect is not supported.',\n  },\n  performanceCrux: {\n    type: 'boolean',\n    default: true,\n    describe:\n      'Set to false to disable sending URLs from performance traces to CrUX API to get field performance data.',\n  },\n  usageStatistics: {\n    type: 'boolean',\n    default: true,\n    describe:\n      'Set to false to opt-out of usage statistics collection. Google collects usage data to improve the tool, handled under the Google Privacy Policy (https://policies.google.com/privacy). This is independent from Chrome browser metrics. Disabled if CHROME_DEVTOOLS_MCP_NO_USAGE_STATISTICS or CI env variables are set.',\n  },\n  clearcutEndpoint: {\n    type: 'string',\n    hidden: true,\n    describe: 'Endpoint for Clearcut telemetry.',\n  },\n  clearcutForceFlushIntervalMs: {\n    type: 'number',\n    hidden: true,\n    describe: 'Force flush interval in milliseconds (for testing).',\n  },\n  clearcutIncludePidHeader: {\n    type: 'boolean',\n    hidden: true,\n    describe: 'Include watchdog PID in Clearcut request headers (for testing).',\n  },\n  slim: {\n    type: 'boolean',\n    describe:\n      'Exposes a \"slim\" set of 3 tools covering navigation, script execution and screenshots only. Useful for basic browser tasks.',\n  },\n  viaCli: {\n    type: 'boolean',\n    describe:\n      'Set by Chrome DevTools CLI if the MCP server is started via the CLI client (this arg exists for usage stats)',\n    hidden: true,\n  },\n} satisfies Record<string, YargsOptions>;\n\nexport type ParsedArguments = ReturnType<typeof parseArguments>;\n\nexport function parseArguments(version: string, argv = process.argv) {\n  const yargsInstance = yargs(hideBin(argv))\n    .scriptName('npx chrome-devtools-mcp@latest')\n    .options(cliOptions)\n    .check(args => {\n      // We can't set default in the options else\n      // Yargs will complain\n      if (\n        !args.channel &&\n        !args.browserUrl &&\n        !args.wsEndpoint &&\n        !args.executablePath\n      ) {\n        args.channel = 'stable';\n      }\n      return true;\n    })\n    .example([\n      [\n        '$0 --browserUrl http://127.0.0.1:9222',\n        'Connect to an existing browser instance via HTTP',\n      ],\n      [\n        '$0 --wsEndpoint ws://127.0.0.1:9222/devtools/browser/abc123',\n        'Connect to an existing browser instance via WebSocket',\n      ],\n      [\n        `$0 --wsEndpoint ws://127.0.0.1:9222/devtools/browser/abc123 --wsHeaders '{\"Authorization\":\"Bearer token\"}'`,\n        'Connect via WebSocket with custom headers',\n      ],\n      ['$0 --channel beta', 'Use Chrome Beta installed on this system'],\n      ['$0 --channel canary', 'Use Chrome Canary installed on this system'],\n      ['$0 --channel dev', 'Use Chrome Dev installed on this system'],\n      ['$0 --channel stable', 'Use stable Chrome installed on this system'],\n      ['$0 --logFile /tmp/log.txt', 'Save logs to a file'],\n      ['$0 --help', 'Print CLI options'],\n      [\n        '$0 --viewport 1280x720',\n        'Launch Chrome with the initial viewport size of 1280x720px',\n      ],\n      [\n        `$0 --chrome-arg='--no-sandbox' --chrome-arg='--disable-setuid-sandbox'`,\n        'Launch Chrome without sandboxes. Use with caution.',\n      ],\n      [\n        `$0 --ignore-default-chrome-arg='--disable-extensions'`,\n        'Disable the default arguments provided by Puppeteer. Use with caution.',\n      ],\n      ['$0 --no-category-emulation', 'Disable tools in the emulation category'],\n      [\n        '$0 --no-category-performance',\n        'Disable tools in the performance category',\n      ],\n      ['$0 --no-category-network', 'Disable tools in the network category'],\n      [\n        '$0 --user-data-dir=/tmp/user-data-dir',\n        'Use a custom user data directory',\n      ],\n      [\n        '$0 --auto-connect',\n        'Connect to a stable Chrome instance (Chrome 144+) running instead of launching a new instance',\n      ],\n      [\n        '$0 --auto-connect --channel=canary',\n        'Connect to a canary Chrome instance (Chrome 144+) running instead of launching a new instance',\n      ],\n      [\n        '$0 --no-usage-statistics',\n        'Do not send usage statistics https://github.com/ChromeDevTools/chrome-devtools-mcp#usage-statistics.',\n      ],\n      [\n        '$0 --no-performance-crux',\n        'Disable CrUX (field data) integration in performance tools.',\n      ],\n      [\n        '$0 --slim',\n        'Only 3 tools: navigation, JavaScript execution and screenshot',\n      ],\n    ]);\n\n  return yargsInstance\n    .wrap(Math.min(120, yargsInstance.terminalWidth()))\n    .help()\n    .version(version)\n    .parseSync();\n}\n"
  },
  {
    "path": "src/bin/chrome-devtools-mcp-main.ts",
    "content": "/**\n * @license\n * Copyright 2025 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport '../polyfill.js';\n\nimport process from 'node:process';\n\nimport {createMcpServer, logDisclaimers} from '../index.js';\nimport {logger, saveLogsToFile} from '../logger.js';\nimport {computeFlagUsage} from '../telemetry/flagUtils.js';\nimport {StdioServerTransport} from '../third_party/index.js';\nimport {VERSION} from '../version.js';\n\nimport {cliOptions, parseArguments} from './chrome-devtools-mcp-cli-options.js';\n\nexport const args = parseArguments(VERSION);\n\nconst logFile = args.logFile ? saveLogsToFile(args.logFile) : undefined;\nif (\n  process.env['CI'] ||\n  process.env['CHROME_DEVTOOLS_MCP_NO_USAGE_STATISTICS']\n) {\n  console.error(\n    \"turning off usage statistics. process.env['CI'] || process.env['CHROME_DEVTOOLS_MCP_NO_USAGE_STATISTICS'] is set.\",\n  );\n  args.usageStatistics = false;\n}\n\nif (process.env['CHROME_DEVTOOLS_MCP_CRASH_ON_UNCAUGHT'] !== 'true') {\n  process.on('unhandledRejection', (reason, promise) => {\n    logger('Unhandled promise rejection', promise, reason);\n  });\n}\n\nlogger(`Starting Chrome DevTools MCP Server v${VERSION}`);\nconst {server, clearcutLogger} = await createMcpServer(args, {\n  logFile,\n});\nconst transport = new StdioServerTransport();\nawait server.connect(transport);\nlogger('Chrome DevTools MCP Server connected');\nlogDisclaimers(args);\nvoid clearcutLogger?.logDailyActiveIfNeeded();\nvoid clearcutLogger?.logServerStart(computeFlagUsage(args, cliOptions));\n"
  },
  {
    "path": "src/bin/chrome-devtools-mcp.ts",
    "content": "#!/usr/bin/env node\n\n/**\n * @license\n * Copyright 2025 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport {version} from 'node:process';\n\nconst [major, minor] = version.substring(1).split('.').map(Number);\n\nif (major === 20 && minor < 19) {\n  console.error(\n    `ERROR: \\`chrome-devtools-mcp\\` does not support Node ${process.version}. Please upgrade to Node 20.19.0 LTS or a newer LTS.`,\n  );\n  process.exit(1);\n}\n\nif (major === 22 && minor < 12) {\n  console.error(\n    `ERROR: \\`chrome-devtools-mcp\\` does not support Node ${process.version}. Please upgrade to Node 22.12.0 LTS or a newer LTS.`,\n  );\n  process.exit(1);\n}\n\nif (major < 20) {\n  console.error(\n    `ERROR: \\`chrome-devtools-mcp\\` does not support Node ${process.version}. Please upgrade to Node 20.19.0 LTS or a newer LTS.`,\n  );\n  process.exit(1);\n}\n\nawait import('./chrome-devtools-mcp-main.js');\n"
  },
  {
    "path": "src/bin/chrome-devtools.ts",
    "content": "#!/usr/bin/env node\n\n/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport process from 'node:process';\n\nimport type {Options, PositionalOptions} from 'yargs';\n\nimport {\n  startDaemon,\n  stopDaemon,\n  sendCommand,\n  handleResponse,\n} from '../daemon/client.js';\nimport {isDaemonRunning, serializeArgs} from '../daemon/utils.js';\nimport {logDisclaimers} from '../index.js';\nimport {hideBin, yargs, type CallToolResult} from '../third_party/index.js';\nimport {VERSION} from '../version.js';\n\nimport {commands} from './chrome-devtools-cli-options.js';\nimport {cliOptions, parseArguments} from './chrome-devtools-mcp-cli-options.js';\n\nasync function start(args: string[]) {\n  const combinedArgs = [...args, ...defaultArgs];\n  await startDaemon(combinedArgs);\n  logDisclaimers(parseArguments(VERSION, combinedArgs));\n}\n\nconst defaultArgs = ['--viaCli', '--experimentalStructuredContent'];\n\nconst startCliOptions = {\n  ...cliOptions,\n} as Partial<typeof cliOptions>;\n\n// Not supported in CLI on purpose.\ndelete startCliOptions.autoConnect;\n// Missing CLI serialization.\ndelete startCliOptions.viewport;\n// CLI is generated based on the default tool definitions. To enable conditional\n// tools, they needs to be enabled during CLI generation.\ndelete startCliOptions.experimentalPageIdRouting;\ndelete startCliOptions.experimentalVision;\ndelete startCliOptions.experimentalInteropTools;\ndelete startCliOptions.experimentalScreencast;\ndelete startCliOptions.categoryEmulation;\ndelete startCliOptions.categoryPerformance;\ndelete startCliOptions.categoryNetwork;\ndelete startCliOptions.categoryExtensions;\n// Always on in CLI.\ndelete startCliOptions.experimentalStructuredContent;\n// Change the defaults.\nif (!('default' in cliOptions.headless)) {\n  throw new Error('headless cli option unexpectedly does not have a default');\n}\nif ('default' in cliOptions.isolated) {\n  throw new Error('headless cli option unexpectedly does not have a default');\n}\nstartCliOptions.headless!.default = true;\n\nconst y = yargs(hideBin(process.argv))\n  .scriptName('chrome-devtools')\n  .showHelpOnFail(true)\n  .usage('chrome-devtools <command> [...args] --flags')\n  .usage(\n    `Run 'chrome-devtools <command> --help' for help on the specific command.`,\n  )\n  .demandCommand()\n  .version(VERSION)\n  .strict()\n  .help(true)\n  .wrap(120);\n\ny.command(\n  'start',\n  'Start or restart chrome-devtools-mcp',\n  y =>\n    y\n      .options(startCliOptions)\n      .example(\n        '$0 start --browserUrl http://localhost:9222',\n        'Start the server connecting to an existing browser',\n      )\n      .strict(),\n  async argv => {\n    if (isDaemonRunning()) {\n      await stopDaemon();\n    }\n    // Defaults but we do not want to affect the yargs conflict resolution.\n    if (argv.isolated === undefined) {\n      argv.isolated = true;\n    }\n    if (argv.headless === undefined) {\n      argv.headless = true;\n    }\n    const args = serializeArgs(cliOptions, argv);\n    await start(args);\n    process.exit(0);\n  },\n).strict(); // Re-enable strict validation for other commands; this is applied to the yargs instance itself\n\ny.command('status', 'Checks if chrome-devtools-mcp is running', async () => {\n  if (isDaemonRunning()) {\n    console.log('chrome-devtools-mcp daemon is running.');\n    const response = await sendCommand({\n      method: 'status',\n    });\n    if (response.success) {\n      const data = JSON.parse(response.result) as {\n        pid: number | null;\n        socketPath: string;\n        startDate: string;\n        version: string;\n        args: string[];\n      };\n      console.log(\n        `pid=${data.pid} socket=${data.socketPath} start-date=${data.startDate} version=${data.version}`,\n      );\n      console.log(`args=${JSON.stringify(data.args)}`);\n    } else {\n      console.error('Error:', response.error);\n      process.exit(1);\n    }\n  } else {\n    console.log('chrome-devtools-mcp daemon is not running.');\n  }\n  process.exit(0);\n});\n\ny.command('stop', 'Stop chrome-devtools-mcp if any', async () => {\n  if (!isDaemonRunning()) {\n    process.exit(0);\n  }\n  await stopDaemon();\n  process.exit(0);\n});\n\nfor (const [commandName, commandDef] of Object.entries(commands)) {\n  const args = commandDef.args;\n  const requiredArgNames = Object.keys(args).filter(\n    name => args[name].required,\n  );\n\n  const optionalArgNames = Object.keys(args).filter(\n    name => !args[name].required,\n  );\n\n  let commandStr = commandName;\n  for (const arg of requiredArgNames) {\n    commandStr += ` <${arg}>`;\n  }\n\n  for (const arg of optionalArgNames) {\n    commandStr += ` [--${arg}]`;\n  }\n\n  y.command(\n    commandStr,\n    commandDef.description,\n    y => {\n      y.option('output-format', {\n        choices: ['md', 'json'],\n        default: 'md',\n      });\n      for (const [argName, opt] of Object.entries(args)) {\n        const type =\n          opt.type === 'integer' || opt.type === 'number'\n            ? 'number'\n            : opt.type === 'boolean'\n              ? 'boolean'\n              : opt.type === 'array'\n                ? 'array'\n                : 'string';\n\n        if (opt.required) {\n          const options: PositionalOptions = {\n            describe: opt.description,\n            type: type as PositionalOptions['type'],\n          };\n          if (opt.default !== undefined) {\n            options.default = opt.default;\n          }\n          if (opt.enum) {\n            options.choices = opt.enum as Array<string | number>;\n          }\n          y.positional(argName, options);\n        } else {\n          const options: Options = {\n            describe: opt.description,\n            type: type as Options['type'],\n          };\n          if (opt.default !== undefined) {\n            options.default = opt.default;\n          }\n          if (opt.enum) {\n            options.choices = opt.enum as Array<string | number>;\n          }\n          y.option(argName, options);\n        }\n      }\n    },\n    async argv => {\n      try {\n        if (!isDaemonRunning()) {\n          await start([]);\n        }\n\n        const commandArgs: Record<string, unknown> = {};\n        for (const argName of Object.keys(args)) {\n          if (argName in argv) {\n            commandArgs[argName] = argv[argName];\n          }\n        }\n\n        const response = await sendCommand({\n          method: 'invoke_tool',\n          tool: commandName,\n          args: commandArgs,\n        });\n\n        if (response.success) {\n          console.log(\n            await handleResponse(\n              JSON.parse(response.result) as unknown as CallToolResult,\n              argv['output-format'] as 'json' | 'md',\n            ),\n          );\n        } else {\n          console.error('Error:', response.error);\n          process.exit(1);\n        }\n      } catch (error) {\n        console.error('Failed to execute command:', error);\n        process.exit(1);\n      }\n    },\n  );\n}\n\nawait y.parse();\n"
  },
  {
    "path": "src/bin/cliDefinitions.ts",
    "content": "/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\n// NOTE: do not edit manually. Auto-generated by 'npm run cli:generate'.\n\nexport interface ArgDef {\n  name: string;\n  type: string;\n  description: string;\n  required: boolean;\n  default?: string | number | boolean;\n  enum?: ReadonlyArray<string | number>;\n}\nexport type Commands = Record<\n  string,\n  {\n    description: string;\n    category: string;\n    args: Record<string, ArgDef>;\n  }\n>;\nexport const commands: Commands = {\n  click: {\n    description: 'Clicks on the provided element',\n    category: 'Input automation',\n    args: {\n      uid: {\n        name: 'uid',\n        type: 'string',\n        description:\n          'The uid of an element on the page from the page content snapshot',\n        required: true,\n      },\n      dblClick: {\n        name: 'dblClick',\n        type: 'boolean',\n        description: 'Set to true for double clicks. Default is false.',\n        required: false,\n      },\n      includeSnapshot: {\n        name: 'includeSnapshot',\n        type: 'boolean',\n        description:\n          'Whether to include a snapshot in the response. Default is false.',\n        required: false,\n      },\n    },\n  },\n  close_page: {\n    description:\n      'Closes the page by its index. The last open page cannot be closed.',\n    category: 'Navigation automation',\n    args: {\n      pageId: {\n        name: 'pageId',\n        type: 'number',\n        description:\n          'The ID of the page to close. Call list_pages to list pages.',\n        required: true,\n      },\n    },\n  },\n  drag: {\n    description: 'Drag an element onto another element',\n    category: 'Input automation',\n    args: {\n      from_uid: {\n        name: 'from_uid',\n        type: 'string',\n        description: 'The uid of the element to drag',\n        required: true,\n      },\n      to_uid: {\n        name: 'to_uid',\n        type: 'string',\n        description: 'The uid of the element to drop into',\n        required: true,\n      },\n      includeSnapshot: {\n        name: 'includeSnapshot',\n        type: 'boolean',\n        description:\n          'Whether to include a snapshot in the response. Default is false.',\n        required: false,\n      },\n    },\n  },\n  emulate: {\n    description: 'Emulates various features on the selected page.',\n    category: 'Emulation',\n    args: {\n      networkConditions: {\n        name: 'networkConditions',\n        type: 'string',\n        description: 'Throttle network. Omit to disable throttling.',\n        required: false,\n        enum: ['Offline', 'Slow 3G', 'Fast 3G', 'Slow 4G', 'Fast 4G'],\n      },\n      cpuThrottlingRate: {\n        name: 'cpuThrottlingRate',\n        type: 'number',\n        description:\n          'Represents the CPU slowdown factor. Omit or set the rate to 1 to disable throttling',\n        required: false,\n      },\n      geolocation: {\n        name: 'geolocation',\n        type: 'string',\n        description:\n          'Geolocation (`<latitude>x<longitude>`) to emulate. Latitude between -90 and 90. Longitude between -180 and 180. Omit clear the geolocation override.',\n        required: false,\n      },\n      userAgent: {\n        name: 'userAgent',\n        type: 'string',\n        description:\n          'User agent to emulate. Set to empty string to clear the user agent override.',\n        required: false,\n      },\n      colorScheme: {\n        name: 'colorScheme',\n        type: 'string',\n        description:\n          'Emulate the dark or the light mode. Set to \"auto\" to reset to the default.',\n        required: false,\n        enum: ['dark', 'light', 'auto'],\n      },\n      viewport: {\n        name: 'viewport',\n        type: 'string',\n        description:\n          \"Emulate device viewports '<width>x<height>x<devicePixelRatio>[,mobile][,touch][,landscape]'. 'touch' and 'mobile' to emulate mobile devices. 'landscape' to emulate landscape mode.\",\n        required: false,\n      },\n    },\n  },\n  evaluate_script: {\n    description:\n      'Evaluate a JavaScript function inside the currently selected page. Returns the response as JSON,\\nso returned values have to be JSON-serializable.',\n    category: 'Debugging',\n    args: {\n      function: {\n        name: 'function',\n        type: 'string',\n        description:\n          'A JavaScript function declaration to be executed by the tool in the currently selected page.\\nExample without arguments: `() => {\\n  return document.title\\n}` or `async () => {\\n  return await fetch(\"example.com\")\\n}`.\\nExample with arguments: `(el) => {\\n  return el.innerText;\\n}`\\n',\n        required: true,\n      },\n      args: {\n        name: 'args',\n        type: 'array',\n        description: 'An optional list of arguments to pass to the function.',\n        required: false,\n      },\n    },\n  },\n  fill: {\n    description:\n      'Type text into a input, text area or select an option from a <select> element.',\n    category: 'Input automation',\n    args: {\n      uid: {\n        name: 'uid',\n        type: 'string',\n        description:\n          'The uid of an element on the page from the page content snapshot',\n        required: true,\n      },\n      value: {\n        name: 'value',\n        type: 'string',\n        description: 'The value to fill in',\n        required: true,\n      },\n      includeSnapshot: {\n        name: 'includeSnapshot',\n        type: 'boolean',\n        description:\n          'Whether to include a snapshot in the response. Default is false.',\n        required: false,\n      },\n    },\n  },\n  get_console_message: {\n    description:\n      'Gets a console message by its ID. You can get all messages by calling list_console_messages.',\n    category: 'Debugging',\n    args: {\n      msgid: {\n        name: 'msgid',\n        type: 'number',\n        description:\n          'The msgid of a console message on the page from the listed console messages',\n        required: true,\n      },\n    },\n  },\n  get_network_request: {\n    description:\n      'Gets a network request by an optional reqid, if omitted returns the currently selected request in the DevTools Network panel.',\n    category: 'Network',\n    args: {\n      reqid: {\n        name: 'reqid',\n        type: 'number',\n        description:\n          'The reqid of the network request. If omitted returns the currently selected request in the DevTools Network panel.',\n        required: false,\n      },\n      requestFilePath: {\n        name: 'requestFilePath',\n        type: 'string',\n        description:\n          'The absolute or relative path to save the request body to. If omitted, the body is returned inline.',\n        required: false,\n      },\n      responseFilePath: {\n        name: 'responseFilePath',\n        type: 'string',\n        description:\n          'The absolute or relative path to save the response body to. If omitted, the body is returned inline.',\n        required: false,\n      },\n    },\n  },\n  handle_dialog: {\n    description:\n      'If a browser dialog was opened, use this command to handle it',\n    category: 'Input automation',\n    args: {\n      action: {\n        name: 'action',\n        type: 'string',\n        description: 'Whether to dismiss or accept the dialog',\n        required: true,\n        enum: ['accept', 'dismiss'],\n      },\n      promptText: {\n        name: 'promptText',\n        type: 'string',\n        description: 'Optional prompt text to enter into the dialog.',\n        required: false,\n      },\n    },\n  },\n  hover: {\n    description: 'Hover over the provided element',\n    category: 'Input automation',\n    args: {\n      uid: {\n        name: 'uid',\n        type: 'string',\n        description:\n          'The uid of an element on the page from the page content snapshot',\n        required: true,\n      },\n      includeSnapshot: {\n        name: 'includeSnapshot',\n        type: 'boolean',\n        description:\n          'Whether to include a snapshot in the response. Default is false.',\n        required: false,\n      },\n    },\n  },\n  lighthouse_audit: {\n    description:\n      'Get Lighthouse score and reports for accessibility, SEO and best practices. This excludes performance. For performance audits, run performance_start_trace',\n    category: 'Debugging',\n    args: {\n      mode: {\n        name: 'mode',\n        type: 'string',\n        description:\n          '\"navigation\" reloads & audits. \"snapshot\" analyzes current state.',\n        required: false,\n        default: 'navigation',\n        enum: ['navigation', 'snapshot'],\n      },\n      device: {\n        name: 'device',\n        type: 'string',\n        description: 'Device to emulate.',\n        required: false,\n        default: 'desktop',\n        enum: ['desktop', 'mobile'],\n      },\n      outputDirPath: {\n        name: 'outputDirPath',\n        type: 'string',\n        description: 'Directory for reports. If omitted, uses temporary files.',\n        required: false,\n      },\n    },\n  },\n  list_console_messages: {\n    description:\n      'List all console messages for the currently selected page since the last navigation.',\n    category: 'Debugging',\n    args: {\n      pageSize: {\n        name: 'pageSize',\n        type: 'integer',\n        description:\n          'Maximum number of messages to return. When omitted, returns all requests.',\n        required: false,\n      },\n      pageIdx: {\n        name: 'pageIdx',\n        type: 'integer',\n        description:\n          'Page number to return (0-based). When omitted, returns the first page.',\n        required: false,\n      },\n      types: {\n        name: 'types',\n        type: 'array',\n        description:\n          'Filter messages to only return messages of the specified resource types. When omitted or empty, returns all messages.',\n        required: false,\n      },\n      includePreservedMessages: {\n        name: 'includePreservedMessages',\n        type: 'boolean',\n        description:\n          'Set to true to return the preserved messages over the last 3 navigations.',\n        required: false,\n        default: false,\n      },\n    },\n  },\n  list_network_requests: {\n    description:\n      'List all requests for the currently selected page since the last navigation.',\n    category: 'Network',\n    args: {\n      pageSize: {\n        name: 'pageSize',\n        type: 'integer',\n        description:\n          'Maximum number of requests to return. When omitted, returns all requests.',\n        required: false,\n      },\n      pageIdx: {\n        name: 'pageIdx',\n        type: 'integer',\n        description:\n          'Page number to return (0-based). When omitted, returns the first page.',\n        required: false,\n      },\n      resourceTypes: {\n        name: 'resourceTypes',\n        type: 'array',\n        description:\n          'Filter requests to only return requests of the specified resource types. When omitted or empty, returns all requests.',\n        required: false,\n      },\n      includePreservedRequests: {\n        name: 'includePreservedRequests',\n        type: 'boolean',\n        description:\n          'Set to true to return the preserved requests over the last 3 navigations.',\n        required: false,\n        default: false,\n      },\n    },\n  },\n  list_pages: {\n    description: 'Get a list of pages  open in the browser.',\n    category: 'Navigation automation',\n    args: {},\n  },\n  navigate_page: {\n    description:\n      'Go to a URL, or back, forward, or reload. Use project URL if not specified otherwise.',\n    category: 'Navigation automation',\n    args: {\n      type: {\n        name: 'type',\n        type: 'string',\n        description:\n          'Navigate the page by URL, back or forward in history, or reload.',\n        required: false,\n        enum: ['url', 'back', 'forward', 'reload'],\n      },\n      url: {\n        name: 'url',\n        type: 'string',\n        description: 'Target URL (only type=url)',\n        required: false,\n      },\n      ignoreCache: {\n        name: 'ignoreCache',\n        type: 'boolean',\n        description: 'Whether to ignore cache on reload.',\n        required: false,\n      },\n      handleBeforeUnload: {\n        name: 'handleBeforeUnload',\n        type: 'string',\n        description:\n          'Whether to auto accept or beforeunload dialogs triggered by this navigation. Default is accept.',\n        required: false,\n        enum: ['accept', 'decline'],\n      },\n      initScript: {\n        name: 'initScript',\n        type: 'string',\n        description:\n          'A JavaScript script to be executed on each new document before any other scripts for the next navigation.',\n        required: false,\n      },\n      timeout: {\n        name: 'timeout',\n        type: 'integer',\n        description:\n          'Maximum wait time in milliseconds. If set to 0, the default timeout will be used.',\n        required: false,\n      },\n    },\n  },\n  new_page: {\n    description:\n      'Open a new tab and load a URL. Use project URL if not specified otherwise.',\n    category: 'Navigation automation',\n    args: {\n      url: {\n        name: 'url',\n        type: 'string',\n        description: 'URL to load in a new page.',\n        required: true,\n      },\n      background: {\n        name: 'background',\n        type: 'boolean',\n        description:\n          'Whether to open the page in the background without bringing it to the front. Default is false (foreground).',\n        required: false,\n      },\n      isolatedContext: {\n        name: 'isolatedContext',\n        type: 'string',\n        description:\n          'If specified, the page is created in an isolated browser context with the given name. Pages in the same browser context share cookies and storage. Pages in different browser contexts are fully isolated.',\n        required: false,\n      },\n      timeout: {\n        name: 'timeout',\n        type: 'integer',\n        description:\n          'Maximum wait time in milliseconds. If set to 0, the default timeout will be used.',\n        required: false,\n      },\n    },\n  },\n  performance_analyze_insight: {\n    description:\n      'Provides more detailed information on a specific Performance Insight of an insight set that was highlighted in the results of a trace recording.',\n    category: 'Performance',\n    args: {\n      insightSetId: {\n        name: 'insightSetId',\n        type: 'string',\n        description:\n          'The id for the specific insight set. Only use the ids given in the \"Available insight sets\" list.',\n        required: true,\n      },\n      insightName: {\n        name: 'insightName',\n        type: 'string',\n        description:\n          'The name of the Insight you want more information on. For example: \"DocumentLatency\" or \"LCPBreakdown\"',\n        required: true,\n      },\n    },\n  },\n  performance_start_trace: {\n    description:\n      'Start a performance trace on the selected webpage. Use to find frontend performance issues, Core Web Vitals (LCP, INP, CLS), and improve page load speed.',\n    category: 'Performance',\n    args: {\n      reload: {\n        name: 'reload',\n        type: 'boolean',\n        description:\n          'Determines if, once tracing has started, the current selected page should be automatically reloaded. Navigate the page to the right URL using the navigate_page tool BEFORE starting the trace if reload or autoStop is set to true.',\n        required: false,\n        default: true,\n      },\n      autoStop: {\n        name: 'autoStop',\n        type: 'boolean',\n        description:\n          'Determines if the trace recording should be automatically stopped.',\n        required: false,\n        default: true,\n      },\n      filePath: {\n        name: 'filePath',\n        type: 'string',\n        description:\n          'The absolute file path, or a file path relative to the current working directory, to save the raw trace data. For example, trace.json.gz (compressed) or trace.json (uncompressed).',\n        required: false,\n      },\n    },\n  },\n  performance_stop_trace: {\n    description:\n      'Stop the active performance trace recording on the selected webpage.',\n    category: 'Performance',\n    args: {\n      filePath: {\n        name: 'filePath',\n        type: 'string',\n        description:\n          'The absolute file path, or a file path relative to the current working directory, to save the raw trace data. For example, trace.json.gz (compressed) or trace.json (uncompressed).',\n        required: false,\n      },\n    },\n  },\n  press_key: {\n    description:\n      'Press a key or key combination. Use this when other input methods like fill() cannot be used (e.g., keyboard shortcuts, navigation keys, or special key combinations).',\n    category: 'Input automation',\n    args: {\n      key: {\n        name: 'key',\n        type: 'string',\n        description:\n          'A key or a combination (e.g., \"Enter\", \"Control+A\", \"Control++\", \"Control+Shift+R\"). Modifiers: Control, Shift, Alt, Meta',\n        required: true,\n      },\n      includeSnapshot: {\n        name: 'includeSnapshot',\n        type: 'boolean',\n        description:\n          'Whether to include a snapshot in the response. Default is false.',\n        required: false,\n      },\n    },\n  },\n  resize_page: {\n    description:\n      \"Resizes the selected page's window so that the page has specified dimension\",\n    category: 'Emulation',\n    args: {\n      width: {\n        name: 'width',\n        type: 'number',\n        description: 'Page width',\n        required: true,\n      },\n      height: {\n        name: 'height',\n        type: 'number',\n        description: 'Page height',\n        required: true,\n      },\n    },\n  },\n  select_page: {\n    description: 'Select a page as a context for future tool calls.',\n    category: 'Navigation automation',\n    args: {\n      pageId: {\n        name: 'pageId',\n        type: 'number',\n        description:\n          'The ID of the page to select. Call list_pages to get available pages.',\n        required: true,\n      },\n      bringToFront: {\n        name: 'bringToFront',\n        type: 'boolean',\n        description: 'Whether to focus the page and bring it to the top.',\n        required: false,\n      },\n    },\n  },\n  take_memory_snapshot: {\n    description:\n      'Capture a memory heapsnapshot of the currently selected page to memory leak debugging',\n    category: 'Performance',\n    args: {\n      filePath: {\n        name: 'filePath',\n        type: 'string',\n        description:\n          'A path to a .heapsnapshot file to save the heapsnapshot to.',\n        required: true,\n      },\n    },\n  },\n  take_screenshot: {\n    description: 'Take a screenshot of the page or element.',\n    category: 'Debugging',\n    args: {\n      format: {\n        name: 'format',\n        type: 'string',\n        description:\n          'Type of format to save the screenshot as. Default is \"png\"',\n        required: false,\n        default: 'png',\n        enum: ['png', 'jpeg', 'webp'],\n      },\n      quality: {\n        name: 'quality',\n        type: 'number',\n        description:\n          'Compression quality for JPEG and WebP formats (0-100). Higher values mean better quality but larger file sizes. Ignored for PNG format.',\n        required: false,\n      },\n      uid: {\n        name: 'uid',\n        type: 'string',\n        description:\n          'The uid of an element on the page from the page content snapshot. If omitted takes a pages screenshot.',\n        required: false,\n      },\n      fullPage: {\n        name: 'fullPage',\n        type: 'boolean',\n        description:\n          'If set to true takes a screenshot of the full page instead of the currently visible viewport. Incompatible with uid.',\n        required: false,\n      },\n      filePath: {\n        name: 'filePath',\n        type: 'string',\n        description:\n          'The absolute path, or a path relative to the current working directory, to save the screenshot to instead of attaching it to the response.',\n        required: false,\n      },\n    },\n  },\n  take_snapshot: {\n    description:\n      'Take a text snapshot of the currently selected page based on the a11y tree. The snapshot lists page elements along with a unique\\nidentifier (uid). Always use the latest snapshot. Prefer taking a snapshot over taking a screenshot. The snapshot indicates the element selected\\nin the DevTools Elements panel (if any).',\n    category: 'Debugging',\n    args: {\n      verbose: {\n        name: 'verbose',\n        type: 'boolean',\n        description:\n          'Whether to include all possible information available in the full a11y tree. Default is false.',\n        required: false,\n      },\n      filePath: {\n        name: 'filePath',\n        type: 'string',\n        description:\n          'The absolute path, or a path relative to the current working directory, to save the snapshot to instead of attaching it to the response.',\n        required: false,\n      },\n    },\n  },\n  type_text: {\n    description: 'Type text using keyboard into a previously focused input',\n    category: 'Input automation',\n    args: {\n      text: {\n        name: 'text',\n        type: 'string',\n        description: 'The text to type',\n        required: true,\n      },\n      submitKey: {\n        name: 'submitKey',\n        type: 'string',\n        description:\n          'Optional key to press after typing. E.g., \"Enter\", \"Tab\", \"Escape\"',\n        required: false,\n      },\n    },\n  },\n  upload_file: {\n    description: 'Upload a file through a provided element.',\n    category: 'Input automation',\n    args: {\n      uid: {\n        name: 'uid',\n        type: 'string',\n        description:\n          'The uid of the file input element or an element that will open file chooser on the page from the page content snapshot',\n        required: true,\n      },\n      filePath: {\n        name: 'filePath',\n        type: 'string',\n        description: 'The local path of the file to upload',\n        required: true,\n      },\n      includeSnapshot: {\n        name: 'includeSnapshot',\n        type: 'boolean',\n        description:\n          'Whether to include a snapshot in the response. Default is false.',\n        required: false,\n      },\n    },\n  },\n} as const;\n"
  },
  {
    "path": "src/browser.ts",
    "content": "/**\n * @license\n * Copyright 2025 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport {execSync} from 'node:child_process';\nimport fs from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\n\nimport {logger} from './logger.js';\nimport type {\n  Browser,\n  ChromeReleaseChannel,\n  LaunchOptions,\n  Target,\n} from './third_party/index.js';\nimport {puppeteer} from './third_party/index.js';\n\nlet browser: Browser | undefined;\n\nfunction makeTargetFilter(enableExtensions = false) {\n  const ignoredPrefixes = new Set(['chrome://', 'chrome-untrusted://']);\n  if (!enableExtensions) {\n    ignoredPrefixes.add('chrome-extension://');\n  }\n\n  return function targetFilter(target: Target): boolean {\n    if (target.url() === 'chrome://newtab/') {\n      return true;\n    }\n    // Could be the only page opened in the browser.\n    if (target.url().startsWith('chrome://inspect')) {\n      return true;\n    }\n    for (const prefix of ignoredPrefixes) {\n      if (target.url().startsWith(prefix)) {\n        return false;\n      }\n    }\n    return true;\n  };\n}\n\nexport async function ensureBrowserConnected(options: {\n  browserURL?: string;\n  wsEndpoint?: string;\n  wsHeaders?: Record<string, string>;\n  devtools: boolean;\n  channel?: Channel;\n  userDataDir?: string;\n  enableExtensions?: boolean;\n}) {\n  const {channel, enableExtensions} = options;\n  if (browser?.connected) {\n    return browser;\n  }\n\n  const connectOptions: Parameters<typeof puppeteer.connect>[0] = {\n    targetFilter: makeTargetFilter(enableExtensions),\n    defaultViewport: null,\n    handleDevToolsAsPage: true,\n  };\n\n  let autoConnect = false;\n  if (options.wsEndpoint) {\n    connectOptions.browserWSEndpoint = options.wsEndpoint;\n    if (options.wsHeaders) {\n      connectOptions.headers = options.wsHeaders;\n    }\n  } else if (options.browserURL) {\n    connectOptions.browserURL = options.browserURL;\n  } else if (channel || options.userDataDir) {\n    const userDataDir = options.userDataDir;\n    if (userDataDir) {\n      autoConnect = true;\n      // TODO: re-expose this logic via Puppeteer.\n      const portPath = path.join(userDataDir, 'DevToolsActivePort');\n      try {\n        const fileContent = await fs.promises.readFile(portPath, 'utf8');\n        const [rawPort, rawPath] = fileContent\n          .split('\\n')\n          .map(line => {\n            return line.trim();\n          })\n          .filter(line => {\n            return !!line;\n          });\n        if (!rawPort || !rawPath) {\n          throw new Error(`Invalid DevToolsActivePort '${fileContent}' found`);\n        }\n        const port = parseInt(rawPort, 10);\n        if (isNaN(port) || port <= 0 || port > 65535) {\n          throw new Error(`Invalid port '${rawPort}' found`);\n        }\n        const browserWSEndpoint = `ws://127.0.0.1:${port}${rawPath}`;\n        connectOptions.browserWSEndpoint = browserWSEndpoint;\n      } catch (error) {\n        throw new Error(\n          `Could not connect to Chrome in ${userDataDir}. Check if Chrome is running and remote debugging is enabled by going to chrome://inspect/#remote-debugging.`,\n          {\n            cause: error,\n          },\n        );\n      }\n    } else {\n      if (!channel) {\n        throw new Error('Channel must be provided if userDataDir is missing');\n      }\n      connectOptions.channel = (\n        channel === 'stable' ? 'chrome' : `chrome-${channel}`\n      ) as ChromeReleaseChannel;\n    }\n  } else {\n    throw new Error(\n      'Either browserURL, wsEndpoint, channel or userDataDir must be provided',\n    );\n  }\n\n  logger('Connecting Puppeteer to ', JSON.stringify(connectOptions));\n  try {\n    browser = await puppeteer.connect(connectOptions);\n  } catch (err) {\n    throw new Error(\n      `Could not connect to Chrome. ${autoConnect ? `Check if Chrome is running and remote debugging is enabled by going to chrome://inspect/#remote-debugging.` : `Check if Chrome is running.`}`,\n      {\n        cause: err,\n      },\n    );\n  }\n  logger('Connected Puppeteer');\n  return browser;\n}\n\ninterface McpLaunchOptions {\n  acceptInsecureCerts?: boolean;\n  executablePath?: string;\n  channel?: Channel;\n  userDataDir?: string;\n  headless: boolean;\n  isolated: boolean;\n  logFile?: fs.WriteStream;\n  viewport?: {\n    width: number;\n    height: number;\n  };\n  chromeArgs?: string[];\n  ignoreDefaultChromeArgs?: string[];\n  devtools: boolean;\n  enableExtensions?: boolean;\n  viaCli?: boolean;\n}\n\nexport function detectDisplay(): void {\n  // Only detect display on Linux/UNIX.\n  if (os.platform() === 'win32' || os.platform() === 'darwin') {\n    return;\n  }\n  if (!process.env['DISPLAY']) {\n    try {\n      const result = execSync(\n        `ps -u $(id -u) -o pid= | xargs -I{} cat /proc/{}/environ 2>/dev/null | tr '\\\\0' '\\\\n' | grep -m1 '^DISPLAY=' | cut -d= -f2`,\n      );\n      const display = result.toString('utf8').trim();\n      process.env['DISPLAY'] = display;\n    } catch {\n      // no-op\n    }\n  }\n}\n\nexport async function launch(options: McpLaunchOptions): Promise<Browser> {\n  const {channel, executablePath, headless, isolated} = options;\n  const profileDirName =\n    channel && channel !== 'stable'\n      ? `chrome-profile-${channel}`\n      : 'chrome-profile';\n\n  let userDataDir = options.userDataDir;\n  if (!isolated && !userDataDir) {\n    userDataDir = path.join(\n      os.homedir(),\n      '.cache',\n      options.viaCli ? 'chrome-devtools-mcp-cli' : 'chrome-devtools-mcp',\n      profileDirName,\n    );\n    await fs.promises.mkdir(userDataDir, {\n      recursive: true,\n    });\n  }\n\n  const args: LaunchOptions['args'] = [\n    ...(options.chromeArgs ?? []),\n    '--hide-crash-restore-bubble',\n  ];\n  const ignoreDefaultArgs: LaunchOptions['ignoreDefaultArgs'] =\n    options.ignoreDefaultChromeArgs ?? false;\n\n  if (headless) {\n    args.push('--screen-info={3840x2160}');\n  }\n  let puppeteerChannel: ChromeReleaseChannel | undefined;\n  if (options.devtools) {\n    args.push('--auto-open-devtools-for-tabs');\n  }\n  if (!executablePath) {\n    puppeteerChannel =\n      channel && channel !== 'stable'\n        ? (`chrome-${channel}` as ChromeReleaseChannel)\n        : 'chrome';\n  }\n\n  if (!headless) {\n    detectDisplay();\n  }\n\n  try {\n    const browser = await puppeteer.launch({\n      channel: puppeteerChannel,\n      targetFilter: makeTargetFilter(options.enableExtensions),\n      executablePath,\n      defaultViewport: null,\n      userDataDir,\n      pipe: true,\n      headless,\n      args,\n      ignoreDefaultArgs: ignoreDefaultArgs,\n      acceptInsecureCerts: options.acceptInsecureCerts,\n      handleDevToolsAsPage: true,\n      enableExtensions: options.enableExtensions,\n    });\n    if (options.logFile) {\n      // FIXME: we are probably subscribing too late to catch startup logs. We\n      // should expose the process earlier or expose the getRecentLogs() getter.\n      browser.process()?.stderr?.pipe(options.logFile);\n      browser.process()?.stdout?.pipe(options.logFile);\n    }\n    if (options.viewport) {\n      const [page] = await browser.pages();\n      await page?.resize({\n        contentWidth: options.viewport.width,\n        contentHeight: options.viewport.height,\n      });\n    }\n    return browser;\n  } catch (error) {\n    if (\n      userDataDir &&\n      (error as Error).message.includes('The browser is already running')\n    ) {\n      throw new Error(\n        `The browser is already running for ${userDataDir}. Use --isolated to run multiple browser instances.`,\n        {\n          cause: error,\n        },\n      );\n    }\n    throw error;\n  }\n}\n\nexport async function ensureBrowserLaunched(\n  options: McpLaunchOptions,\n): Promise<Browser> {\n  if (browser?.connected) {\n    return browser;\n  }\n  browser = await launch(options);\n  return browser;\n}\n\nexport type Channel = 'stable' | 'canary' | 'beta' | 'dev';\n"
  },
  {
    "path": "src/daemon/client.ts",
    "content": "/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport {spawn} from 'node:child_process';\nimport fs from 'node:fs';\nimport net from 'node:net';\n\nimport {logger} from '../logger.js';\nimport type {CallToolResult} from '../third_party/index.js';\nimport {PipeTransport} from '../third_party/index.js';\nimport {saveTemporaryFile} from '../utils/files.js';\n\nimport type {DaemonMessage, DaemonResponse} from './types.js';\nimport {\n  DAEMON_SCRIPT_PATH,\n  getSocketPath,\n  getPidFilePath,\n  isDaemonRunning,\n} from './utils.js';\n\nconst FILE_TIMEOUT = 10_000;\n\n/**\n * Waits for a file to be created and populated (removed = false) or removed (removed = true).\n */\nfunction waitForFile(filePath: string, removed = false) {\n  return new Promise<void>((resolve, reject) => {\n    const check = () => {\n      const exists = fs.existsSync(filePath);\n      if (removed) {\n        return !exists;\n      }\n      if (!exists) {\n        return false;\n      }\n      try {\n        return fs.statSync(filePath).size > 0;\n      } catch {\n        return false;\n      }\n    };\n\n    if (check()) {\n      resolve();\n      return;\n    }\n\n    const timer = setTimeout(() => {\n      fs.unwatchFile(filePath);\n      reject(\n        new Error(\n          `Timeout: file ${filePath} ${removed ? 'not removed' : 'not found'} within ${FILE_TIMEOUT}ms`,\n        ),\n      );\n    }, FILE_TIMEOUT);\n\n    fs.watchFile(filePath, {interval: 500}, () => {\n      if (check()) {\n        clearTimeout(timer);\n        fs.unwatchFile(filePath);\n        resolve();\n      }\n    });\n  });\n}\n\nexport async function startDaemon(mcpArgs: string[] = []) {\n  if (isDaemonRunning()) {\n    logger('Daemon is already running');\n    return;\n  }\n\n  const pidFilePath = getPidFilePath();\n\n  if (fs.existsSync(pidFilePath)) {\n    fs.unlinkSync(pidFilePath);\n  }\n\n  logger('Starting daemon...', ...mcpArgs);\n  const child = spawn(process.execPath, [DAEMON_SCRIPT_PATH, ...mcpArgs], {\n    detached: true,\n    stdio: 'ignore',\n    env: process.env,\n    cwd: process.cwd(),\n    windowsHide: true,\n  });\n  child.unref();\n\n  await waitForFile(pidFilePath);\n}\n\nconst SEND_COMMAND_TIMEOUT = 60_000; // ms\n\n/**\n * `sendCommand` opens a socket connection sends a single command and disconnects.\n */\nexport async function sendCommand(\n  command: DaemonMessage,\n): Promise<DaemonResponse> {\n  const socketPath = getSocketPath();\n\n  const socket = net.createConnection({\n    path: socketPath,\n  });\n\n  return new Promise((resolve, reject) => {\n    const timer = setTimeout(() => {\n      socket.destroy();\n      reject(new Error('Timeout waiting for daemon response'));\n    }, SEND_COMMAND_TIMEOUT);\n\n    const transport = new PipeTransport(socket, socket);\n    transport.onmessage = async (message: string) => {\n      clearTimeout(timer);\n      logger('onmessage', message);\n      resolve(JSON.parse(message));\n    };\n    socket.on('error', error => {\n      clearTimeout(timer);\n      logger('Socket error:', error);\n      reject(error);\n    });\n    socket.on('close', () => {\n      clearTimeout(timer);\n      logger('Socket closed:');\n      reject(new Error('Socket closed'));\n    });\n    logger('Sending message', command);\n    transport.send(JSON.stringify(command));\n  });\n}\n\nexport async function stopDaemon() {\n  if (!isDaemonRunning()) {\n    logger('Daemon is not running');\n    return;\n  }\n\n  const pidFilePath = getPidFilePath();\n\n  await sendCommand({method: 'stop'});\n\n  await waitForFile(pidFilePath, /*removed=*/ true);\n}\n\nexport async function handleResponse(\n  response: CallToolResult,\n  format: 'json' | 'md',\n): Promise<string> {\n  if (response.isError) {\n    return JSON.stringify(response.content);\n  }\n  if (format === 'json') {\n    if (response.structuredContent) {\n      return JSON.stringify(response.structuredContent);\n    }\n    // Fall-through to text for backward compatibility.\n  }\n  const chunks = [];\n  for (const content of response.content) {\n    if (content.type === 'text') {\n      chunks.push(content.text);\n    } else if (content.type === 'image') {\n      const imageData = content.data;\n      const mimeType = content.mimeType;\n      let extension = '.png';\n      switch (mimeType) {\n        case 'image/jpg':\n        case 'image/jpeg':\n          extension = '.jpeg';\n          break;\n        case 'webp':\n          extension = '.webp';\n          break;\n      }\n      const data = Buffer.from(imageData, 'base64');\n      const name = crypto.randomUUID();\n      const {filepath} = await saveTemporaryFile(data, `${name}${extension}`);\n      chunks.push(`Saved to ${filepath}.`);\n    } else {\n      throw new Error('Not supported response content type');\n    }\n  }\n  return format === 'md' ? chunks.join(' ') : JSON.stringify(chunks);\n}\n"
  },
  {
    "path": "src/daemon/daemon.ts",
    "content": "#!/usr/bin/env node\n\n/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport fs from 'node:fs';\nimport {createServer, type Server} from 'node:net';\nimport path from 'node:path';\nimport process from 'node:process';\n\nimport {logger} from '../logger.js';\nimport {\n  Client,\n  PipeTransport,\n  StdioClientTransport,\n} from '../third_party/index.js';\nimport {VERSION} from '../version.js';\n\nimport type {DaemonMessage} from './types.js';\nimport {\n  getDaemonPid,\n  getPidFilePath,\n  getSocketPath,\n  INDEX_SCRIPT_PATH,\n  IS_WINDOWS,\n  isDaemonRunning,\n} from './utils.js';\n\nconst pid = getDaemonPid();\nif (isDaemonRunning(pid)) {\n  logger('Another daemon process is running.');\n  process.exit(1);\n}\nconst pidFilePath = getPidFilePath();\nfs.mkdirSync(path.dirname(pidFilePath), {\n  recursive: true,\n});\nfs.writeFileSync(pidFilePath, process.pid.toString());\nlogger(`Writing ${process.pid.toString()} to ${pidFilePath}`);\n\nconst socketPath = getSocketPath();\n\nconst startDate = new Date();\nconst mcpServerArgs = process.argv.slice(2);\n\nlet mcpClient: Client | null = null;\nlet mcpTransport: StdioClientTransport | null = null;\nlet server: Server | null = null;\n\nasync function setupMCPClient() {\n  console.log('Setting up MCP client connection...');\n\n  // Create stdio transport for chrome-devtools-mcp\n  // Workaround for https://github.com/modelcontextprotocol/typescript-sdk/blob/v1.x/src/client/stdio.ts#L128\n  // which causes the console window to show on Windows.\n  // @ts-expect-error no types for type.\n  process.type = 'mcp-client';\n  mcpTransport = new StdioClientTransport({\n    command: process.execPath,\n    args: [INDEX_SCRIPT_PATH, ...mcpServerArgs],\n    env: process.env as Record<string, string>,\n  });\n  mcpClient = new Client(\n    {\n      name: 'chrome-devtools-cli-daemon',\n      version: VERSION,\n    },\n    {\n      capabilities: {},\n    },\n  );\n  await mcpClient.connect(mcpTransport);\n\n  console.log('MCP client connected');\n}\n\ninterface McpContent {\n  type: string;\n  text?: string;\n}\n\ninterface McpResult {\n  content?: McpContent[] | string;\n  text?: string;\n}\nasync function handleRequest(msg: DaemonMessage) {\n  try {\n    if (msg.method === 'invoke_tool') {\n      if (!mcpClient) {\n        throw new Error('MCP client not initialized');\n      }\n      const {tool, args} = msg;\n\n      const result = (await mcpClient.callTool({\n        name: tool,\n        arguments: args || {},\n      })) as McpResult | McpContent[];\n\n      return {\n        success: true,\n        result: JSON.stringify(result),\n      };\n    } else if (msg.method === 'stop') {\n      // Ensure we are not interrupting in-progress starting.\n      await started;\n      // Trigger cleanup asynchronously.\n      setImmediate(() => {\n        void cleanup();\n      });\n      return {\n        success: true,\n        message: 'stopping',\n      };\n    } else if (msg.method === 'status') {\n      return {\n        success: true,\n        result: JSON.stringify({\n          pid: process.pid,\n          socketPath,\n          startDate: startDate.toISOString(),\n          version: VERSION,\n          args: mcpServerArgs,\n        }),\n      };\n    }\n    {\n      return {\n        success: false,\n        error: `Unknown method: ${JSON.stringify(msg, null, 2)}`,\n      };\n    }\n  } catch (error: unknown) {\n    const errorMessage = error instanceof Error ? error.message : String(error);\n    return {\n      success: false,\n      error: errorMessage,\n    };\n  }\n}\n\nasync function startSocketServer() {\n  // Remove existing socket file if it exists (only on non-Windows)\n  if (!IS_WINDOWS) {\n    try {\n      fs.unlinkSync(socketPath);\n    } catch {\n      // ignore errors.\n    }\n  }\n\n  return await new Promise<void>((resolve, reject) => {\n    server = createServer(socket => {\n      const transport = new PipeTransport(socket, socket);\n      transport.onmessage = async (message: string) => {\n        logger('onmessage', message);\n        const response = await handleRequest(JSON.parse(message));\n        transport.send(JSON.stringify(response));\n        socket.end();\n      };\n      socket.on('error', error => {\n        logger('Socket error:', error);\n      });\n    });\n\n    server.listen(\n      {\n        path: socketPath,\n        readableAll: false,\n        writableAll: false,\n      },\n      async () => {\n        console.log(`Daemon server listening on ${socketPath}`);\n\n        try {\n          // Setup MCP client\n          await setupMCPClient();\n          resolve();\n        } catch (err) {\n          reject(err);\n        }\n      },\n    );\n\n    server.on('error', error => {\n      logger('Server error:', error);\n      reject(error);\n    });\n  });\n}\n\nasync function cleanup() {\n  console.log('Cleaning up daemon...');\n\n  try {\n    await mcpClient?.close();\n  } catch (error) {\n    logger('Error closing MCP client:', error);\n  }\n  try {\n    await mcpTransport?.close();\n  } catch (error) {\n    logger('Error closing MCP transport:', error);\n  }\n  if (server) {\n    await new Promise<void>(resolve => {\n      server!.close(() => resolve());\n    });\n  }\n  if (!IS_WINDOWS) {\n    try {\n      fs.unlinkSync(socketPath);\n    } catch {\n      // ignore errors\n    }\n  }\n  logger(`unlinking ${pidFilePath}`);\n  if (fs.existsSync(pidFilePath)) {\n    fs.unlinkSync(pidFilePath);\n  }\n  process.exit(0);\n}\n\n// Handle shutdown signals\nprocess.on('SIGTERM', () => {\n  void cleanup();\n});\nprocess.on('SIGINT', () => {\n  void cleanup();\n});\nprocess.on('SIGHUP', () => {\n  void cleanup();\n});\n\n// Handle uncaught errors\nprocess.on('uncaughtException', error => {\n  logger('Uncaught exception:', error);\n});\nprocess.on('unhandledRejection', error => {\n  logger('Unhandled rejection:', error);\n});\n\n// Start the server\nconst started = startSocketServer().catch(error => {\n  logger('Failed to start daemon server:', error);\n  process.exit(1);\n});\n"
  },
  {
    "path": "src/daemon/types.ts",
    "content": "/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nexport type DaemonMessage =\n  | {\n      method: 'stop';\n    }\n  | {\n      method: 'status';\n    }\n  | {\n      method: 'invoke_tool';\n      tool: string;\n      args?: Record<string, unknown>;\n    };\n\nexport interface DaemonResponse {\n  success: boolean;\n  // Stringified CallToolResult.\n  result: string;\n  error: unknown;\n}\n"
  },
  {
    "path": "src/daemon/utils.ts",
    "content": "/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport fs from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\nimport process from 'node:process';\n\nimport {logger} from '../logger.js';\nimport type {YargsOptions} from '../third_party/index.js';\n\nexport const DAEMON_SCRIPT_PATH = path.join(import.meta.dirname, 'daemon.js');\nexport const INDEX_SCRIPT_PATH = path.join(\n  import.meta.dirname,\n  '..',\n  'bin',\n  'chrome-devtools-mcp.js',\n);\n\nconst APP_NAME = 'chrome-devtools-mcp';\n\n// Using these paths due to strict limits on the POSIX socket path length.\nexport function getSocketPath(): string {\n  const uid = os.userInfo().uid;\n\n  if (IS_WINDOWS) {\n    // Windows uses Named Pipes, not file paths.\n    // This format is required for server.listen()\n    return path.join('\\\\\\\\.\\\\pipe', APP_NAME, 'server.sock');\n  }\n\n  // 1. Try XDG_RUNTIME_DIR (Linux standard, sometimes macOS)\n  if (process.env.XDG_RUNTIME_DIR) {\n    return path.join(process.env.XDG_RUNTIME_DIR, APP_NAME, 'server.sock');\n  }\n\n  // 2. macOS/Unix Fallback: Use /tmp/\n  // We use /tmp/ because it is much shorter than ~/Library/Application Support/\n  // and keeps us well under the 104-character limit.\n  return path.join('/tmp', `${APP_NAME}-${uid}.sock`);\n}\n\nexport function getRuntimeHome(): string {\n  const platform = os.platform();\n  const uid = os.userInfo().uid;\n\n  // 1. Check for the modern Unix standard\n  if (process.env.XDG_RUNTIME_DIR) {\n    return path.join(process.env.XDG_RUNTIME_DIR, APP_NAME);\n  }\n\n  // 2. Fallback for macOS and older Linux\n  if (platform === 'darwin' || platform === 'linux') {\n    // /tmp is cleared on boot, making it perfect for PIDs\n    return path.join('/tmp', `${APP_NAME}-${uid}`);\n  }\n\n  // 3. Windows Fallback\n  return path.join(os.tmpdir(), APP_NAME);\n}\n\nexport const IS_WINDOWS = os.platform() === 'win32';\n\nexport function getPidFilePath() {\n  const runtimeDir = getRuntimeHome();\n  return path.join(runtimeDir, 'daemon.pid');\n}\n\nexport function getDaemonPid() {\n  try {\n    const pidFile = getPidFilePath();\n    logger(`Daemon pid file ${pidFile}`);\n    if (!fs.existsSync(pidFile)) {\n      return null;\n    }\n    const pidContent = fs.readFileSync(pidFile, 'utf-8');\n    const pid = parseInt(pidContent.trim(), 10);\n    logger(`Daemon pid: ${pid}`);\n    if (isNaN(pid)) {\n      return null;\n    }\n    return pid;\n  } catch {\n    return null;\n  }\n}\n\nexport function isDaemonRunning(pid = getDaemonPid()): pid is number {\n  if (pid) {\n    try {\n      process.kill(pid, 0); // Throws if process doesn't exist\n      return true;\n    } catch {\n      // Process is dead, stale PID file. Proceed with startup.\n    }\n  }\n  return false;\n}\n\nexport function serializeArgs(\n  options: Record<string, YargsOptions>,\n  argv: Record<string, unknown>,\n): string[] {\n  const args: string[] = [];\n  for (const key of Object.keys(options)) {\n    if (argv[key] === undefined || argv[key] === null) {\n      continue;\n    }\n    const value = argv[key];\n    const kebabKey = key.replace(/[A-Z]/g, m => `-${m.toLowerCase()}`);\n\n    if (typeof value === 'boolean') {\n      if (value) {\n        args.push(`--${kebabKey}`);\n      } else {\n        args.push(`--no-${kebabKey}`);\n      }\n    } else if (Array.isArray(value)) {\n      for (const item of value) {\n        args.push(`--${kebabKey}`, String(item));\n      }\n    } else {\n      args.push(`--${kebabKey}`, String(value));\n    }\n  }\n  return args;\n}\n"
  },
  {
    "path": "src/devtools.d.ts",
    "content": "/**\n * @license\n * Copyright 2025 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\ntype CSSInJS = string & {_tag: 'CSS-in-JS'};\ndeclare module '*.css.js' {\n  const styles: CSSInJS;\n  export default styles;\n}\n"
  },
  {
    "path": "src/formatters/ConsoleFormatter.ts",
    "content": "/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport {\n  createStackTraceForConsoleMessage,\n  type TargetUniverse,\n  SymbolizedError,\n} from '../DevtoolsUtils.js';\nimport {UncaughtError} from '../PageCollector.js';\nimport * as DevTools from '../third_party/index.js';\nimport type {ConsoleMessage} from '../third_party/index.js';\n\nexport interface ConsoleFormatterOptions {\n  fetchDetailedData?: boolean;\n  id: number;\n  devTools?: TargetUniverse;\n  resolvedArgsForTesting?: unknown[];\n  resolvedStackTraceForTesting?: DevTools.DevTools.StackTrace.StackTrace.StackTrace;\n  resolvedCauseForTesting?: SymbolizedError;\n  isIgnoredForTesting?: IgnoreCheck;\n}\n\nexport type IgnoreCheck = (\n  frame: DevTools.DevTools.StackTrace.StackTrace.Frame,\n) => boolean;\n\ninterface ConsoleMessageConcise {\n  type: string;\n  text: string;\n  argsCount: number;\n  id: number;\n}\n\ninterface ConsoleMessageDetailed extends ConsoleMessageConcise {\n  // pre-formatted args.\n  args: string[];\n  // pre-formatted stacktrace.\n  stackTrace?: string;\n}\n\nexport class ConsoleFormatter {\n  readonly #id: number;\n  readonly #type: string;\n  readonly #text: string;\n\n  readonly #argCount: number;\n  readonly #resolvedArgs: unknown[];\n\n  readonly #stack?: DevTools.DevTools.StackTrace.StackTrace.StackTrace;\n  readonly #cause?: SymbolizedError;\n\n  readonly isIgnored: IgnoreCheck;\n\n  private constructor(params: {\n    id: number;\n    type: string;\n    text: string;\n    argCount?: number;\n    resolvedArgs?: unknown[];\n    stack?: DevTools.DevTools.StackTrace.StackTrace.StackTrace;\n    cause?: SymbolizedError;\n    isIgnored: IgnoreCheck;\n  }) {\n    this.#id = params.id;\n    this.#type = params.type;\n    this.#text = params.text;\n    this.#argCount = params.argCount ?? 0;\n    this.#resolvedArgs = params.resolvedArgs ?? [];\n    this.#stack = params.stack;\n    this.#cause = params.cause;\n    this.isIgnored = params.isIgnored;\n  }\n\n  static async from(\n    msg: ConsoleMessage | UncaughtError,\n    options: ConsoleFormatterOptions,\n  ): Promise<ConsoleFormatter> {\n    const ignoreListManager = options?.devTools?.universe.context.get(\n      DevTools.DevTools.IgnoreListManager,\n    );\n    const isIgnored: IgnoreCheck =\n      options.isIgnoredForTesting ||\n      (frame => {\n        if (!ignoreListManager) {\n          return false;\n        }\n        if (frame.uiSourceCode) {\n          return ignoreListManager.isUserOrSourceMapIgnoreListedUISourceCode(\n            frame.uiSourceCode,\n          );\n        }\n        if (frame.url) {\n          return ignoreListManager.isUserIgnoreListedURL(\n            frame.url as Parameters<\n              DevTools.DevTools.IgnoreListManager['isUserIgnoreListedURL']\n            >[0],\n          );\n        }\n        return false;\n      });\n\n    if (msg instanceof UncaughtError) {\n      const error = await SymbolizedError.fromDetails({\n        devTools: options?.devTools,\n        details: msg.details,\n        targetId: msg.targetId,\n        includeStackAndCause: options?.fetchDetailedData,\n        resolvedStackTraceForTesting: options?.resolvedStackTraceForTesting,\n        resolvedCauseForTesting: options?.resolvedCauseForTesting,\n      });\n      return new ConsoleFormatter({\n        id: options.id,\n        type: 'error',\n        text: error.message,\n        stack: error.stackTrace,\n        cause: error.cause,\n        isIgnored,\n      });\n    }\n\n    let resolvedArgs: unknown[] = [];\n    if (options.resolvedArgsForTesting) {\n      resolvedArgs = options.resolvedArgsForTesting;\n    } else if (options.fetchDetailedData) {\n      resolvedArgs = await Promise.all(\n        msg.args().map(async (arg, i) => {\n          try {\n            const remoteObject = arg.remoteObject();\n            if (\n              remoteObject.type === 'object' &&\n              remoteObject.subtype === 'error'\n            ) {\n              return await SymbolizedError.fromError({\n                devTools: options.devTools,\n                error: remoteObject,\n                // @ts-expect-error Internal ConsoleMessage API\n                targetId: msg._targetId(),\n              });\n            }\n            return await arg.jsonValue();\n          } catch {\n            return `<error: Argument ${i} is no longer available>`;\n          }\n        }),\n      );\n    }\n\n    let stack: DevTools.DevTools.StackTrace.StackTrace.StackTrace | undefined;\n    if (options.resolvedStackTraceForTesting) {\n      stack = options.resolvedStackTraceForTesting;\n    } else if (options.fetchDetailedData && options.devTools) {\n      try {\n        stack = await createStackTraceForConsoleMessage(options.devTools, msg);\n      } catch {\n        // ignore\n      }\n    }\n\n    return new ConsoleFormatter({\n      id: options.id,\n      type: msg.type(),\n      text: msg.text(),\n      argCount: resolvedArgs.length || msg.args().length,\n      resolvedArgs,\n      stack,\n      isIgnored,\n    });\n  }\n\n  // The short format for a console message.\n  toString(): string {\n    return convertConsoleMessageConciseToString(this.toJSON());\n  }\n\n  // The verbose format for a console message, including all details.\n  toStringDetailed(): string {\n    return convertConsoleMessageConciseDetailedToString(this.toJSONDetailed());\n  }\n\n  #getArgs(): unknown[] {\n    if (this.#resolvedArgs.length > 0) {\n      const args = [...this.#resolvedArgs];\n      // If there is no text, the first argument serves as text (see formatMessage).\n      if (!this.#text) {\n        args.shift();\n      }\n      return args;\n    }\n    return [];\n  }\n\n  toJSON(): ConsoleMessageConcise {\n    return {\n      type: this.#type,\n      text: this.#text,\n      argsCount: this.#argCount,\n      id: this.#id,\n    };\n  }\n\n  toJSONDetailed(): ConsoleMessageDetailed {\n    return {\n      id: this.#id,\n      type: this.#type,\n      text: this.#text,\n      argsCount: this.#argCount,\n      args: this.#getArgs().map(arg => formatArg(arg, this)),\n      stackTrace: this.#stack\n        ? formatStackTrace(this.#stack, this.#cause, this)\n        : undefined,\n    };\n  }\n}\n\nfunction convertConsoleMessageConciseToString(msg: ConsoleMessageConcise) {\n  return `msgid=${msg.id} [${msg.type}] ${msg.text} (${msg.argsCount} args)`;\n}\n\nfunction convertConsoleMessageConciseDetailedToString(\n  msg: ConsoleMessageDetailed,\n) {\n  const result = [\n    `ID: ${msg.id}`,\n    `Message: ${msg.type}> ${msg.text}`,\n    formatArgs(msg),\n    ...(msg.stackTrace ? ['### Stack trace', msg.stackTrace] : []),\n  ].filter(line => !!line);\n  return result.join('\\n');\n}\n\nfunction formatArgs(msg: ConsoleMessageDetailed): string {\n  const args = msg.args;\n\n  if (!args.length) {\n    return '';\n  }\n\n  const result = ['### Arguments'];\n\n  for (const [key, arg] of args.entries()) {\n    result.push(`Arg #${key}: ${arg}`);\n  }\n\n  return result.join('\\n');\n}\n\nfunction formatArg(arg: unknown, formatter: {isIgnored: IgnoreCheck}) {\n  if (arg instanceof SymbolizedError) {\n    return [\n      arg.message,\n      arg.stackTrace\n        ? formatStackTrace(arg.stackTrace, arg.cause, formatter)\n        : undefined,\n    ]\n      .filter(line => !!line)\n      .join('\\n');\n  }\n  return typeof arg === 'object' ? JSON.stringify(arg) : String(arg);\n}\n\nconst STACK_TRACE_MAX_LINES = 50;\n\nfunction formatStackTrace(\n  stackTrace: DevTools.DevTools.StackTrace.StackTrace.StackTrace,\n  cause: SymbolizedError | undefined,\n  formatter: {isIgnored: IgnoreCheck},\n): string {\n  const lines = formatStackTraceInner(stackTrace, cause, formatter);\n  const includedLines = lines.slice(0, STACK_TRACE_MAX_LINES);\n  const reminderCount = lines.length - includedLines.length;\n\n  return [\n    ...includedLines,\n    reminderCount > 0 ? `... and ${reminderCount} more frames` : '',\n    'Note: line and column numbers use 1-based indexing',\n  ]\n    .filter(line => !!line)\n    .join('\\n');\n}\n\nfunction formatStackTraceInner(\n  stackTrace: DevTools.DevTools.StackTrace.StackTrace.StackTrace | undefined,\n  cause: SymbolizedError | undefined,\n  formatter: {isIgnored: IgnoreCheck},\n): string[] {\n  if (!stackTrace) {\n    return [];\n  }\n\n  return [\n    ...formatFragment(stackTrace.syncFragment, formatter),\n    ...stackTrace.asyncFragments\n      .map(item => formatAsyncFragment(item, formatter))\n      .flat(),\n    ...formatCause(cause, formatter),\n  ];\n}\n\nfunction formatFragment(\n  fragment: DevTools.DevTools.StackTrace.StackTrace.Fragment,\n  formatter: {isIgnored: IgnoreCheck},\n): string[] {\n  const frames = fragment.frames.filter(frame => !formatter.isIgnored(frame));\n  return frames.map(formatFrame);\n}\n\nfunction formatAsyncFragment(\n  fragment: DevTools.DevTools.StackTrace.StackTrace.AsyncFragment,\n  formatter: {isIgnored: IgnoreCheck},\n): string[] {\n  const formattedFrames = formatFragment(fragment, formatter);\n  if (formattedFrames.length === 0) {\n    return [];\n  }\n\n  const separatorLineLength = 40;\n  const prefix = `--- ${fragment.description || 'async'} `;\n  const separator = prefix + '-'.repeat(separatorLineLength - prefix.length);\n  return [separator, ...formattedFrames];\n}\n\nfunction formatFrame(\n  frame: DevTools.DevTools.StackTrace.StackTrace.Frame,\n): string {\n  let result = `at ${frame.name ?? '<anonymous>'}`;\n  if (frame.uiSourceCode) {\n    const location = frame.uiSourceCode.uiLocation(frame.line, frame.column);\n    result += ` (${location.linkText(/* skipTrim */ false, /* showColumnNumber */ true)})`;\n  } else if (frame.url) {\n    result += ` (${frame.url}:${frame.line}:${frame.column})`;\n  }\n  return result;\n}\n\nfunction formatCause(\n  cause: SymbolizedError | undefined,\n  formatter: {isIgnored: IgnoreCheck},\n): string[] {\n  if (!cause) {\n    return [];\n  }\n\n  return [\n    `Caused by: ${cause.message}`,\n    ...formatStackTraceInner(cause.stackTrace, cause.cause, formatter),\n  ];\n}\n"
  },
  {
    "path": "src/formatters/IssueFormatter.ts",
    "content": "/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport {ISSUE_UTILS} from '../issue-descriptions.js';\nimport {logger} from '../logger.js';\nimport {DevTools} from '../third_party/index.js';\n\nexport interface IssueFormatterOptions {\n  requestIdResolver?: (requestId: string) => number | undefined;\n  elementIdResolver?: (backendNodeId: number) => string | undefined;\n  id: number;\n}\n\nexport interface AffectedResource {\n  uid?: string;\n  data?: unknown;\n  request?: string | number;\n}\n\ninterface IssueConcise {\n  type: 'issue';\n  title?: string;\n  count: number;\n  id: number;\n}\n\ninterface IssueDetailed extends IssueConcise {\n  description?: string;\n  links?: Array<{\n    link: string;\n    linkTitle: string;\n  }>;\n  affectedResources: AffectedResource[];\n}\n\nexport class IssueFormatter {\n  #issue: DevTools.AggregatedIssue;\n  #options: IssueFormatterOptions;\n\n  constructor(issue: DevTools.AggregatedIssue, options: IssueFormatterOptions) {\n    this.#issue = issue;\n    this.#options = options;\n  }\n\n  toString(): string {\n    return convertIssueConciseToString(this.toJSON());\n  }\n\n  toStringDetailed(): string {\n    return convertIssueDetailedToString(this.toJSONDetailed());\n  }\n\n  toJSON(): IssueConcise {\n    return {\n      type: 'issue',\n      title: this.#getTitle(),\n      count: this.#issue.getAggregatedIssuesCount(),\n      id: this.#options.id,\n    };\n  }\n\n  toJSONDetailed(): IssueDetailed {\n    return {\n      id: this.#options.id,\n      type: 'issue',\n      count: this.#issue.getAggregatedIssuesCount(),\n      title: this.#getTitle(),\n      description: this.#getDescription(),\n      links: this.#issue.getDescription()?.links,\n      affectedResources: this.#getAffectedResources(),\n    };\n  }\n\n  #getAffectedResources(): AffectedResource[] {\n    const issues = this.#issue.getAllIssues();\n    const affectedResources: Array<{\n      uid?: string;\n      data?: object;\n      request?: string | number;\n    }> = [];\n    for (const singleIssue of issues) {\n      const details = singleIssue.details();\n      if (!details) {\n        continue;\n      }\n\n      // We send the remaining details as untyped JSON because the DevTools\n      // frontend code is currently not re-usable.\n      const data = structuredClone(details) as unknown as Record<\n        string,\n        unknown\n      >;\n\n      let uid;\n      let request: number | string | undefined;\n      if (\n        'violatingNodeId' in details &&\n        details.violatingNodeId &&\n        this.#options.elementIdResolver\n      ) {\n        uid = this.#options.elementIdResolver(details.violatingNodeId);\n        delete data.violatingNodeId;\n      }\n      if (\n        'nodeId' in details &&\n        details.nodeId &&\n        this.#options.elementIdResolver\n      ) {\n        uid = this.#options.elementIdResolver(details.nodeId);\n        delete data.nodeId;\n      }\n      if (\n        'documentNodeId' in details &&\n        details.documentNodeId &&\n        this.#options.elementIdResolver\n      ) {\n        uid = this.#options.elementIdResolver(details.documentNodeId);\n        delete data.documentNodeId;\n      }\n\n      if ('request' in details && details.request) {\n        request = details.request.url;\n        if (details.request.requestId && this.#options.requestIdResolver) {\n          const resolvedId = this.#options.requestIdResolver(\n            details.request.requestId,\n          );\n          if (resolvedId) {\n            request = resolvedId;\n            const requestData = data.request as Record<string, unknown>;\n            delete requestData.requestId;\n          }\n        }\n      }\n\n      // These fields has no use for the MCP client (redundant or irrelevant).\n      delete data.errorType;\n      delete data.frameId;\n      affectedResources.push({\n        uid,\n        data: data,\n        request,\n      });\n    }\n    return affectedResources;\n  }\n\n  isValid(): boolean {\n    return this.#getTitle() !== undefined;\n  }\n\n  // Helper to extract title\n  #getTitle(): string | undefined {\n    const markdownDescription = this.#issue.getDescription();\n    const filename = markdownDescription?.file;\n    if (!filename) {\n      logger(`no description found for issue:` + this.#issue.code());\n      return undefined;\n    }\n\n    // We already have the description logic in #getDescription, but title extraction is separate\n    // We can reuse the logic or cache it.\n    // Ideally we should process markdown once.\n\n    const rawMarkdown = ISSUE_UTILS.getIssueDescription(filename);\n    if (!rawMarkdown) {\n      logger(`no markdown ${filename} found for issue:` + this.#issue.code());\n      return undefined;\n    }\n\n    try {\n      const processedMarkdown =\n        DevTools.MarkdownIssueDescription.substitutePlaceholders(\n          rawMarkdown,\n          markdownDescription?.substitutions,\n        );\n      const markdownAst = DevTools.Marked.Marked.lexer(processedMarkdown);\n      const title =\n        DevTools.MarkdownIssueDescription.findTitleFromMarkdownAst(markdownAst);\n      if (!title) {\n        logger('cannot read issue title from ' + filename);\n        return undefined;\n      }\n      return title;\n    } catch {\n      logger('error parsing markdown for issue ' + this.#issue.code());\n      return undefined;\n    }\n  }\n\n  #getDescription(): string | undefined {\n    const markdownDescription = this.#issue.getDescription();\n    const filename = markdownDescription?.file;\n    if (!filename) {\n      return undefined;\n    }\n\n    const rawMarkdown = ISSUE_UTILS.getIssueDescription(filename);\n    if (!rawMarkdown) {\n      return undefined;\n    }\n\n    try {\n      return DevTools.MarkdownIssueDescription.substitutePlaceholders(\n        rawMarkdown,\n        markdownDescription?.substitutions,\n      );\n    } catch {\n      return undefined;\n    }\n  }\n}\n\nfunction convertIssueConciseToString(issue: IssueConcise): string {\n  return `msgid=${issue.id} [issue] ${issue.title} (count: ${issue.count})`;\n}\n\nfunction convertIssueDetailedToString(issue: IssueDetailed): string {\n  const result: string[] = [];\n  result.push(`ID: ${issue.id}`);\n\n  const bodyParts: string[] = [];\n\n  const description = issue.description;\n  let processedMarkdown = description?.trim();\n  // Remove heading in order not to conflict with the whole console message response markdown\n  if (processedMarkdown?.startsWith('# ')) {\n    processedMarkdown = processedMarkdown.substring(2).trimStart();\n  }\n  if (processedMarkdown) {\n    bodyParts.push(processedMarkdown);\n  } else {\n    bodyParts.push(issue.title ?? 'Unknown Issue');\n  }\n\n  const links = issue.links;\n  if (links && links.length > 0) {\n    bodyParts.push('Learn more:');\n    for (const link of links) {\n      bodyParts.push(`[${link.linkTitle}](${link.link})`);\n    }\n  }\n\n  const affectedResources = issue.affectedResources;\n  if (affectedResources.length) {\n    bodyParts.push('### Affected resources');\n    bodyParts.push(\n      ...affectedResources.map(item => {\n        const details = [];\n        if (item.uid) {\n          details.push(`uid=${item.uid}`);\n        }\n        if (item.request) {\n          details.push(\n            (typeof item.request === 'number' ? `reqid=` : 'url=') +\n              item.request,\n          );\n        }\n        if (item.data) {\n          details.push(`data=${JSON.stringify(item.data)}`);\n        }\n        return details.join(' ');\n      }),\n    );\n  }\n\n  result.push(`Message: issue> ${bodyParts.join('\\n')}`);\n\n  return result.join('\\n');\n}\n"
  },
  {
    "path": "src/formatters/NetworkFormatter.ts",
    "content": "/**\n * @license\n * Copyright 2025 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n * */\n\nimport {isUtf8} from 'node:buffer';\n\nimport type {HTTPRequest, HTTPResponse} from '../third_party/index.js';\n\nconst BODY_CONTEXT_SIZE_LIMIT = 10000;\n\nexport interface NetworkFormatterOptions {\n  requestId?: number | string;\n  selectedInDevToolsUI?: boolean;\n  requestIdResolver?: (request: HTTPRequest) => number | string;\n  fetchData?: boolean;\n  requestFilePath?: string;\n  responseFilePath?: string;\n  saveFile?: (\n    data: Uint8Array<ArrayBufferLike>,\n    filename: string,\n  ) => Promise<{filename: string}>;\n}\n\ninterface NetworkRequestConcise {\n  requestId?: number | string;\n  method: string;\n  url: string;\n  status: string;\n  selectedInDevToolsUI?: boolean;\n}\n\ninterface NetworkRequestDetailed extends NetworkRequestConcise {\n  requestHeaders: Record<string, string>;\n  requestBody?: string;\n  requestBodyFilePath?: string;\n  responseHeaders?: Record<string, string>;\n  responseBody?: string;\n  responseBodyFilePath?: string;\n  failure?: string;\n  redirectChain?: NetworkRequestConcise[];\n}\n\nexport class NetworkFormatter {\n  #request: HTTPRequest;\n  #options: NetworkFormatterOptions;\n  #requestBody?: string;\n  #responseBody?: string;\n  #requestBodyFilePath?: string;\n  #responseBodyFilePath?: string;\n\n  private constructor(request: HTTPRequest, options: NetworkFormatterOptions) {\n    this.#request = request;\n    this.#options = options;\n  }\n\n  static async from(\n    request: HTTPRequest,\n    options: NetworkFormatterOptions,\n  ): Promise<NetworkFormatter> {\n    const instance = new NetworkFormatter(request, options);\n    if (options.fetchData) {\n      await instance.#loadDetailedData();\n    }\n    return instance;\n  }\n\n  async #loadDetailedData(): Promise<void> {\n    // Load Request Body\n    if (this.#request.hasPostData()) {\n      let data;\n      try {\n        data =\n          this.#request.postData() ?? (await this.#request.fetchPostData());\n      } catch {\n        // Ignore parsing errors\n      }\n      const requestBodyNotAvailableMessage =\n        '<Request body not available anymore>';\n      if (this.#options.requestFilePath) {\n        if (!this.#options.saveFile) {\n          throw new Error('saveFile is not provided');\n        }\n        if (data) {\n          await this.#options.saveFile(\n            Buffer.from(data),\n            this.#options.requestFilePath,\n          );\n          this.#requestBodyFilePath = this.#options.requestFilePath;\n        } else {\n          this.#requestBody = requestBodyNotAvailableMessage;\n        }\n      } else {\n        if (data) {\n          this.#requestBody = getSizeLimitedString(\n            data,\n            BODY_CONTEXT_SIZE_LIMIT,\n          );\n        } else {\n          this.#requestBody = requestBodyNotAvailableMessage;\n        }\n      }\n    }\n\n    // Load Response Body\n    const response = this.#request.response();\n    if (response) {\n      const responseBodyNotAvailableMessage =\n        '<Response body not available anymore>';\n      if (this.#options.responseFilePath) {\n        try {\n          const buffer = await response.buffer();\n          if (!this.#options.saveFile) {\n            throw new Error('saveFile is not provided');\n          }\n          await this.#options.saveFile(buffer, this.#options.responseFilePath);\n          this.#responseBodyFilePath = this.#options.responseFilePath;\n        } catch {\n          // Flatten error handling for buffer() failure and save failure\n        }\n\n        if (!this.#responseBodyFilePath) {\n          this.#responseBody = responseBodyNotAvailableMessage;\n        }\n      } else {\n        this.#responseBody = await this.#getFormattedResponseBody(\n          response,\n          BODY_CONTEXT_SIZE_LIMIT,\n        );\n      }\n    }\n  }\n\n  toString(): string {\n    return convertNetworkRequestConciseToString(this.toJSON());\n  }\n\n  toStringDetailed(): string {\n    return converNetworkRequestDetailedToStringDetailed(this.toJSONDetailed());\n  }\n\n  toJSON(): NetworkRequestConcise {\n    return {\n      requestId: this.#options.requestId,\n      method: this.#request.method(),\n      url: this.#request.url(),\n      status: this.#getStatusFromRequest(this.#request),\n      selectedInDevToolsUI: this.#options.selectedInDevToolsUI,\n    };\n  }\n\n  toJSONDetailed(): NetworkRequestDetailed {\n    const redirectChain = this.#request.redirectChain();\n    const formattedRedirectChain = redirectChain.reverse().map(request => {\n      const id = this.#options.requestIdResolver\n        ? this.#options.requestIdResolver(request)\n        : undefined;\n      const formatter = new NetworkFormatter(request, {\n        requestId: id,\n        saveFile: this.#options.saveFile,\n      });\n      return formatter.toJSON();\n    });\n\n    return {\n      ...this.toJSON(),\n      requestHeaders: this.#request.headers(),\n      requestBody: this.#requestBody,\n      requestBodyFilePath: this.#requestBodyFilePath,\n      responseHeaders: this.#request.response()?.headers(),\n      responseBody: this.#responseBody,\n      responseBodyFilePath: this.#responseBodyFilePath,\n      failure: this.#request.failure()?.errorText,\n      redirectChain: formattedRedirectChain.length\n        ? formattedRedirectChain\n        : undefined,\n    };\n  }\n\n  #getStatusFromRequest(request: HTTPRequest): string {\n    const httpResponse = request.response();\n    const failure = request.failure();\n    let status: string;\n    if (httpResponse) {\n      status = httpResponse.status().toString();\n    } else if (failure) {\n      status = failure.errorText;\n    } else {\n      status = 'pending';\n    }\n    return status;\n  }\n\n  async #getFormattedResponseBody(\n    httpResponse: HTTPResponse,\n    sizeLimit = BODY_CONTEXT_SIZE_LIMIT,\n  ): Promise<string | undefined> {\n    try {\n      const responseBuffer = await httpResponse.buffer();\n\n      if (isUtf8(responseBuffer)) {\n        const responseAsTest = responseBuffer.toString('utf-8');\n\n        if (responseAsTest.length === 0) {\n          return '<empty response>';\n        }\n\n        return getSizeLimitedString(responseAsTest, sizeLimit);\n      }\n\n      return '<binary data>';\n    } catch {\n      return '<not available anymore>';\n    }\n  }\n}\n\nfunction getSizeLimitedString(text: string, sizeLimit: number) {\n  if (text.length > sizeLimit) {\n    return text.substring(0, sizeLimit) + '... <truncated>';\n  }\n  return text;\n}\n\nfunction convertNetworkRequestConciseToString(\n  data: NetworkRequestConcise,\n): string {\n  // TODO truncate the URL\n  return `reqid=${data.requestId} ${data.method} ${data.url} [${data.status}]${data.selectedInDevToolsUI ? ` [selected in the DevTools Network panel]` : ''}`;\n}\n\nfunction formatHeadlers(headers: Record<string, string>): string[] {\n  const response: string[] = [];\n  for (const [name, value] of Object.entries(headers)) {\n    response.push(`- ${name}:${value}`);\n  }\n  return response;\n}\n\nfunction converNetworkRequestDetailedToStringDetailed(\n  data: NetworkRequestDetailed,\n): string {\n  const response: string[] = [];\n  response.push(`## Request ${data.url}`);\n  response.push(`Status: ${data.status}`);\n  response.push(`### Request Headers`);\n  for (const line of formatHeadlers(data.requestHeaders)) {\n    response.push(line);\n  }\n\n  if (data.requestBody) {\n    response.push(`### Request Body`);\n    response.push(data.requestBody);\n  } else if (data.requestBodyFilePath) {\n    response.push(`### Request Body`);\n    response.push(`Saved to ${data.requestBodyFilePath}.`);\n  }\n\n  if (data.responseHeaders) {\n    response.push(`### Response Headers`);\n    for (const line of formatHeadlers(data.responseHeaders)) {\n      response.push(line);\n    }\n  }\n\n  if (data.responseBody) {\n    response.push(`### Response Body`);\n    response.push(data.responseBody);\n  } else if (data.responseBodyFilePath) {\n    response.push(`### Response Body`);\n    response.push(`Saved to ${data.responseBodyFilePath}.`);\n  }\n\n  if (data.failure) {\n    response.push(`### Request failed with`);\n    response.push(data.failure);\n  }\n\n  const redirectChain = data.redirectChain;\n  if (redirectChain?.length) {\n    response.push(`### Redirect chain`);\n    let indent = 0;\n    for (const request of redirectChain.reverse()) {\n      response.push(\n        `${'  '.repeat(indent)}${convertNetworkRequestConciseToString(request)})}`,\n      );\n      indent++;\n    }\n  }\n  return response.join('\\n');\n}\n"
  },
  {
    "path": "src/formatters/SnapshotFormatter.ts",
    "content": "/**\n * @license\n * Copyright 2025 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport type {TextSnapshot, TextSnapshotNode} from '../McpContext.js';\n\nexport class SnapshotFormatter {\n  #snapshot: TextSnapshot;\n\n  constructor(snapshot: TextSnapshot) {\n    this.#snapshot = snapshot;\n  }\n\n  toString(): string {\n    const chunks: string[] = [];\n    const root = this.#snapshot.root;\n\n    // Top-level content of the snapshot.\n    if (\n      this.#snapshot.verbose &&\n      this.#snapshot.hasSelectedElement &&\n      !this.#snapshot.selectedElementUid\n    ) {\n      chunks.push(`Note: there is a selected element in the DevTools Elements panel but it is not included into the current a11y tree snapshot.\nGet a verbose snapshot to include all elements if you are interested in the selected element.\\n\\n`);\n    }\n\n    chunks.push(this.#formatNode(root, 0));\n    return chunks.join('');\n  }\n\n  toJSON(): object {\n    return this.#nodeToJSON(this.#snapshot.root);\n  }\n\n  #formatNode(node: TextSnapshotNode, depth = 0): string {\n    const chunks: string[] = [];\n    const attributes = this.#getAttributes(node);\n    const line =\n      ' '.repeat(depth * 2) +\n      attributes.join(' ') +\n      (node.id === this.#snapshot.selectedElementUid\n        ? ' [selected in the DevTools Elements panel]'\n        : '') +\n      '\\n';\n    chunks.push(line);\n\n    for (const child of node.children) {\n      chunks.push(this.#formatNode(child, depth + 1));\n    }\n    return chunks.join('');\n  }\n\n  #nodeToJSON(node: TextSnapshotNode): object {\n    const rawAttrs = this.#getAttributesMap(node);\n    const children = node.children.map(child => this.#nodeToJSON(child));\n    const result: Record<string, unknown> = structuredClone(rawAttrs);\n    if (children.length > 0) {\n      result.children = children;\n    }\n    return result;\n  }\n\n  #getAttributes(serializedAXNodeRoot: TextSnapshotNode): string[] {\n    const attributes = [`uid=${serializedAXNodeRoot.id}`];\n\n    if (serializedAXNodeRoot.role) {\n      attributes.push(\n        serializedAXNodeRoot.role === 'none'\n          ? 'ignored'\n          : serializedAXNodeRoot.role,\n      );\n    }\n    if (serializedAXNodeRoot.name) {\n      attributes.push(`\"${serializedAXNodeRoot.name}\"`);\n    }\n\n    const simpleAttrs = this.#getAttributesMap(\n      serializedAXNodeRoot,\n      /* excludeSpecial */ true,\n    );\n\n    for (const attr of Object.keys(serializedAXNodeRoot).sort()) {\n      if (excludedAttributes.has(attr)) {\n        continue;\n      }\n\n      const mapped = booleanPropertyMap[attr];\n      if (mapped && simpleAttrs[mapped]) {\n        attributes.push(mapped);\n      }\n\n      const val = simpleAttrs[attr];\n      if (val === true) {\n        attributes.push(attr);\n      } else if (typeof val === 'string' || typeof val === 'number') {\n        attributes.push(`${attr}=\"${val}\"`);\n      }\n    }\n\n    return attributes;\n  }\n\n  #getAttributesMap(\n    node: TextSnapshotNode,\n    excludeSpecial = false,\n  ): Record<string, unknown> {\n    const result: Record<string, unknown> = {};\n    if (!excludeSpecial) {\n      result.id = node.id;\n      if (node.role) {\n        result.role = node.role;\n      }\n      if (node.name) {\n        result.name = node.name;\n      }\n    }\n\n    // Re-implementing the exact logic from original function for #getAttributes to be safe:\n    return {\n      ...result,\n      ...this.#extractedAttributes(node),\n    };\n  }\n\n  #extractedAttributes(node: TextSnapshotNode): Record<string, unknown> {\n    const result: Record<string, unknown> = {};\n\n    for (const attr of Object.keys(node).sort()) {\n      if (excludedAttributes.has(attr)) {\n        continue;\n      }\n      const value = (node as unknown as Record<string, unknown>)[attr];\n      if (typeof value === 'boolean') {\n        if (booleanPropertyMap[attr]) {\n          result[booleanPropertyMap[attr]] = true;\n        }\n        if (value) {\n          result[attr] = true;\n        }\n      } else if (typeof value === 'string' || typeof value === 'number') {\n        result[attr] = value;\n      }\n    }\n    return result;\n  }\n}\n\nconst booleanPropertyMap: Record<string, string> = {\n  disabled: 'disableable',\n  expanded: 'expandable',\n  focused: 'focusable',\n  selected: 'selectable',\n};\n\nconst excludedAttributes = new Set([\n  'id',\n  'role',\n  'name',\n  'elementHandle',\n  'children',\n  'backendNodeId',\n  'loaderId',\n]);\n"
  },
  {
    "path": "src/index.ts",
    "content": "/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport type fs from 'node:fs';\n\nimport type {parseArguments} from './bin/chrome-devtools-mcp-cli-options.js';\nimport type {Channel} from './browser.js';\nimport {ensureBrowserConnected, ensureBrowserLaunched} from './browser.js';\nimport {loadIssueDescriptions} from './issue-descriptions.js';\nimport {logger} from './logger.js';\nimport {McpContext} from './McpContext.js';\nimport {McpResponse} from './McpResponse.js';\nimport {Mutex} from './Mutex.js';\nimport {SlimMcpResponse} from './SlimMcpResponse.js';\nimport {ClearcutLogger} from './telemetry/ClearcutLogger.js';\nimport {bucketizeLatency} from './telemetry/metricUtils.js';\nimport {\n  McpServer,\n  type CallToolResult,\n  SetLevelRequestSchema,\n} from './third_party/index.js';\nimport {ToolCategory} from './tools/categories.js';\nimport type {DefinedPageTool, ToolDefinition} from './tools/ToolDefinition.js';\nimport {pageIdSchema} from './tools/ToolDefinition.js';\nimport {createTools} from './tools/tools.js';\nimport {VERSION} from './version.js';\n\nexport async function createMcpServer(\n  serverArgs: ReturnType<typeof parseArguments>,\n  options: {\n    logFile?: fs.WriteStream;\n  },\n) {\n  let clearcutLogger: ClearcutLogger | undefined;\n  if (serverArgs.usageStatistics) {\n    clearcutLogger = new ClearcutLogger({\n      logFile: serverArgs.logFile,\n      appVersion: VERSION,\n      clearcutEndpoint: serverArgs.clearcutEndpoint,\n      clearcutForceFlushIntervalMs: serverArgs.clearcutForceFlushIntervalMs,\n      clearcutIncludePidHeader: serverArgs.clearcutIncludePidHeader,\n    });\n  }\n\n  const server = new McpServer(\n    {\n      name: 'chrome_devtools',\n      title: 'Chrome DevTools MCP server',\n      version: VERSION,\n    },\n    {capabilities: {logging: {}}},\n  );\n  server.server.setRequestHandler(SetLevelRequestSchema, () => {\n    return {};\n  });\n\n  let context: McpContext;\n  async function getContext(): Promise<McpContext> {\n    const chromeArgs: string[] = (serverArgs.chromeArg ?? []).map(String);\n    const ignoreDefaultChromeArgs: string[] = (\n      serverArgs.ignoreDefaultChromeArg ?? []\n    ).map(String);\n    if (serverArgs.proxyServer) {\n      chromeArgs.push(`--proxy-server=${serverArgs.proxyServer}`);\n    }\n    const devtools = serverArgs.experimentalDevtools ?? false;\n    const browser =\n      serverArgs.browserUrl || serverArgs.wsEndpoint || serverArgs.autoConnect\n        ? await ensureBrowserConnected({\n            browserURL: serverArgs.browserUrl,\n            wsEndpoint: serverArgs.wsEndpoint,\n            wsHeaders: serverArgs.wsHeaders,\n            // Important: only pass channel, if autoConnect is true.\n            channel: serverArgs.autoConnect\n              ? (serverArgs.channel as Channel)\n              : undefined,\n            userDataDir: serverArgs.userDataDir,\n            devtools,\n          })\n        : await ensureBrowserLaunched({\n            headless: serverArgs.headless,\n            executablePath: serverArgs.executablePath,\n            channel: serverArgs.channel as Channel,\n            isolated: serverArgs.isolated ?? false,\n            userDataDir: serverArgs.userDataDir,\n            logFile: options.logFile,\n            viewport: serverArgs.viewport,\n            chromeArgs,\n            ignoreDefaultChromeArgs,\n            acceptInsecureCerts: serverArgs.acceptInsecureCerts,\n            devtools,\n            enableExtensions: serverArgs.categoryExtensions,\n            viaCli: serverArgs.viaCli,\n          });\n\n    if (context?.browser !== browser) {\n      context = await McpContext.from(browser, logger, {\n        experimentalDevToolsDebugging: devtools,\n        experimentalIncludeAllPages: serverArgs.experimentalIncludeAllPages,\n        performanceCrux: serverArgs.performanceCrux,\n      });\n    }\n    return context;\n  }\n\n  const toolMutex = new Mutex();\n\n  function registerTool(tool: ToolDefinition | DefinedPageTool): void {\n    if (\n      tool.annotations.category === ToolCategory.EMULATION &&\n      serverArgs.categoryEmulation === false\n    ) {\n      return;\n    }\n    if (\n      tool.annotations.category === ToolCategory.PERFORMANCE &&\n      serverArgs.categoryPerformance === false\n    ) {\n      return;\n    }\n    if (\n      tool.annotations.category === ToolCategory.NETWORK &&\n      serverArgs.categoryNetwork === false\n    ) {\n      return;\n    }\n    if (\n      tool.annotations.category === ToolCategory.EXTENSIONS &&\n      !serverArgs.categoryExtensions\n    ) {\n      return;\n    }\n    if (\n      tool.annotations.conditions?.includes('computerVision') &&\n      !serverArgs.experimentalVision\n    ) {\n      return;\n    }\n    if (\n      tool.annotations.conditions?.includes('experimentalInteropTools') &&\n      !serverArgs.experimentalInteropTools\n    ) {\n      return;\n    }\n    if (\n      tool.annotations.conditions?.includes('screencast') &&\n      !serverArgs.experimentalScreencast\n    ) {\n      return;\n    }\n    const schema =\n      'pageScoped' in tool &&\n      tool.pageScoped &&\n      serverArgs.experimentalPageIdRouting &&\n      !serverArgs.slim\n        ? {...tool.schema, ...pageIdSchema}\n        : tool.schema;\n\n    server.registerTool(\n      tool.name,\n      {\n        description: tool.description,\n        inputSchema: schema,\n        annotations: tool.annotations,\n      },\n      async (params): Promise<CallToolResult> => {\n        const guard = await toolMutex.acquire();\n        const startTime = Date.now();\n        let success = false;\n        try {\n          logger(`${tool.name} request: ${JSON.stringify(params, null, '  ')}`);\n          const context = await getContext();\n          logger(`${tool.name} context: resolved`);\n          await context.detectOpenDevToolsWindows();\n          const response = serverArgs.slim\n            ? new SlimMcpResponse(serverArgs)\n            : new McpResponse(serverArgs);\n          if ('pageScoped' in tool && tool.pageScoped) {\n            const page =\n              serverArgs.experimentalPageIdRouting &&\n              params.pageId &&\n              !serverArgs.slim\n                ? context.getPageById(params.pageId)\n                : context.getSelectedMcpPage();\n            response.setPage(page);\n            await tool.handler(\n              {\n                params,\n                page,\n              },\n              response,\n              context,\n            );\n          } else {\n            await tool.handler(\n              // @ts-expect-error types do not match.\n              {\n                params,\n              },\n              response,\n              context,\n            );\n          }\n          const {content, structuredContent} = await response.handle(\n            tool.name,\n            context,\n          );\n          const result: CallToolResult & {\n            structuredContent?: Record<string, unknown>;\n          } = {\n            content,\n          };\n          success = true;\n          if (serverArgs.experimentalStructuredContent) {\n            result.structuredContent = structuredContent as Record<\n              string,\n              unknown\n            >;\n          }\n          return result;\n        } catch (err) {\n          logger(`${tool.name} error:`, err, err?.stack);\n          let errorText = err && 'message' in err ? err.message : String(err);\n          if ('cause' in err && err.cause) {\n            errorText += `\\nCause: ${err.cause.message}`;\n          }\n          return {\n            content: [\n              {\n                type: 'text',\n                text: errorText,\n              },\n            ],\n            isError: true,\n          };\n        } finally {\n          void clearcutLogger?.logToolInvocation({\n            toolName: tool.name,\n            success,\n            latencyMs: bucketizeLatency(Date.now() - startTime),\n          });\n          guard.dispose();\n        }\n      },\n    );\n  }\n\n  const tools = createTools(serverArgs);\n  for (const tool of tools) {\n    registerTool(tool);\n  }\n\n  await loadIssueDescriptions();\n\n  return {server, clearcutLogger};\n}\n\nexport const logDisclaimers = (args: ReturnType<typeof parseArguments>) => {\n  console.error(\n    `chrome-devtools-mcp exposes content of the browser instance to the MCP clients allowing them to inspect,\ndebug, and modify any data in the browser or DevTools.\nAvoid sharing sensitive or personal information that you do not want to share with MCP clients.`,\n  );\n\n  if (!args.slim && args.performanceCrux) {\n    console.error(\n      `Performance tools may send trace URLs to the Google CrUX API to fetch real-user experience data. To disable, run with --no-performance-crux.`,\n    );\n  }\n\n  if (!args.slim && args.usageStatistics) {\n    console.error(\n      `\nGoogle collects usage statistics to improve Chrome DevTools MCP. To opt-out, run with --no-usage-statistics.\nFor more details, visit: https://github.com/ChromeDevTools/chrome-devtools-mcp#usage-statistics`,\n    );\n  }\n};\n"
  },
  {
    "path": "src/issue-descriptions.ts",
    "content": "/**\n * @license\n * Copyright 2025 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\n\nconst DESCRIPTIONS_PATH = path.join(\n  import.meta.dirname,\n  'third_party/issue-descriptions',\n);\n\nlet issueDescriptions: Record<string, string> = {};\n\n/**\n * Reads all issue descriptions from the filesystem into memory.\n */\nexport async function loadIssueDescriptions(): Promise<void> {\n  if (Object.keys(issueDescriptions).length > 0) {\n    return;\n  }\n\n  const files = await fs.promises.readdir(DESCRIPTIONS_PATH);\n  const descriptions: Record<string, string> = {};\n\n  for (const file of files) {\n    if (!file.endsWith('.md')) {\n      continue;\n    }\n    const content = await fs.promises.readFile(\n      path.join(DESCRIPTIONS_PATH, file),\n      'utf-8',\n    );\n    descriptions[file] = content;\n  }\n\n  issueDescriptions = descriptions;\n}\n\n/**\n * Gets an issue description from the in-memory cache.\n * @param fileName The file name of the issue description.\n * @returns The description of the issue, or null if it doesn't exist.\n */\nexport function getIssueDescription(fileName: string): string | null {\n  return issueDescriptions[fileName] ?? null;\n}\n\nexport const ISSUE_UTILS = {\n  loadIssueDescriptions,\n  getIssueDescription,\n};\n"
  },
  {
    "path": "src/logger.ts",
    "content": "/**\n * @license\n * Copyright 2025 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport fs from 'node:fs';\n\nimport {debug} from './third_party/index.js';\n\nconst mcpDebugNamespace = 'mcp:log';\n\nconst namespacesToEnable = [\n  mcpDebugNamespace,\n  ...(process.env['DEBUG'] ? [process.env['DEBUG']] : []),\n];\n\nexport function saveLogsToFile(fileName: string): fs.WriteStream {\n  // Enable overrides everything so we need to add them\n  debug.enable(namespacesToEnable.join(','));\n\n  const logFile = fs.createWriteStream(fileName, {flags: 'a+'});\n  debug.log = function (...chunks: any[]) {\n    logFile.write(`${chunks.join(' ')}\\n`);\n  };\n  logFile.on('error', function (error) {\n    console.error(`Error when opening/writing to log file: ${error.message}`);\n    logFile.end();\n    process.exit(1);\n  });\n  return logFile;\n}\n\nexport function flushLogs(\n  logFile: fs.WriteStream,\n  timeoutMs = 2000,\n): Promise<void> {\n  return new Promise((resolve, reject) => {\n    const timeout = setTimeout(reject, timeoutMs);\n    logFile.end(() => {\n      clearTimeout(timeout);\n      resolve();\n    });\n  });\n}\n\nexport const logger = debug(mcpDebugNamespace);\n"
  },
  {
    "path": "src/polyfill.ts",
    "content": "/**\n * @license\n * Copyright 2025 Google Inc.\n * SPDX-License-Identifier: Apache-2.0\n */\n\n// polyfills are now bundled with all other dependencies\nimport './third_party/index.js';\n"
  },
  {
    "path": "src/telemetry/ClearcutLogger.ts",
    "content": "/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport process from 'node:process';\n\nimport {logger} from '../logger.js';\n\nimport type {LocalState, Persistence} from './persistence.js';\nimport {FilePersistence} from './persistence.js';\nimport {type FlagUsage, WatchdogMessageType, OsType} from './types.js';\nimport {WatchdogClient} from './WatchdogClient.js';\n\nconst MS_PER_DAY = 24 * 60 * 60 * 1000;\n\nfunction detectOsType(): OsType {\n  switch (process.platform) {\n    case 'win32':\n      return OsType.OS_TYPE_WINDOWS;\n    case 'darwin':\n      return OsType.OS_TYPE_MACOS;\n    case 'linux':\n      return OsType.OS_TYPE_LINUX;\n    default:\n      return OsType.OS_TYPE_UNSPECIFIED;\n  }\n}\n\nexport class ClearcutLogger {\n  #persistence: Persistence;\n  #watchdog: WatchdogClient;\n\n  constructor(options: {\n    appVersion: string;\n    logFile?: string;\n    persistence?: Persistence;\n    watchdogClient?: WatchdogClient;\n    clearcutEndpoint?: string;\n    clearcutForceFlushIntervalMs?: number;\n    clearcutIncludePidHeader?: boolean;\n  }) {\n    this.#persistence = options.persistence ?? new FilePersistence();\n    this.#watchdog =\n      options.watchdogClient ??\n      new WatchdogClient({\n        parentPid: process.pid,\n        appVersion: options.appVersion,\n        osType: detectOsType(),\n        logFile: options.logFile,\n        clearcutEndpoint: options.clearcutEndpoint,\n        clearcutForceFlushIntervalMs: options.clearcutForceFlushIntervalMs,\n        clearcutIncludePidHeader: options.clearcutIncludePidHeader,\n      });\n  }\n\n  async logToolInvocation(args: {\n    toolName: string;\n    success: boolean;\n    latencyMs: number;\n  }): Promise<void> {\n    this.#watchdog.send({\n      type: WatchdogMessageType.LOG_EVENT,\n      payload: {\n        tool_invocation: {\n          tool_name: args.toolName,\n          success: args.success,\n          latency_ms: args.latencyMs,\n        },\n      },\n    });\n  }\n\n  async logServerStart(flagUsage: FlagUsage): Promise<void> {\n    this.#watchdog.send({\n      type: WatchdogMessageType.LOG_EVENT,\n      payload: {\n        server_start: {\n          flag_usage: flagUsage,\n        },\n      },\n    });\n  }\n\n  async logDailyActiveIfNeeded(): Promise<void> {\n    try {\n      const state = await this.#persistence.loadState();\n\n      if (this.#shouldLogDailyActive(state)) {\n        let daysSince = -1;\n        if (state.lastActive) {\n          const lastActiveDate = new Date(state.lastActive);\n          const now = new Date();\n          const diffTime = Math.abs(now.getTime() - lastActiveDate.getTime());\n          daysSince = Math.ceil(diffTime / MS_PER_DAY);\n        }\n\n        this.#watchdog.send({\n          type: WatchdogMessageType.LOG_EVENT,\n          payload: {\n            daily_active: {\n              days_since_last_active: daysSince,\n            },\n          },\n        });\n\n        state.lastActive = new Date().toISOString();\n        await this.#persistence.saveState(state);\n      }\n    } catch (err) {\n      logger('Error in logDailyActiveIfNeeded:', err);\n    }\n  }\n\n  #shouldLogDailyActive(state: LocalState): boolean {\n    if (!state.lastActive) {\n      return true;\n    }\n    const lastActiveDate = new Date(state.lastActive);\n    const now = new Date();\n\n    // Compare UTC dates\n    const isSameDay =\n      lastActiveDate.getUTCFullYear() === now.getUTCFullYear() &&\n      lastActiveDate.getUTCMonth() === now.getUTCMonth() &&\n      lastActiveDate.getUTCDate() === now.getUTCDate();\n\n    return !isSameDay;\n  }\n}\n"
  },
  {
    "path": "src/telemetry/WatchdogClient.ts",
    "content": "/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport {spawn, type ChildProcess} from 'node:child_process';\nimport {fileURLToPath} from 'node:url';\n\nimport {logger} from '../logger.js';\n\nimport type {WatchdogMessage, OsType} from './types.js';\n\nexport class WatchdogClient {\n  #childProcess: ChildProcess;\n\n  constructor(\n    config: {\n      parentPid: number;\n      appVersion: string;\n      osType: OsType;\n      logFile?: string;\n      clearcutEndpoint?: string;\n      clearcutForceFlushIntervalMs?: number;\n      clearcutIncludePidHeader?: boolean;\n    },\n    options?: {spawn?: typeof spawn},\n  ) {\n    const watchdogPath = fileURLToPath(\n      new URL('./watchdog/main.js', import.meta.url),\n    );\n\n    const args = [\n      watchdogPath,\n      `--parent-pid=${config.parentPid}`,\n      `--app-version=${config.appVersion}`,\n      `--os-type=${config.osType}`,\n    ];\n\n    if (config.logFile) {\n      args.push(`--log-file=${config.logFile}`);\n    }\n    if (config.clearcutEndpoint) {\n      args.push(`--clearcut-endpoint=${config.clearcutEndpoint}`);\n    }\n    if (config.clearcutForceFlushIntervalMs) {\n      args.push(\n        `--clearcut-force-flush-interval-ms=${config.clearcutForceFlushIntervalMs}`,\n      );\n    }\n    if (config.clearcutIncludePidHeader) {\n      args.push('--clearcut-include-pid-header');\n    }\n\n    const spawner = options?.spawn ?? spawn;\n    this.#childProcess = spawner(process.execPath, args, {\n      stdio: ['pipe', 'ignore', 'ignore'],\n      detached: true,\n    });\n    this.#childProcess.unref();\n    this.#childProcess.on('error', err => {\n      logger('Watchdog process error:', err);\n    });\n    this.#childProcess.on('exit', (code, signal) => {\n      logger(`Watchdog exited with code ${code} and signal ${signal}`);\n    });\n  }\n\n  send(message: WatchdogMessage): void {\n    if (\n      this.#childProcess.stdin &&\n      !this.#childProcess.stdin.destroyed &&\n      this.#childProcess.pid\n    ) {\n      try {\n        const line = JSON.stringify(message) + '\\n';\n        this.#childProcess.stdin.write(line);\n      } catch (err) {\n        logger('Failed to write to watchdog stdin', err);\n      }\n    } else {\n      logger('Watchdog stdin not available, dropping message');\n    }\n  }\n}\n"
  },
  {
    "path": "src/telemetry/flagUtils.ts",
    "content": "/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport type {cliOptions} from '../bin/chrome-devtools-mcp-cli-options.js';\nimport {toSnakeCase} from '../utils/string.js';\n\nimport type {FlagUsage} from './types.js';\n\ntype CliOptions = typeof cliOptions;\n\n/**\n * Computes telemetry flag usage from parsed arguments and CLI options.\n *\n * Iterates over the defined CLI options to construct a payload:\n * - Flag names are converted to snake_case (e.g. `browserUrl` -> `browser_url`).\n * - A flag is logged as `{flag_name}_present` if:\n *    - It has no default value, OR\n *    - The provided value differs from the default value.\n * - Boolean flags are logged with their literal value.\n * - String flags with defined `choices` (Enums) are logged as their uppercase value.\n */\nexport function computeFlagUsage(\n  args: Record<string, unknown>,\n  options: CliOptions,\n): FlagUsage {\n  const usage: FlagUsage = {};\n\n  for (const [flagName, config] of Object.entries(options)) {\n    const value = args[flagName];\n    const snakeCaseName = toSnakeCase(flagName);\n\n    // If there isn't a default value provided for the flag,\n    // we're going to log whether it's present on the args user\n    // provided or not. If there is a default value, we only log presence\n    // if the value differs from the default, implying explicit user intent.\n    if (!('default' in config) || value !== config.default) {\n      usage[`${snakeCaseName}_present`] = value !== undefined && value !== null;\n    }\n\n    if (config.type === 'boolean' && typeof value === 'boolean') {\n      // For boolean options, we're going to log the value directly.\n      usage[snakeCaseName] = value;\n    } else if (\n      config.type === 'string' &&\n      typeof value === 'string' &&\n      'choices' in config &&\n      config.choices\n    ) {\n      // For enums, log the value as uppercase\n      // We're going to have an enum for such flags with choices represented\n      // as an `enum` where the keys of the enum will map to the uppercase `choice`.\n      usage[snakeCaseName] = `${snakeCaseName}_${value}`.toUpperCase();\n    }\n  }\n\n  return usage;\n}\n"
  },
  {
    "path": "src/telemetry/metricUtils.ts",
    "content": "/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nconst LATENCY_BUCKETS = [50, 100, 250, 500, 1000, 2500, 5000, 10000];\n\nexport function bucketizeLatency(latencyMs: number): number {\n  for (const bucket of LATENCY_BUCKETS) {\n    if (latencyMs <= bucket) {\n      return bucket;\n    }\n  }\n  return LATENCY_BUCKETS[LATENCY_BUCKETS.length - 1];\n}\n"
  },
  {
    "path": "src/telemetry/persistence.ts",
    "content": "/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport fs from 'node:fs/promises';\nimport os from 'node:os';\nimport path from 'node:path';\nimport process from 'node:process';\n\nimport {logger} from '../logger.js';\n\nexport interface LocalState {\n  lastActive: string; // ISO 8601 UTC date string\n}\n\nconst STATE_FILE_NAME = 'telemetry_state.json';\nfunction getDataFolder(): string {\n  const homedir = os.homedir();\n  const {env} = process;\n  const name = 'chrome-devtools-mcp';\n\n  if (process.platform === 'darwin') {\n    return path.join(homedir, 'Library', 'Application Support', name);\n  }\n\n  if (process.platform === 'win32') {\n    const localAppData =\n      env.LOCALAPPDATA || path.join(homedir, 'AppData', 'Local');\n    return path.join(localAppData, name, 'Data');\n  }\n\n  return path.join(\n    env.XDG_DATA_HOME || path.join(homedir, '.local', 'share'),\n    name,\n  );\n}\n\nexport interface Persistence {\n  loadState(): Promise<LocalState>;\n  saveState(state: LocalState): Promise<void>;\n}\n\nexport class FilePersistence implements Persistence {\n  #dataFolder: string;\n\n  constructor(dataFolderOverride?: string) {\n    this.#dataFolder = dataFolderOverride ?? getDataFolder();\n  }\n\n  async loadState(): Promise<LocalState> {\n    try {\n      const filePath = path.join(this.#dataFolder, STATE_FILE_NAME);\n      const content = await fs.readFile(filePath, 'utf-8');\n      return JSON.parse(content) as LocalState;\n    } catch {\n      return {\n        lastActive: '',\n      };\n    }\n  }\n\n  async saveState(state: LocalState): Promise<void> {\n    const filePath = path.join(this.#dataFolder, STATE_FILE_NAME);\n    try {\n      await fs.mkdir(this.#dataFolder, {recursive: true});\n      await fs.writeFile(filePath, JSON.stringify(state, null, 2), 'utf-8');\n    } catch (error) {\n      // Ignore errors during state saving to avoid crashing the server\n      logger(`Failed to save telemetry state to ${filePath}:`, error);\n    }\n  }\n}\n"
  },
  {
    "path": "src/telemetry/types.ts",
    "content": "/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\n// Protobuf message interfaces\nexport interface ChromeDevToolsMcpExtension {\n  os_type?: OsType;\n  mcp_client?: McpClient;\n  app_version?: string;\n  session_id?: string;\n  tool_invocation?: ToolInvocation;\n  server_start?: ServerStart;\n  daily_active?: DailyActive;\n  server_shutdown?: ServerShutdown;\n}\n\nexport type ServerShutdown = Record<string, never>;\n\nexport interface ToolInvocation {\n  tool_name: string;\n  success: boolean;\n  latency_ms: number;\n}\n\nexport interface ServerStart {\n  flag_usage?: FlagUsage;\n}\n\nexport interface DailyActive {\n  days_since_last_active: number;\n}\n\nexport type FlagUsage = Record<string, boolean | string | number | undefined>;\n\n// Clearcut API interfaces\nexport interface LogRequest {\n  log_source: number;\n  request_time_ms: string;\n  client_info: {\n    client_type: number;\n  };\n  log_event: Array<{\n    event_time_ms: string;\n    source_extension_json: string;\n  }>;\n}\n\nexport interface LogResponse {\n  /**\n   * If present, the client must wait this many milliseconds before\n   * issuing the next HTTP request.\n   */\n  next_request_wait_millis?: number;\n}\n\n// Enums\nexport enum OsType {\n  OS_TYPE_UNSPECIFIED = 0,\n  OS_TYPE_WINDOWS = 1,\n  OS_TYPE_MACOS = 2,\n  OS_TYPE_LINUX = 3,\n}\n\nexport enum ChromeChannel {\n  CHROME_CHANNEL_UNSPECIFIED = 0,\n  CHROME_CHANNEL_CANARY = 1,\n  CHROME_CHANNEL_DEV = 2,\n  CHROME_CHANNEL_BETA = 3,\n  CHROME_CHANNEL_STABLE = 4,\n}\n\nexport enum McpClient {\n  MCP_CLIENT_UNSPECIFIED = 0,\n  MCP_CLIENT_CLAUDE_CODE = 1,\n  MCP_CLIENT_GEMINI_CLI = 2,\n}\n\n// IPC types for messages between the main process and the\n// telemetry watchdog process.\nexport enum WatchdogMessageType {\n  LOG_EVENT = 'log-event',\n}\n\nexport interface WatchdogMessage {\n  type: WatchdogMessageType.LOG_EVENT;\n  payload: ChromeDevToolsMcpExtension;\n}\n"
  },
  {
    "path": "src/telemetry/watchdog/ClearcutSender.ts",
    "content": "/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport crypto from 'node:crypto';\n\nimport {logger} from '../../logger.js';\nimport type {\n  ChromeDevToolsMcpExtension,\n  LogRequest,\n  LogResponse,\n  OsType,\n} from '../types.js';\n\nexport interface ClearcutSenderConfig {\n  appVersion: string;\n  osType: OsType;\n  clearcutEndpoint?: string;\n  forceFlushIntervalMs?: number;\n  includePidHeader?: boolean;\n}\n\nconst MAX_BUFFER_SIZE = 1000;\nconst DEFAULT_CLEARCUT_ENDPOINT =\n  'https://play.googleapis.com/log?format=json_proto';\nconst DEFAULT_FLUSH_INTERVAL_MS = 15 * 60 * 1000;\n\nconst LOG_SOURCE = 2839;\nconst CLIENT_TYPE = 47;\nconst MIN_RATE_LIMIT_WAIT_MS = 30_000;\nconst REQUEST_TIMEOUT_MS = 30_000;\nconst SHUTDOWN_TIMEOUT_MS = 5_000;\nconst SESSION_ROTATION_INTERVAL_MS = 24 * 60 * 60 * 1000;\n\ninterface BufferedEvent {\n  event: ChromeDevToolsMcpExtension;\n  timestamp: number;\n}\n\nexport class ClearcutSender {\n  #appVersion: string;\n  #osType: OsType;\n  #clearcutEndpoint: string;\n  #flushIntervalMs: number;\n  #includePidHeader: boolean;\n  #sessionId: string;\n  #sessionCreated: number;\n  #buffer: BufferedEvent[] = [];\n  #flushTimer: ReturnType<typeof setTimeout> | null = null;\n  #isFlushing = false;\n  #timerStarted = false;\n\n  constructor(config: ClearcutSenderConfig) {\n    this.#appVersion = config.appVersion;\n    this.#osType = config.osType;\n    this.#clearcutEndpoint =\n      config.clearcutEndpoint ?? DEFAULT_CLEARCUT_ENDPOINT;\n    this.#flushIntervalMs =\n      config.forceFlushIntervalMs ?? DEFAULT_FLUSH_INTERVAL_MS;\n    this.#includePidHeader = config.includePidHeader ?? false;\n    this.#sessionId = crypto.randomUUID();\n    this.#sessionCreated = Date.now();\n  }\n\n  enqueueEvent(event: ChromeDevToolsMcpExtension): void {\n    if (Date.now() - this.#sessionCreated > SESSION_ROTATION_INTERVAL_MS) {\n      this.#sessionId = crypto.randomUUID();\n      this.#sessionCreated = Date.now();\n    }\n\n    logger('Enqueing telemetry event', JSON.stringify(event, null, 2));\n\n    this.#addToBuffer({\n      ...event,\n      session_id: this.#sessionId,\n      app_version: this.#appVersion,\n      os_type: this.#osType,\n    });\n\n    if (!this.#timerStarted) {\n      this.#timerStarted = true;\n      this.#scheduleFlush(this.#flushIntervalMs);\n    }\n  }\n\n  async sendShutdownEvent(): Promise<void> {\n    if (this.#flushTimer) {\n      clearTimeout(this.#flushTimer);\n      this.#flushTimer = null;\n    }\n\n    const shutdownEvent: ChromeDevToolsMcpExtension = {\n      server_shutdown: {},\n    };\n    this.enqueueEvent(shutdownEvent);\n\n    try {\n      await Promise.race([\n        this.#finalFlush(),\n        new Promise(resolve => setTimeout(resolve, SHUTDOWN_TIMEOUT_MS)),\n      ]);\n      logger('Final flush completed');\n    } catch (error) {\n      logger('Final flush failed:', error);\n    }\n  }\n\n  async #flush(): Promise<void> {\n    if (this.#isFlushing) {\n      return;\n    }\n\n    if (this.#buffer.length === 0) {\n      this.#scheduleFlush(this.#flushIntervalMs);\n      return;\n    }\n\n    this.#isFlushing = true;\n    let nextDelayMs = this.#flushIntervalMs;\n\n    // Optimistically remove events from buffer before sending.\n    // This prevents race conditions where a simultaneous #finalFlush would include these same events.\n    const eventsToSend = [...this.#buffer];\n    this.#buffer = [];\n\n    try {\n      const result = await this.#sendBatch(eventsToSend);\n\n      if (result.success) {\n        if (result.nextRequestWaitMs !== undefined) {\n          nextDelayMs = Math.max(\n            result.nextRequestWaitMs,\n            MIN_RATE_LIMIT_WAIT_MS,\n          );\n        }\n      } else if (result.isPermanentError) {\n        logger(\n          'Permanent error, dropped batch of',\n          eventsToSend.length,\n          'events',\n        );\n      } else {\n        // Transient error: Requeue events at the front of the buffer\n        // to maintain order and retry them later.\n        this.#buffer = [...eventsToSend, ...this.#buffer];\n      }\n    } catch (error) {\n      // Safety catch for unexpected errors, requeue events\n      this.#buffer = [...eventsToSend, ...this.#buffer];\n      logger('Flush failed unexpectedly:', error);\n    } finally {\n      this.#isFlushing = false;\n      this.#scheduleFlush(nextDelayMs);\n    }\n  }\n\n  #addToBuffer(event: ChromeDevToolsMcpExtension): void {\n    if (this.#buffer.length >= MAX_BUFFER_SIZE) {\n      this.#buffer.shift();\n      logger('Telemetry buffer overflow: dropped oldest event');\n    }\n    this.#buffer.push({\n      event,\n      timestamp: Date.now(),\n    });\n  }\n\n  #scheduleFlush(delayMs: number): void {\n    logger(`Scheduling flush in ${delayMs}`);\n    if (this.#flushTimer) {\n      clearTimeout(this.#flushTimer);\n    }\n    this.#flushTimer = setTimeout(() => {\n      this.#flush().catch(err => {\n        logger('Flush error:', err);\n      });\n    }, delayMs);\n  }\n\n  async #sendBatch(events: BufferedEvent[]): Promise<{\n    success: boolean;\n    isPermanentError?: boolean;\n    nextRequestWaitMs?: number;\n  }> {\n    logger(`Sending batch of ${events.length}`);\n    const requestBody: LogRequest = {\n      log_source: LOG_SOURCE,\n      request_time_ms: Date.now().toString(),\n      client_info: {\n        client_type: CLIENT_TYPE,\n      },\n      log_event: events.map(({event, timestamp}) => ({\n        event_time_ms: timestamp.toString(),\n        source_extension_json: JSON.stringify(event),\n      })),\n    };\n\n    const controller = new AbortController();\n    const timeoutId = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);\n    try {\n      const response = await fetch(this.#clearcutEndpoint, {\n        method: 'POST',\n        headers: {\n          'Content-Type': 'application/json',\n          // Used in E2E tests to confirm that the watchdog process is killed\n          ...(this.#includePidHeader\n            ? {'X-Watchdog-Pid': process.pid.toString()}\n            : {}),\n        },\n        body: JSON.stringify(requestBody),\n        signal: controller.signal,\n      });\n\n      clearTimeout(timeoutId);\n      if (response.ok) {\n        const data = (await response.json()) as LogResponse;\n        return {\n          success: true,\n          nextRequestWaitMs: data.next_request_wait_millis,\n        };\n      }\n\n      const status = response.status;\n      if (status >= 500 || status === 429) {\n        return {success: false};\n      }\n\n      logger('Telemetry permanent error:', status);\n      return {success: false, isPermanentError: true};\n    } catch {\n      clearTimeout(timeoutId);\n      return {success: false};\n    }\n  }\n\n  async #finalFlush(): Promise<void> {\n    if (this.#buffer.length === 0) {\n      return;\n    }\n    const eventsToSend = [...this.#buffer];\n    await this.#sendBatch(eventsToSend);\n  }\n\n  stopForTesting(): void {\n    if (this.#flushTimer) {\n      clearTimeout(this.#flushTimer);\n      this.#flushTimer = null;\n    }\n    this.#timerStarted = false;\n  }\n\n  get bufferSizeForTesting(): number {\n    return this.#buffer.length;\n  }\n}\n"
  },
  {
    "path": "src/telemetry/watchdog/main.ts",
    "content": "/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport type {WriteStream} from 'node:fs';\nimport process from 'node:process';\nimport readline from 'node:readline';\nimport {parseArgs} from 'node:util';\n\nimport {logger, flushLogs, saveLogsToFile} from '../../logger.js';\nimport type {OsType} from '../types.js';\nimport {WatchdogMessageType} from '../types.js';\n\nimport {ClearcutSender} from './ClearcutSender.js';\n\ninterface WatchdogArgs {\n  // Required arguments\n  parentPid: number;\n  appVersion: string;\n  osType: OsType;\n  // Optional arguments\n  logFile?: string;\n  clearcutEndpoint?: string;\n  clearcutForceFlushIntervalMs?: number;\n  clearcutIncludePidHeader?: boolean;\n}\n\nfunction parseWatchdogArgs(): WatchdogArgs {\n  const {values} = parseArgs({\n    options: {\n      'parent-pid': {type: 'string'},\n      'app-version': {type: 'string'},\n      'os-type': {type: 'string'},\n      'log-file': {type: 'string'},\n      'clearcut-endpoint': {type: 'string'},\n      'clearcut-force-flush-interval-ms': {type: 'string'},\n      'clearcut-include-pid-header': {type: 'boolean'},\n    },\n    strict: true,\n  });\n  // Verify required arguments\n  const parentPid = parseInt(values['parent-pid'] ?? '', 10);\n  const appVersion = values['app-version'];\n  const osType = parseInt(values['os-type'] ?? '', 10);\n  if (isNaN(parentPid) || !appVersion || isNaN(osType)) {\n    console.error(\n      'Invalid arguments provided for watchdog process: ',\n      JSON.stringify({parentPid, appVersion, osType}),\n    );\n    process.exit(1);\n  }\n\n  // Parse Optional Arguments\n  const logFile = values['log-file'];\n  const clearcutEndpoint = values['clearcut-endpoint'];\n  const clearcutIncludePidHeader = values['clearcut-include-pid-header'];\n  let clearcutForceFlushIntervalMs: number | undefined;\n  if (values['clearcut-force-flush-interval-ms']) {\n    const parsed = parseInt(values['clearcut-force-flush-interval-ms'], 10);\n    if (!isNaN(parsed)) {\n      clearcutForceFlushIntervalMs = parsed;\n    }\n  }\n\n  return {\n    parentPid,\n    appVersion,\n    osType,\n    logFile,\n    clearcutEndpoint,\n    clearcutForceFlushIntervalMs,\n    clearcutIncludePidHeader,\n  };\n}\n\nfunction main() {\n  const {\n    parentPid,\n    appVersion,\n    osType,\n    logFile,\n    clearcutEndpoint,\n    clearcutForceFlushIntervalMs,\n    clearcutIncludePidHeader,\n  } = parseWatchdogArgs();\n  let logStream: WriteStream | undefined;\n  if (logFile) {\n    logStream = saveLogsToFile(logFile);\n  }\n\n  const exit = (code: number) => {\n    if (!logStream) {\n      process.exit(code);\n    }\n\n    void flushLogs(logStream).finally(() => {\n      process.exit(code);\n    });\n  };\n\n  logger(\n    'Watchdog started',\n    JSON.stringify(\n      {\n        pid: process.pid,\n        parentPid,\n        version: appVersion,\n        osType,\n      },\n      null,\n      2,\n    ),\n  );\n\n  const sender = new ClearcutSender({\n    appVersion,\n    osType: osType,\n    clearcutEndpoint,\n    forceFlushIntervalMs: clearcutForceFlushIntervalMs,\n    includePidHeader: clearcutIncludePidHeader,\n  });\n\n  let isShuttingDown = false;\n  function onParentDeath(reason: string) {\n    if (isShuttingDown) {\n      return;\n    }\n\n    isShuttingDown = true;\n    logger(`Parent death detected (${reason}). Sending shutdown event...`);\n    sender\n      .sendShutdownEvent()\n      .then(() => {\n        logger('Shutdown event sent. Exiting.');\n        exit(0);\n      })\n      .catch(err => {\n        logger('Failed to send shutdown event', err);\n        exit(1);\n      });\n  }\n\n  process.stdin.on('end', () => onParentDeath('stdin end'));\n  process.stdin.on('close', () => onParentDeath('stdin close'));\n  process.on('disconnect', () => onParentDeath('ipc disconnect'));\n\n  const rl = readline.createInterface({\n    input: process.stdin,\n    terminal: false,\n  });\n\n  rl.on('line', line => {\n    try {\n      if (!line.trim()) {\n        return;\n      }\n\n      const msg = JSON.parse(line);\n      if (msg.type === WatchdogMessageType.LOG_EVENT && msg.payload) {\n        sender.enqueueEvent(msg.payload);\n      }\n    } catch (err) {\n      logger('Failed to parse IPC message', err);\n    }\n  });\n}\n\ntry {\n  main();\n} catch (err) {\n  console.error('Watchdog fatal error:', err);\n  process.exit(1);\n}\n"
  },
  {
    "path": "src/third_party/LIGHTHOUSE_MCP_BUNDLE_THIRD_PARTY_NOTICES",
    "content": "Name: ms\nURL: N/A\nVersion: 2.1.2\nLicense: MIT\n\nThe MIT License (MIT)\n\nCopyright (c) 2016 Zeit, Inc.\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\n-------------------- DEPENDENCY DIVIDER --------------------\n\nName: debug\nURL: git://github.com/debug-js/debug.git\nVersion: 4.3.4\nLicense: MIT\n\n(The MIT License)\n\nCopyright (c) 2014-2017 TJ Holowaychuk <tj@vision-media.ca>\nCopyright (c) 2018-2021 Josh Junon\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software\nand associated documentation files (the 'Software'), to deal in the Software without restriction,\nincluding without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,\nand/or sell copies of the 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 copies or substantial\nportions of the Software.\n\nTHE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT\nLIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\nWHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n\n\n-------------------- DEPENDENCY DIVIDER --------------------\n\nName: marky\nURL: N/A\nVersion: 1.2.2\nLicense: Apache-2.0\n\nApache License\nVersion 2.0, January 2004\nhttp://www.apache.org/licenses/\n\nTERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n1. Definitions.\n\n    \"License\" shall mean the terms and conditions for use, reproduction, and\n    distribution as defined by Sections 1 through 9 of this document.\n\n    \"Licensor\" shall mean the copyright owner or entity authorized by the\n    copyright owner that is granting the License.\n\n    \"Legal Entity\" shall mean the union of the acting entity and all other\n    entities that control, are controlled by, or are under common control with\n    that entity. For the purposes of this definition, \"control\" means (i) the\n    power, direct or indirect, to cause the direction or management of such\n    entity, whether by contract or otherwise, or (ii) ownership of\n    fifty percent (50%) or more of the outstanding shares, or (iii) beneficial\n    ownership of such entity.\n\n    \"You\" (or \"Your\") shall mean an individual or Legal Entity exercising\n    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 source,\n    and configuration files.\n\n    \"Object\" form shall mean any form resulting from mechanical transformation\n    or translation of a Source form, including but not limited to compiled\n    object code, generated documentation, and conversions to\n    other media types.\n\n    \"Work\" shall mean the work of authorship, whether in Source or Object\n    form, made available under the License, as indicated by a copyright notice\n    that is included in or attached to the work (an example is provided in the\n    Appendix below).\n\n    \"Derivative Works\" shall mean any work, whether in Source or Object form,\n    that is based on (or derived from) the Work and for which the editorial\n    revisions, annotations, elaborations, or other modifications represent,\n    as a whole, an original work of authorship. For the purposes of this\n    License, Derivative Works shall not include works that remain separable\n    from, or merely link (or bind by name) to the interfaces of, the Work and\n    Derivative Works thereof.\n\n    \"Contribution\" shall mean any work of authorship, including the original\n    version of the Work and any modifications or additions to that Work or\n    Derivative Works thereof, that is intentionally submitted to Licensor for\n    inclusion in the Work by the copyright owner or by an individual or\n    Legal Entity authorized to submit on behalf of the copyright owner.\n    For the purposes of this definition, \"submitted\" means any form of\n    electronic, verbal, or written communication sent to the Licensor or its\n    representatives, including but not limited to communication on electronic\n    mailing lists, source code control systems, and issue tracking systems\n    that are managed by, or on behalf of, the Licensor for the purpose of\n    discussing and improving the Work, but excluding communication that is\n    conspicuously marked or otherwise designated in writing by the copyright\n    owner as \"Not a Contribution.\"\n\n    \"Contributor\" shall mean Licensor and any individual or Legal Entity on\n    behalf of whom a Contribution has been received by Licensor and\n    subsequently incorporated within the Work.\n\n2. Grant of Copyright License.\n\n    Subject to the terms and conditions of this License, each Contributor\n    hereby grants to You a perpetual, worldwide, non-exclusive, no-charge,\n    royalty-free, irrevocable copyright license to reproduce, prepare\n    Derivative Works of, publicly display, publicly perform, sublicense,\n    and distribute the Work and such Derivative Works in\n    Source or Object form.\n\n3. Grant of Patent License.\n\n    Subject to the terms and conditions of this License, each Contributor\n    hereby grants to You a perpetual, worldwide, non-exclusive, no-charge,\n    royalty-free, irrevocable (except as stated in this section) patent\n    license to make, have made, use, offer to sell, sell, import, and\n    otherwise transfer the Work, where such license applies only to those\n    patent claims licensable by such Contributor that are necessarily\n    infringed by their Contribution(s) alone or by combination of their\n    Contribution(s) with the Work to which such Contribution(s) was submitted.\n    If You institute patent litigation against any entity (including a\n    cross-claim or counterclaim in a lawsuit) alleging that the Work or a\n    Contribution incorporated within the Work constitutes direct or\n    contributory patent infringement, then any patent licenses granted to\n    You under this License for that Work shall terminate as of the date such\n    litigation is filed.\n\n4. Redistribution.\n\n    You may reproduce and distribute copies of the Work or Derivative Works\n    thereof in any medium, with or without modifications, and in Source or\n    Object form, provided that You meet the following conditions:\n\n    1. You must give any other recipients of the Work or Derivative Works a\n    copy of this License; and\n\n    2. You must cause any modified files to carry prominent notices stating\n    that You changed the files; and\n\n    3. You must retain, in the Source form of any Derivative Works that You\n    distribute, all copyright, patent, trademark, and attribution notices from\n    the Source form of the Work, excluding those notices that do not pertain\n    to any part of the Derivative Works; and\n\n    4. If the Work includes a \"NOTICE\" text file as part of its distribution,\n    then any Derivative Works that You distribute must include a readable copy\n    of the attribution notices contained within such NOTICE file, excluding\n    those notices that do not pertain to any part of the Derivative Works,\n    in at least one of the following places: within a NOTICE text file\n    distributed as part of the Derivative Works; within the Source form or\n    documentation, if provided along with the Derivative Works; or, within a\n    display generated by the Derivative Works, if and wherever such\n    third-party notices normally appear. The contents of the NOTICE file are\n    for informational purposes only and do not modify the License.\n    You may add Your own attribution notices within Derivative Works that You\n    distribute, alongside or as an addendum to the NOTICE text from the Work,\n    provided 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 may\n    provide additional or different license terms and conditions for use,\n    reproduction, or distribution of Your modifications, or for any such\n    Derivative Works as a whole, provided Your use, reproduction, and\n    distribution of the Work otherwise complies with the conditions\n    stated in this License.\n\n5. Submission of Contributions.\n\n    Unless You explicitly state otherwise, any Contribution intentionally\n    submitted for inclusion in the Work by You to the Licensor shall be under\n    the terms and conditions of this License, without any additional\n    terms or conditions. Notwithstanding the above, nothing herein shall\n    supersede or modify the terms of any separate license agreement you may\n    have executed with Licensor regarding such Contributions.\n\n6. Trademarks.\n\n    This License does not grant permission to use the trade names, trademarks,\n    service marks, or product names of the Licensor, except as required for\n    reasonable and customary use in describing the origin of the Work and\n    reproducing the content of the NOTICE file.\n\n7. Disclaimer of Warranty.\n\n    Unless required by applicable law or agreed to in writing, Licensor\n    provides the Work (and each Contributor provides its Contributions)\n    on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,\n    either express or implied, including, without limitation, any warranties\n    or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS\n    FOR A PARTICULAR PURPOSE. You are solely responsible for determining the\n    appropriateness of using or redistributing the Work and assume any risks\n    associated with Your exercise of permissions under this License.\n\n8. Limitation of Liability.\n\n    In no event and under no legal theory, whether in tort\n    (including negligence), contract, or otherwise, unless required by\n    applicable law (such as deliberate and grossly negligent acts) or agreed\n    to in writing, shall any Contributor be liable to You for damages,\n    including any direct, indirect, special, incidental, or consequential\n    damages of any character arising as a result of this License or out of\n    the use or inability to use the Work (including but not limited to damages\n    for loss of goodwill, work stoppage, computer failure or malfunction,\n    or any and all other commercial damages or losses), even if such\n    Contributor has been advised of the possibility of such damages.\n\n9. Accepting Warranty or Additional Liability.\n\n    While redistributing the Work or Derivative Works thereof, You may choose\n    to offer, and charge a fee for, acceptance of support, warranty,\n    indemnity, or other liability obligations and/or rights consistent with\n    this License. However, in accepting such obligations, You may act only\n    on Your own behalf and on Your sole responsibility, not on behalf of any\n    other Contributor, and only if You agree to indemnify, defend, and hold\n    each Contributor harmless for any liability incurred by, or claims\n    asserted against, such Contributor by reason of your accepting any such\n    warranty or additional liability.\n\nEND OF TERMS AND CONDITIONS\n\nAPPENDIX: How to apply the Apache License to your work\n\n    To apply the Apache License to your work, attach the following boilerplate\n    notice, with the fields enclosed by brackets \"[]\" replaced with your own\n    identifying information. (Don't include the brackets!) The text should be\n    enclosed in the appropriate comment syntax for the file format. We also\n    recommend that a file or class name and description of purpose be included\n    on the same \"printed page\" as the copyright notice for easier\n    identification within third-party archives.\n\n        Copyright 2016 Nolan Lawson\n\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\n        or implied. See the License for the specific language governing\n        permissions and limitations under the License.\n\n\n\n-------------------- DEPENDENCY DIVIDER --------------------\n\nName: lodash-es\nURL: N/A\nVersion: 4.17.21\nLicense: MIT\n\nCopyright OpenJS Foundation and other contributors <https://openjsf.org/>\n\nBased on Underscore.js, copyright Jeremy Ashkenas,\nDocumentCloud and Investigative Reporters & Editors <http://underscorejs.org/>\n\nThis software consists of voluntary contributions made by many\nindividuals. For exact contribution history, see the revision history\navailable at https://github.com/lodash/lodash\n\nThe following license applies to all parts of this software except as\ndocumented below:\n\n====\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====\n\nCopyright and related rights for sample code are waived via CC0. Sample\ncode is defined as all source code displayed within the prose of the\ndocumentation.\n\nCC0: http://creativecommons.org/publicdomain/zero/1.0/\n\n====\n\nFiles located in the node_modules and vendor directories are externally\nmaintained libraries used by this software which have their own\nlicenses; we recommend you read them, as their terms may differ from the\nterms above.\n\n\n-------------------- DEPENDENCY DIVIDER --------------------\n\nName: tslib\nURL: N/A\nVersion: 2.6.2\nLicense: 0BSD\n\nCopyright (c) Microsoft Corporation.\n\nPermission to use, copy, modify, and/or distribute this software for any\npurpose with or without fee is hereby granted.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH\nREGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY\nAND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,\nINDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM\nLOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR\nOTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR\nPERFORMANCE OF THIS SOFTWARE.\n\n-------------------- DEPENDENCY DIVIDER --------------------\n\nName: @formatjs/icu-messageformat-parser\nURL: https://github.com/formatjs/formatjs.git\nVersion: 2.6.2\nLicense: MIT\n\nMIT License\n\nCopyright (c) 2021 FormatJS\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n\n-------------------- DEPENDENCY DIVIDER --------------------\n\nName: @formatjs/icu-skeleton-parser\nURL: https://github.com/formatjs/formatjs.git\nVersion: 1.6.2\nLicense: MIT\n\nMIT License\n\nCopyright (c) 2021 FormatJS\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n\n-------------------- DEPENDENCY DIVIDER --------------------\n\nName: @formatjs/fast-memoize\nURL: N/A\nVersion: 2.2.0\nLicense: MIT\n\nMIT License\n\nCopyright (c) 2021 FormatJS\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n\n-------------------- DEPENDENCY DIVIDER --------------------\n\nName: intl-messageformat\nURL: N/A\nVersion: 10.5.3\nLicense: BSD-3-Clause\n\nCopyright (c) 2021, Oath Inc.\n\nLicensed under the terms of the New BSD license. See below for terms.\n\nRedistribution and use of this software in source and binary forms,\nwith or without modification, are permitted provided that the following\nconditions are met:\n\n- Redistributions of source code must retain the above\n  copyright notice, this list of conditions and the\n  following disclaimer.\n\n- Redistributions in binary form must reproduce the above\n  copyright notice, this list of conditions and the\n  following disclaimer in the documentation and/or other\n  materials provided with the distribution.\n\n- Neither the name of Oath Inc. nor the names of its\n  contributors may be used to endorse or promote products\n  derived from this software without specific prior\n  written permission of Oath Inc.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS\nIS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED\nTO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A\nPARTICULAR 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\n-------------------- DEPENDENCY DIVIDER --------------------\n\nName: lighthouse-stack-packs\nURL: N/A\nVersion: 1.12.3\nLicense: Apache-2.0\n\n\n                                 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 [yyyy] [name of copyright owner]\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-------------------- DEPENDENCY DIVIDER --------------------\n\nName: lookup-closest-locale\nURL: N/A\nVersion: 6.2.0\nLicense: MIT\n\n-------------------- DEPENDENCY DIVIDER --------------------\n\nName: @paulirish/trace_engine\nURL: N/A\nVersion: 0.0.61\nLicense: BSD-3-Clause\n\n// Copyright 2014 The Chromium Authors\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\n\n-------------------- DEPENDENCY DIVIDER --------------------\n\nName: third-party-web\nURL: https://github.com/patrickhulce/third-party-web.git\nVersion: 0.26.2\nLicense: MIT\n\nThe MIT License (MIT)\nCopyright (c) 2019 Patrick Hulce\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\n-------------------- DEPENDENCY DIVIDER --------------------\n\nName: legacy-javascript\nURL: N/A\nVersion: 0.0.1\nLicense: Apache-2.0\n\n-------------------- DEPENDENCY DIVIDER --------------------\n\nName: tldts-icann\nURL: N/A\nVersion: 7.0.17\nLicense: MIT\n\nCopyright (c) 2017 Thomas Parisot, 2018 Rémi Berson\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and\nassociated documentation files (the \"Software\"), to deal in the Software without restriction,\nincluding without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,\nand/or sell copies of the 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 copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n\n-------------------- DEPENDENCY DIVIDER --------------------\n\nName: http-link-header\nURL: N/A\nVersion: 1.1.1\nLicense: MIT\n\n# The MIT License (MIT)\nCopyright (c) 2016 Jonas Hermsmeier\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,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,\nDAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\nOTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE\nOR OTHER DEALINGS IN THE SOFTWARE.\n\n\n-------------------- DEPENDENCY DIVIDER --------------------\n\nName: csp_evaluator\nURL: N/A\nVersion: 1.1.5\nLicense: Apache-2.0\n\n\n                                 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 [yyyy] [name of copyright owner]\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-------------------- DEPENDENCY DIVIDER --------------------\n\nName: robots-parser\nURL: N/A\nVersion: 3.0.1\nLicense: MIT\n\nThe MIT License (MIT)\n\nCopyright (c) 2014 Sam Clarke\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": "src/third_party/devtools-formatter-worker.ts",
    "content": "/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\n// eslint-disable-next-line no-restricted-imports\nimport '../../node_modules/chrome-devtools-frontend/front_end/entrypoints/formatter_worker/formatter_worker-entrypoint.js';\n"
  },
  {
    "path": "src/third_party/index.ts",
    "content": "/**\n * @license\n * Copyright 2025 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport 'core-js/modules/es.promise.with-resolvers.js';\nimport 'core-js/modules/es.set.union.v2.js';\nimport 'core-js/proposals/iterator-helpers.js';\n\nimport type {Flags, OutputMode, Result, RunnerResult} from 'lighthouse';\nimport type {Page} from 'puppeteer-core';\n\nexport type {Flags, Result, RunnerResult, OutputMode};\n\nexport type {Options as YargsOptions} from 'yargs';\nexport {default as yargs} from 'yargs';\nexport {hideBin} from 'yargs/helpers';\nexport {default as debug} from 'debug';\nexport type {Debugger} from 'debug';\nexport {McpServer} from '@modelcontextprotocol/sdk/server/mcp.js';\nexport {StdioServerTransport} from '@modelcontextprotocol/sdk/server/stdio.js';\nexport {StdioClientTransport} from '@modelcontextprotocol/sdk/client/stdio.js';\nexport {Client} from '@modelcontextprotocol/sdk/client/index.js';\nexport {\n  type CallToolResult,\n  SetLevelRequestSchema,\n  type ImageContent,\n  type TextContent,\n} from '@modelcontextprotocol/sdk/types.js';\nexport {z as zod} from 'zod';\nexport {\n  Locator,\n  PredefinedNetworkConditions,\n  KnownDevices,\n  CDPSessionEvent,\n} from 'puppeteer-core';\nexport {default as puppeteer} from 'puppeteer-core';\nexport type * from 'puppeteer-core';\nexport {PipeTransport} from 'puppeteer-core/internal/node/PipeTransport.js';\nexport type {CdpPage} from 'puppeteer-core/internal/cdp/Page.js';\nexport {\n  resolveDefaultUserDataDir,\n  detectBrowserPlatform,\n  Browser as BrowserEnum,\n  type ChromeReleaseChannel as BrowsersChromeReleaseChannel,\n} from '@puppeteer/browsers';\n\nimport {\n  snapshot as snapshotImpl,\n  navigation as navigationImpl,\n  generateReport as generateReportImpl,\n} from './lighthouse-devtools-mcp-bundle.js';\n\nexport const snapshot = snapshotImpl as (\n  page: Page,\n  options: {flags?: Flags},\n) => Promise<RunnerResult>;\nexport const navigation = navigationImpl as (\n  page: Page,\n  url: string,\n  options: {flags?: Flags},\n) => Promise<RunnerResult>;\nexport const generateReport = generateReportImpl as (\n  lhr: Result,\n  format: string,\n) => string;\n\nexport * as DevTools from '../../node_modules/chrome-devtools-frontend/mcp/mcp.js';\n"
  },
  {
    "path": "src/third_party/lighthouse-devtools-mcp-bundle.js",
    "content": "/**\n * Lighthouse v13.0.3-4-gd6e2a8e40 (Mar 04 2026)\n *\n * Automated auditing, performance metrics, and best practices for the web.\n *\n * @homepage https://github.com/GoogleChrome/lighthouse#readme\n * @author   Copyright 2026 Google LLC\n * @license  Apache-2.0\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0\n * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.\n */\nvar __create = Object.create;\nvar __defProp = Object.defineProperty;\nvar __getOwnPropDesc = Object.getOwnPropertyDescriptor;\nvar __getOwnPropNames = Object.getOwnPropertyNames;\nvar __getProtoOf = Object.getPrototypeOf;\nvar __hasOwnProp = Object.prototype.hasOwnProperty;\nvar __name = (target, value) => __defProp(target, \"name\", { value, configurable: true });\nvar __esm = (fn, res) => function __init() {\n  return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;\n};\nvar __commonJS = (cb, mod2) => function __require() {\n  return mod2 || (0, cb[__getOwnPropNames(cb)[0]])((mod2 = { exports: {} }).exports, mod2), mod2.exports;\n};\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 __toESM = (mod2, isNodeMode, target) => (target = mod2 != null ? __create(__getProtoOf(mod2)) : {}, __copyProps(\n  // If the importer is in node compatibility mode or this is not an ESM\n  // file that has been converted to a CommonJS file using a Babel-\n  // compatible transform (i.e. \"__esModule\" has not been set), then set\n  // \"default\" to the CommonJS \"module.exports\" for node compatibility.\n  isNodeMode || !mod2 || !mod2.__esModule ? __defProp(target, \"default\", { value: mod2, enumerable: true }) : target,\n  mod2\n));\nvar __toCommonJS = (mod2) => __copyProps(__defProp({}, \"__esModule\", { value: true }), mod2);\n\n// build/process-global.js\nimport process2 from \"process\";\nvar init_process_global = __esm({\n  \"build/process-global.js\"() {\n    \"use strict\";\n    globalThis.process = process2;\n  }\n});\n\n// types/lh.js\nvar init_lh = __esm({\n  \"types/lh.js\"() {\n    \"use strict\";\n    init_process_global();\n    /**\n     * @license\n     * Copyright 2023 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n  }\n});\n\n// core/gather/base-gatherer.js\nvar BaseGatherer, base_gatherer_default;\nvar init_base_gatherer = __esm({\n  \"core/gather/base-gatherer.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_lh();\n    /**\n     * @license\n     * Copyright 2021 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    BaseGatherer = class {\n      static {\n        __name(this, \"BaseGatherer\");\n      }\n      /** @type {LH.Gatherer.GathererMeta} */\n      meta = { supportedModes: [] };\n      /**\n       * Method to start observing a page for an arbitrary period of time.\n       * @param {LH.Gatherer.Context} passContext\n       * @return {Promise<void>|void}\n       */\n      startInstrumentation(passContext) {\n      }\n      /**\n       * Method to start observing a page when the measurements are very sensitive and\n       * should observe as little Lighthouse-induced work as possible.\n       * @param {LH.Gatherer.Context} passContext\n       * @return {Promise<void>|void}\n       */\n      startSensitiveInstrumentation(passContext) {\n      }\n      /**\n       * Method to stop observing a page when the measurements are very sensitive and\n       * should observe as little Lighthouse-induced work as possible.\n       *\n       * @param {LH.Gatherer.Context} passContext\n       * @return {Promise<void>|void}\n       */\n      stopSensitiveInstrumentation(passContext) {\n      }\n      /**\n       * Method to end observing a page after an arbitrary period of time.\n       * @param {LH.Gatherer.Context} passContext\n       * @return {Promise<void>|void}\n       */\n      stopInstrumentation(passContext) {\n      }\n      /**\n       * Method to gather results about a page.\n       * @param {LH.Gatherer.Context} passContext\n       * @return {LH.Gatherer.PhaseResult}\n       */\n      getArtifact(passContext) {\n      }\n    };\n    base_gatherer_default = BaseGatherer;\n  }\n});\n\n// lh-gatherer-shim:/Users/alexrudenko/src/lighthouse/core/gather/gatherers/trace.js\nvar trace_exports = {};\n__export(trace_exports, {\n  default: () => trace_default\n});\nvar ShimGatherer, trace_default;\nvar init_trace = __esm({\n  \"lh-gatherer-shim:/Users/alexrudenko/src/lighthouse/core/gather/gatherers/trace.js\"() {\n    init_process_global();\n    init_base_gatherer();\n    ShimGatherer = class extends base_gatherer_default {\n      static {\n        __name(this, \"ShimGatherer\");\n      }\n      meta = { supportedModes: [\"navigation\", \"timespan\", \"snapshot\"] };\n      static getDefaultTraceCategories() {\n        return [];\n      }\n      getArtifact() {\n        return void 0;\n      }\n    };\n    trace_default = ShimGatherer;\n  }\n});\n\n// node_modules/debug/node_modules/ms/index.js\nvar require_ms = __commonJS({\n  \"node_modules/debug/node_modules/ms/index.js\"(exports2, module2) {\n    init_process_global();\n    var s = 1e3;\n    var m = s * 60;\n    var h = m * 60;\n    var d = h * 24;\n    var w = d * 7;\n    var y = d * 365.25;\n    module2.exports = function(val, options) {\n      options = options || {};\n      var type = typeof val;\n      if (type === \"string\" && val.length > 0) {\n        return parse(val);\n      } else if (type === \"number\" && isFinite(val)) {\n        return options.long ? fmtLong(val) : fmtShort(val);\n      }\n      throw new Error(\n        \"val is not a non-empty string or a valid number. val=\" + JSON.stringify(val)\n      );\n    };\n    function parse(str) {\n      str = String(str);\n      if (str.length > 100) {\n        return;\n      }\n      var match = /^(-?(?:\\d+)?\\.?\\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec(\n        str\n      );\n      if (!match) {\n        return;\n      }\n      var n = parseFloat(match[1]);\n      var type = (match[2] || \"ms\").toLowerCase();\n      switch (type) {\n        case \"years\":\n        case \"year\":\n        case \"yrs\":\n        case \"yr\":\n        case \"y\":\n          return n * y;\n        case \"weeks\":\n        case \"week\":\n        case \"w\":\n          return n * w;\n        case \"days\":\n        case \"day\":\n        case \"d\":\n          return n * d;\n        case \"hours\":\n        case \"hour\":\n        case \"hrs\":\n        case \"hr\":\n        case \"h\":\n          return n * h;\n        case \"minutes\":\n        case \"minute\":\n        case \"mins\":\n        case \"min\":\n        case \"m\":\n          return n * m;\n        case \"seconds\":\n        case \"second\":\n        case \"secs\":\n        case \"sec\":\n        case \"s\":\n          return n * s;\n        case \"milliseconds\":\n        case \"millisecond\":\n        case \"msecs\":\n        case \"msec\":\n        case \"ms\":\n          return n;\n        default:\n          return void 0;\n      }\n    }\n    __name(parse, \"parse\");\n    function fmtShort(ms) {\n      var msAbs = Math.abs(ms);\n      if (msAbs >= d) {\n        return Math.round(ms / d) + \"d\";\n      }\n      if (msAbs >= h) {\n        return Math.round(ms / h) + \"h\";\n      }\n      if (msAbs >= m) {\n        return Math.round(ms / m) + \"m\";\n      }\n      if (msAbs >= s) {\n        return Math.round(ms / s) + \"s\";\n      }\n      return ms + \"ms\";\n    }\n    __name(fmtShort, \"fmtShort\");\n    function fmtLong(ms) {\n      var msAbs = Math.abs(ms);\n      if (msAbs >= d) {\n        return plural(ms, msAbs, d, \"day\");\n      }\n      if (msAbs >= h) {\n        return plural(ms, msAbs, h, \"hour\");\n      }\n      if (msAbs >= m) {\n        return plural(ms, msAbs, m, \"minute\");\n      }\n      if (msAbs >= s) {\n        return plural(ms, msAbs, s, \"second\");\n      }\n      return ms + \" ms\";\n    }\n    __name(fmtLong, \"fmtLong\");\n    function plural(ms, msAbs, n, name) {\n      var isPlural = msAbs >= n * 1.5;\n      return Math.round(ms / n) + \" \" + name + (isPlural ? \"s\" : \"\");\n    }\n    __name(plural, \"plural\");\n  }\n});\n\n// node_modules/debug/src/common.js\nvar require_common = __commonJS({\n  \"node_modules/debug/src/common.js\"(exports2, module2) {\n    init_process_global();\n    function setup(env) {\n      createDebug.debug = createDebug;\n      createDebug.default = createDebug;\n      createDebug.coerce = coerce;\n      createDebug.disable = disable;\n      createDebug.enable = enable;\n      createDebug.enabled = enabled;\n      createDebug.humanize = require_ms();\n      createDebug.destroy = destroy;\n      Object.keys(env).forEach((key) => {\n        createDebug[key] = env[key];\n      });\n      createDebug.names = [];\n      createDebug.skips = [];\n      createDebug.formatters = {};\n      function selectColor(namespace) {\n        let hash = 0;\n        for (let i = 0; i < namespace.length; i++) {\n          hash = (hash << 5) - hash + namespace.charCodeAt(i);\n          hash |= 0;\n        }\n        return createDebug.colors[Math.abs(hash) % createDebug.colors.length];\n      }\n      __name(selectColor, \"selectColor\");\n      createDebug.selectColor = selectColor;\n      function createDebug(namespace) {\n        let prevTime;\n        let enableOverride = null;\n        let namespacesCache;\n        let enabledCache;\n        function debug2(...args) {\n          if (!debug2.enabled) {\n            return;\n          }\n          const self2 = debug2;\n          const curr = Number(/* @__PURE__ */ new Date());\n          const ms = curr - (prevTime || curr);\n          self2.diff = ms;\n          self2.prev = prevTime;\n          self2.curr = curr;\n          prevTime = curr;\n          args[0] = createDebug.coerce(args[0]);\n          if (typeof args[0] !== \"string\") {\n            args.unshift(\"%O\");\n          }\n          let index = 0;\n          args[0] = args[0].replace(/%([a-zA-Z%])/g, (match, format) => {\n            if (match === \"%%\") {\n              return \"%\";\n            }\n            index++;\n            const formatter = createDebug.formatters[format];\n            if (typeof formatter === \"function\") {\n              const val = args[index];\n              match = formatter.call(self2, val);\n              args.splice(index, 1);\n              index--;\n            }\n            return match;\n          });\n          createDebug.formatArgs.call(self2, args);\n          const logFn = self2.log || createDebug.log;\n          logFn.apply(self2, args);\n        }\n        __name(debug2, \"debug\");\n        debug2.namespace = namespace;\n        debug2.useColors = createDebug.useColors();\n        debug2.color = createDebug.selectColor(namespace);\n        debug2.extend = extend;\n        debug2.destroy = createDebug.destroy;\n        Object.defineProperty(debug2, \"enabled\", {\n          enumerable: true,\n          configurable: false,\n          get: /* @__PURE__ */ __name(() => {\n            if (enableOverride !== null) {\n              return enableOverride;\n            }\n            if (namespacesCache !== createDebug.namespaces) {\n              namespacesCache = createDebug.namespaces;\n              enabledCache = createDebug.enabled(namespace);\n            }\n            return enabledCache;\n          }, \"get\"),\n          set: /* @__PURE__ */ __name((v) => {\n            enableOverride = v;\n          }, \"set\")\n        });\n        if (typeof createDebug.init === \"function\") {\n          createDebug.init(debug2);\n        }\n        return debug2;\n      }\n      __name(createDebug, \"createDebug\");\n      function extend(namespace, delimiter) {\n        const newDebug = createDebug(this.namespace + (typeof delimiter === \"undefined\" ? \":\" : delimiter) + namespace);\n        newDebug.log = this.log;\n        return newDebug;\n      }\n      __name(extend, \"extend\");\n      function enable(namespaces) {\n        createDebug.save(namespaces);\n        createDebug.namespaces = namespaces;\n        createDebug.names = [];\n        createDebug.skips = [];\n        let i;\n        const split = (typeof namespaces === \"string\" ? namespaces : \"\").split(/[\\s,]+/);\n        const len = split.length;\n        for (i = 0; i < len; i++) {\n          if (!split[i]) {\n            continue;\n          }\n          namespaces = split[i].replace(/\\*/g, \".*?\");\n          if (namespaces[0] === \"-\") {\n            createDebug.skips.push(new RegExp(\"^\" + namespaces.slice(1) + \"$\"));\n          } else {\n            createDebug.names.push(new RegExp(\"^\" + namespaces + \"$\"));\n          }\n        }\n      }\n      __name(enable, \"enable\");\n      function disable() {\n        const namespaces = [\n          ...createDebug.names.map(toNamespace),\n          ...createDebug.skips.map(toNamespace).map((namespace) => \"-\" + namespace)\n        ].join(\",\");\n        createDebug.enable(\"\");\n        return namespaces;\n      }\n      __name(disable, \"disable\");\n      function enabled(name) {\n        if (name[name.length - 1] === \"*\") {\n          return true;\n        }\n        let i;\n        let len;\n        for (i = 0, len = createDebug.skips.length; i < len; i++) {\n          if (createDebug.skips[i].test(name)) {\n            return false;\n          }\n        }\n        for (i = 0, len = createDebug.names.length; i < len; i++) {\n          if (createDebug.names[i].test(name)) {\n            return true;\n          }\n        }\n        return false;\n      }\n      __name(enabled, \"enabled\");\n      function toNamespace(regexp) {\n        return regexp.toString().substring(2, regexp.toString().length - 2).replace(/\\.\\*\\?$/, \"*\");\n      }\n      __name(toNamespace, \"toNamespace\");\n      function coerce(val) {\n        if (val instanceof Error) {\n          return val.stack || val.message;\n        }\n        return val;\n      }\n      __name(coerce, \"coerce\");\n      function destroy() {\n        console.warn(\"Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`.\");\n      }\n      __name(destroy, \"destroy\");\n      createDebug.enable(createDebug.load());\n      return createDebug;\n    }\n    __name(setup, \"setup\");\n    module2.exports = setup;\n  }\n});\n\n// node_modules/debug/src/browser.js\nvar require_browser = __commonJS({\n  \"node_modules/debug/src/browser.js\"(exports2, module2) {\n    init_process_global();\n    exports2.formatArgs = formatArgs;\n    exports2.save = save;\n    exports2.load = load;\n    exports2.useColors = useColors;\n    exports2.storage = localstorage();\n    exports2.destroy = /* @__PURE__ */ (() => {\n      let warned = false;\n      return () => {\n        if (!warned) {\n          warned = true;\n          console.warn(\"Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`.\");\n        }\n      };\n    })();\n    exports2.colors = [\n      \"#0000CC\",\n      \"#0000FF\",\n      \"#0033CC\",\n      \"#0033FF\",\n      \"#0066CC\",\n      \"#0066FF\",\n      \"#0099CC\",\n      \"#0099FF\",\n      \"#00CC00\",\n      \"#00CC33\",\n      \"#00CC66\",\n      \"#00CC99\",\n      \"#00CCCC\",\n      \"#00CCFF\",\n      \"#3300CC\",\n      \"#3300FF\",\n      \"#3333CC\",\n      \"#3333FF\",\n      \"#3366CC\",\n      \"#3366FF\",\n      \"#3399CC\",\n      \"#3399FF\",\n      \"#33CC00\",\n      \"#33CC33\",\n      \"#33CC66\",\n      \"#33CC99\",\n      \"#33CCCC\",\n      \"#33CCFF\",\n      \"#6600CC\",\n      \"#6600FF\",\n      \"#6633CC\",\n      \"#6633FF\",\n      \"#66CC00\",\n      \"#66CC33\",\n      \"#9900CC\",\n      \"#9900FF\",\n      \"#9933CC\",\n      \"#9933FF\",\n      \"#99CC00\",\n      \"#99CC33\",\n      \"#CC0000\",\n      \"#CC0033\",\n      \"#CC0066\",\n      \"#CC0099\",\n      \"#CC00CC\",\n      \"#CC00FF\",\n      \"#CC3300\",\n      \"#CC3333\",\n      \"#CC3366\",\n      \"#CC3399\",\n      \"#CC33CC\",\n      \"#CC33FF\",\n      \"#CC6600\",\n      \"#CC6633\",\n      \"#CC9900\",\n      \"#CC9933\",\n      \"#CCCC00\",\n      \"#CCCC33\",\n      \"#FF0000\",\n      \"#FF0033\",\n      \"#FF0066\",\n      \"#FF0099\",\n      \"#FF00CC\",\n      \"#FF00FF\",\n      \"#FF3300\",\n      \"#FF3333\",\n      \"#FF3366\",\n      \"#FF3399\",\n      \"#FF33CC\",\n      \"#FF33FF\",\n      \"#FF6600\",\n      \"#FF6633\",\n      \"#FF9900\",\n      \"#FF9933\",\n      \"#FFCC00\",\n      \"#FFCC33\"\n    ];\n    function useColors() {\n      if (typeof window !== \"undefined\" && window.process && (window.process.type === \"renderer\" || window.process.__nwjs)) {\n        return true;\n      }\n      if (typeof navigator !== \"undefined\" && navigator.userAgent && navigator.userAgent.toLowerCase().match(/(edge|trident)\\/(\\d+)/)) {\n        return false;\n      }\n      return typeof document !== \"undefined\" && document.documentElement && document.documentElement.style && document.documentElement.style.WebkitAppearance || // Is firebug? http://stackoverflow.com/a/398120/376773\n      typeof window !== \"undefined\" && window.console && (window.console.firebug || window.console.exception && window.console.table) || // Is firefox >= v31?\n      // https://developer.mozilla.org/en-US/docs/Tools/Web_Console#Styling_messages\n      typeof navigator !== \"undefined\" && navigator.userAgent && navigator.userAgent.toLowerCase().match(/firefox\\/(\\d+)/) && parseInt(RegExp.$1, 10) >= 31 || // Double check webkit in userAgent just in case we are in a worker\n      typeof navigator !== \"undefined\" && navigator.userAgent && navigator.userAgent.toLowerCase().match(/applewebkit\\/(\\d+)/);\n    }\n    __name(useColors, \"useColors\");\n    function formatArgs(args) {\n      args[0] = (this.useColors ? \"%c\" : \"\") + this.namespace + (this.useColors ? \" %c\" : \" \") + args[0] + (this.useColors ? \"%c \" : \" \") + \"+\" + module2.exports.humanize(this.diff);\n      if (!this.useColors) {\n        return;\n      }\n      const c = \"color: \" + this.color;\n      args.splice(1, 0, c, \"color: inherit\");\n      let index = 0;\n      let lastC = 0;\n      args[0].replace(/%[a-zA-Z%]/g, (match) => {\n        if (match === \"%%\") {\n          return;\n        }\n        index++;\n        if (match === \"%c\") {\n          lastC = index;\n        }\n      });\n      args.splice(lastC, 0, c);\n    }\n    __name(formatArgs, \"formatArgs\");\n    exports2.log = console.debug || console.log || (() => {\n    });\n    function save(namespaces) {\n      try {\n        if (namespaces) {\n          exports2.storage.setItem(\"debug\", namespaces);\n        } else {\n          exports2.storage.removeItem(\"debug\");\n        }\n      } catch (error) {\n      }\n    }\n    __name(save, \"save\");\n    function load() {\n      let r;\n      try {\n        r = exports2.storage.getItem(\"debug\");\n      } catch (error) {\n      }\n      if (!r && typeof process !== \"undefined\" && \"env\" in process) {\n        r = process.env.DEBUG;\n      }\n      return r;\n    }\n    __name(load, \"load\");\n    function localstorage() {\n      try {\n        return localStorage;\n      } catch (error) {\n      }\n    }\n    __name(localstorage, \"localstorage\");\n    module2.exports = require_common()(exports2);\n    var { formatters } = module2.exports;\n    formatters.j = function(v) {\n      try {\n        return JSON.stringify(v);\n      } catch (error) {\n        return \"[UnexpectedJSONParseError]: \" + error.message;\n      }\n    };\n  }\n});\n\n// node_modules/marky/lib/marky.cjs.js\nvar require_marky_cjs = __commonJS({\n  \"node_modules/marky/lib/marky.cjs.js\"(exports2) {\n    \"use strict\";\n    init_process_global();\n    Object.defineProperty(exports2, \"__esModule\", { value: true });\n    var perf = typeof performance !== \"undefined\" && performance;\n    var nowForNode;\n    {\n      hrtime = process.hrtime;\n      getNanoSeconds = /* @__PURE__ */ __name(function() {\n        var hr = hrtime();\n        return hr[0] * 1e9 + hr[1];\n      }, \"getNanoSeconds\");\n      loadTime = getNanoSeconds();\n      nowForNode = /* @__PURE__ */ __name(function() {\n        return (getNanoSeconds() - loadTime) / 1e6;\n      }, \"nowForNode\");\n    }\n    var hrtime;\n    var getNanoSeconds;\n    var loadTime;\n    var now = nowForNode;\n    function throwIfEmpty(name) {\n      if (!name) {\n        throw new Error(\"name must be non-empty\");\n      }\n    }\n    __name(throwIfEmpty, \"throwIfEmpty\");\n    function insertSorted(arr, item) {\n      var low = 0;\n      var high = arr.length;\n      var mid;\n      while (low < high) {\n        mid = low + high >>> 1;\n        if (arr[mid].startTime < item.startTime) {\n          low = mid + 1;\n        } else {\n          high = mid;\n        }\n      }\n      arr.splice(low, 0, item);\n    }\n    __name(insertSorted, \"insertSorted\");\n    exports2.mark = void 0;\n    exports2.stop = void 0;\n    exports2.getEntries = void 0;\n    exports2.clear = void 0;\n    if (perf && perf.mark && perf.getEntriesByName && perf.getEntriesByType && perf.clearMeasures) {\n      exports2.mark = function(name) {\n        throwIfEmpty(name);\n        perf.mark(\"start \" + name);\n      };\n      exports2.stop = function(name) {\n        throwIfEmpty(name);\n        perf.mark(\"end \" + name);\n        perf.measure(name, \"start \" + name, \"end \" + name);\n        var entries2 = perf.getEntriesByName(name);\n        return entries2[entries2.length - 1];\n      };\n      exports2.getEntries = function() {\n        return perf.getEntriesByType(\"measure\");\n      };\n      exports2.clear = function() {\n        perf.clearMarks();\n        perf.clearMeasures();\n      };\n    } else {\n      marks = {};\n      entries = [];\n      exports2.mark = function(name) {\n        throwIfEmpty(name);\n        var startTime = now();\n        marks[\"$\" + name] = startTime;\n      };\n      exports2.stop = function(name) {\n        throwIfEmpty(name);\n        var endTime = now();\n        var startTime = marks[\"$\" + name];\n        if (!startTime) {\n          throw new Error(\"no known mark: \" + name);\n        }\n        var entry = {\n          startTime,\n          name,\n          duration: endTime - startTime,\n          entryType: \"measure\"\n        };\n        insertSorted(entries, entry);\n        return entry;\n      };\n      exports2.getEntries = function() {\n        return entries;\n      };\n      exports2.clear = function() {\n        marks = {};\n        entries = [];\n      };\n    }\n    var marks;\n    var entries;\n  }\n});\n\n// lighthouse-logger/index.js\nimport process3 from \"process\";\nimport { EventEmitter } from \"events\";\nvar import_debug, marky, isWindows, isBrowser, colors, Emitter, loggersByTitle, loggingBufferColumns, level_, Log, lighthouse_logger_default;\nvar init_lighthouse_logger = __esm({\n  \"lighthouse-logger/index.js\"() {\n    \"use strict\";\n    init_process_global();\n    import_debug = __toESM(require_browser(), 1);\n    marky = __toESM(require_marky_cjs(), 1);\n    /**\n     * @license\n     * Copyright 2016 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    isWindows = process3.platform === \"win32\";\n    isBrowser = process3.browser;\n    colors = {\n      red: isBrowser ? \"crimson\" : 1,\n      yellow: isBrowser ? \"gold\" : 3,\n      cyan: isBrowser ? \"darkturquoise\" : 6,\n      green: isBrowser ? \"forestgreen\" : 2,\n      blue: isBrowser ? \"steelblue\" : 4,\n      magenta: isBrowser ? \"palevioletred\" : 5\n    };\n    import_debug.default.colors = [colors.cyan, colors.green, colors.blue, colors.magenta];\n    Emitter = class extends EventEmitter {\n      static {\n        __name(this, \"Emitter\");\n      }\n      // yarn build-types fails without this!\n      // https://github.com/microsoft/TypeScript/issues/41672#issuecomment-2303803072\n      constructor(options) {\n        super(options);\n      }\n      /**\n       * Fires off all status updates. Listen with\n       * `require('lib/log').events.addListener('status', callback)`\n       * @param {string} title\n       * @param {!Array<*>} argsArray\n       */\n      issueStatus(title, argsArray) {\n        if (title === \"status\" || title === \"statusEnd\") {\n          this.emit(title, [title, ...argsArray]);\n        }\n      }\n      /**\n       * Fires off all warnings. Listen with\n       * `require('lib/log').events.addListener('warning', callback)`\n       * @param {string} title\n       * @param {!Array<*>} argsArray\n       */\n      issueWarning(title, argsArray) {\n        this.emit(\"warning\", [title, ...argsArray]);\n      }\n    };\n    loggersByTitle = {};\n    loggingBufferColumns = 25;\n    Log = class _Log {\n      static {\n        __name(this, \"Log\");\n      }\n      static _logToStdErr(title, argsArray) {\n        const log = _Log.loggerfn(title);\n        log(...argsArray);\n      }\n      /**\n       * @param {string} title\n       */\n      static loggerfn(title) {\n        title = `LH:${title}`;\n        let log = loggersByTitle[title];\n        if (!log) {\n          log = (0, import_debug.default)(title);\n          loggersByTitle[title] = log;\n          if (title.endsWith(\"error\")) {\n            log.color = colors.red;\n          } else if (title.endsWith(\"warn\")) {\n            log.color = colors.yellow;\n          }\n        }\n        return log;\n      }\n      /**\n       * @param {string} level\n       */\n      static setLevel(level) {\n        level_ = level;\n        switch (level) {\n          case \"silent\":\n            import_debug.default.enable(\"-LH:*\");\n            break;\n          case \"verbose\":\n            import_debug.default.enable(\"LH:*\");\n            break;\n          case \"warn\":\n            import_debug.default.enable(\"-LH:*, LH:*:warn, LH:*:error\");\n            break;\n          case \"error\":\n            import_debug.default.enable(\"-LH:*, LH:*:error\");\n            break;\n          default:\n            import_debug.default.enable(\"LH:*, -LH:*:verbose\");\n        }\n      }\n      /**\n       * A simple formatting utility for event logging.\n       * @param {string} prefix\n       * @param {!Object} data A JSON-serializable object of event data to log.\n       * @param {string=} level Optional logging level. Defaults to 'log'.\n       */\n      static formatProtocol(prefix, data31, level) {\n        const columns = !process3 || process3.browser ? Infinity : process3.stdout.columns;\n        const method = data31.method || \"?????\";\n        const maxLength = columns - method.length - prefix.length - loggingBufferColumns;\n        const snippet = data31.params && method !== \"IO.read\" ? JSON.stringify(data31.params).substr(0, maxLength) : \"\";\n        _Log._logToStdErr(`${prefix}:${level || \"\"}`, [method, snippet]);\n      }\n      /**\n       * @return {boolean}\n       */\n      static isVerbose() {\n        return level_ === \"verbose\";\n      }\n      /**\n       * @param {{msg: string, id: string, args?: any[]}} status\n       * @param {string} level\n       */\n      static time({ msg, id, args = [] }, level = \"log\") {\n        marky.mark(id);\n        _Log[level](\"status\", msg, ...args);\n      }\n      /**\n       * @param {{msg: string, id: string, args?: any[]}} status\n       * @param {string} level\n       */\n      static timeEnd({ msg, id, args = [] }, level = \"verbose\") {\n        _Log[level](\"statusEnd\", msg, ...args);\n        marky.stop(id);\n      }\n      /**\n       * @param {string} title\n       * @param {...any} args\n       */\n      static log(title, ...args) {\n        _Log.events.issueStatus(title, args);\n        return _Log._logToStdErr(title, args);\n      }\n      /**\n       * @param {string} title\n       * @param {...any} args\n       */\n      static warn(title, ...args) {\n        _Log.events.issueWarning(title, args);\n        return _Log._logToStdErr(`${title}:warn`, args);\n      }\n      /**\n       * @param {string} title\n       * @param {...any} args\n       */\n      static error(title, ...args) {\n        return _Log._logToStdErr(`${title}:error`, args);\n      }\n      /**\n       * @param {string} title\n       * @param {...any} args\n       */\n      static verbose(title, ...args) {\n        _Log.events.issueStatus(title, args);\n        return _Log._logToStdErr(`${title}:verbose`, args);\n      }\n      /**\n       * Add surrounding escape sequences to turn a string green when logged.\n       * @param {string} str\n       * @return {string}\n       */\n      static greenify(str) {\n        return `${_Log.green}${str}${_Log.reset}`;\n      }\n      /**\n       * Add surrounding escape sequences to turn a string red when logged.\n       * @param {string} str\n       * @return {string}\n       */\n      static redify(str) {\n        return `${_Log.red}${str}${_Log.reset}`;\n      }\n      static get green() {\n        return \"\\x1B[32m\";\n      }\n      static get red() {\n        return \"\\x1B[31m\";\n      }\n      static get yellow() {\n        return \"\\x1B[33m\";\n      }\n      static get purple() {\n        return \"\\x1B[95m\";\n      }\n      static get reset() {\n        return \"\\x1B[0m\";\n      }\n      static get bold() {\n        return \"\\x1B[1m\";\n      }\n      static get dim() {\n        return \"\\x1B[2m\";\n      }\n      static get tick() {\n        return isWindows ? \"√\" : \"✓\";\n      }\n      static get cross() {\n        return isWindows ? \"×\" : \"✘\";\n      }\n      static get whiteSmallSquare() {\n        return isWindows ? \"·\" : \"▫\";\n      }\n      static get heavyHorizontal() {\n        return isWindows ? \"─\" : \"━\";\n      }\n      static get heavyVertical() {\n        return isWindows ? \"│ \" : \"┃ \";\n      }\n      static get heavyUpAndRight() {\n        return isWindows ? \"└\" : \"┗\";\n      }\n      static get heavyVerticalAndRight() {\n        return isWindows ? \"├\" : \"┣\";\n      }\n      static get heavyDownAndHorizontal() {\n        return isWindows ? \"┬\" : \"┳\";\n      }\n      static get doubleLightHorizontal() {\n        return \"──\";\n      }\n    };\n    Log.events = new Emitter();\n    Log.takeTimeEntries = () => {\n      const entries = marky.getEntries();\n      marky.clear();\n      return entries;\n    };\n    Log.getTimeEntries = () => marky.getEntries();\n    lighthouse_logger_default = Log;\n  }\n});\n\n// node_modules/lodash-es/_freeGlobal.js\nvar freeGlobal, freeGlobal_default;\nvar init_freeGlobal = __esm({\n  \"node_modules/lodash-es/_freeGlobal.js\"() {\n    init_process_global();\n    freeGlobal = typeof global == \"object\" && global && global.Object === Object && global;\n    freeGlobal_default = freeGlobal;\n  }\n});\n\n// node_modules/lodash-es/_root.js\nvar freeSelf, root, root_default;\nvar init_root = __esm({\n  \"node_modules/lodash-es/_root.js\"() {\n    init_process_global();\n    init_freeGlobal();\n    freeSelf = typeof self == \"object\" && self && self.Object === Object && self;\n    root = freeGlobal_default || freeSelf || Function(\"return this\")();\n    root_default = root;\n  }\n});\n\n// node_modules/lodash-es/_Symbol.js\nvar Symbol2, Symbol_default;\nvar init_Symbol = __esm({\n  \"node_modules/lodash-es/_Symbol.js\"() {\n    init_process_global();\n    init_root();\n    Symbol2 = root_default.Symbol;\n    Symbol_default = Symbol2;\n  }\n});\n\n// node_modules/lodash-es/_getRawTag.js\nfunction getRawTag(value) {\n  var isOwn = hasOwnProperty.call(value, symToStringTag), tag = value[symToStringTag];\n  try {\n    value[symToStringTag] = void 0;\n    var unmasked = true;\n  } catch (e) {\n  }\n  var result = nativeObjectToString.call(value);\n  if (unmasked) {\n    if (isOwn) {\n      value[symToStringTag] = tag;\n    } else {\n      delete value[symToStringTag];\n    }\n  }\n  return result;\n}\nvar objectProto, hasOwnProperty, nativeObjectToString, symToStringTag, getRawTag_default;\nvar init_getRawTag = __esm({\n  \"node_modules/lodash-es/_getRawTag.js\"() {\n    init_process_global();\n    init_Symbol();\n    objectProto = Object.prototype;\n    hasOwnProperty = objectProto.hasOwnProperty;\n    nativeObjectToString = objectProto.toString;\n    symToStringTag = Symbol_default ? Symbol_default.toStringTag : void 0;\n    __name(getRawTag, \"getRawTag\");\n    getRawTag_default = getRawTag;\n  }\n});\n\n// node_modules/lodash-es/_objectToString.js\nfunction objectToString(value) {\n  return nativeObjectToString2.call(value);\n}\nvar objectProto2, nativeObjectToString2, objectToString_default;\nvar init_objectToString = __esm({\n  \"node_modules/lodash-es/_objectToString.js\"() {\n    init_process_global();\n    objectProto2 = Object.prototype;\n    nativeObjectToString2 = objectProto2.toString;\n    __name(objectToString, \"objectToString\");\n    objectToString_default = objectToString;\n  }\n});\n\n// node_modules/lodash-es/_baseGetTag.js\nfunction baseGetTag(value) {\n  if (value == null) {\n    return value === void 0 ? undefinedTag : nullTag;\n  }\n  return symToStringTag2 && symToStringTag2 in Object(value) ? getRawTag_default(value) : objectToString_default(value);\n}\nvar nullTag, undefinedTag, symToStringTag2, baseGetTag_default;\nvar init_baseGetTag = __esm({\n  \"node_modules/lodash-es/_baseGetTag.js\"() {\n    init_process_global();\n    init_Symbol();\n    init_getRawTag();\n    init_objectToString();\n    nullTag = \"[object Null]\";\n    undefinedTag = \"[object Undefined]\";\n    symToStringTag2 = Symbol_default ? Symbol_default.toStringTag : void 0;\n    __name(baseGetTag, \"baseGetTag\");\n    baseGetTag_default = baseGetTag;\n  }\n});\n\n// node_modules/lodash-es/isObjectLike.js\nfunction isObjectLike(value) {\n  return value != null && typeof value == \"object\";\n}\nvar isObjectLike_default;\nvar init_isObjectLike = __esm({\n  \"node_modules/lodash-es/isObjectLike.js\"() {\n    init_process_global();\n    __name(isObjectLike, \"isObjectLike\");\n    isObjectLike_default = isObjectLike;\n  }\n});\n\n// node_modules/lodash-es/isArray.js\nvar isArray, isArray_default;\nvar init_isArray = __esm({\n  \"node_modules/lodash-es/isArray.js\"() {\n    init_process_global();\n    isArray = Array.isArray;\n    isArray_default = isArray;\n  }\n});\n\n// node_modules/lodash-es/isObject.js\nfunction isObject(value) {\n  var type = typeof value;\n  return value != null && (type == \"object\" || type == \"function\");\n}\nvar isObject_default;\nvar init_isObject = __esm({\n  \"node_modules/lodash-es/isObject.js\"() {\n    init_process_global();\n    __name(isObject, \"isObject\");\n    isObject_default = isObject;\n  }\n});\n\n// node_modules/lodash-es/isFunction.js\nfunction isFunction(value) {\n  if (!isObject_default(value)) {\n    return false;\n  }\n  var tag = baseGetTag_default(value);\n  return tag == funcTag || tag == genTag || tag == asyncTag || tag == proxyTag;\n}\nvar asyncTag, funcTag, genTag, proxyTag, isFunction_default;\nvar init_isFunction = __esm({\n  \"node_modules/lodash-es/isFunction.js\"() {\n    init_process_global();\n    init_baseGetTag();\n    init_isObject();\n    asyncTag = \"[object AsyncFunction]\";\n    funcTag = \"[object Function]\";\n    genTag = \"[object GeneratorFunction]\";\n    proxyTag = \"[object Proxy]\";\n    __name(isFunction, \"isFunction\");\n    isFunction_default = isFunction;\n  }\n});\n\n// node_modules/lodash-es/_coreJsData.js\nvar coreJsData, coreJsData_default;\nvar init_coreJsData = __esm({\n  \"node_modules/lodash-es/_coreJsData.js\"() {\n    init_process_global();\n    init_root();\n    coreJsData = root_default[\"__core-js_shared__\"];\n    coreJsData_default = coreJsData;\n  }\n});\n\n// node_modules/lodash-es/_isMasked.js\nfunction isMasked(func) {\n  return !!maskSrcKey && maskSrcKey in func;\n}\nvar maskSrcKey, isMasked_default;\nvar init_isMasked = __esm({\n  \"node_modules/lodash-es/_isMasked.js\"() {\n    init_process_global();\n    init_coreJsData();\n    maskSrcKey = (function() {\n      var uid = /[^.]+$/.exec(coreJsData_default && coreJsData_default.keys && coreJsData_default.keys.IE_PROTO || \"\");\n      return uid ? \"Symbol(src)_1.\" + uid : \"\";\n    })();\n    __name(isMasked, \"isMasked\");\n    isMasked_default = isMasked;\n  }\n});\n\n// node_modules/lodash-es/_toSource.js\nfunction toSource(func) {\n  if (func != null) {\n    try {\n      return funcToString.call(func);\n    } catch (e) {\n    }\n    try {\n      return func + \"\";\n    } catch (e) {\n    }\n  }\n  return \"\";\n}\nvar funcProto, funcToString, toSource_default;\nvar init_toSource = __esm({\n  \"node_modules/lodash-es/_toSource.js\"() {\n    init_process_global();\n    funcProto = Function.prototype;\n    funcToString = funcProto.toString;\n    __name(toSource, \"toSource\");\n    toSource_default = toSource;\n  }\n});\n\n// node_modules/lodash-es/_baseIsNative.js\nfunction baseIsNative(value) {\n  if (!isObject_default(value) || isMasked_default(value)) {\n    return false;\n  }\n  var pattern = isFunction_default(value) ? reIsNative : reIsHostCtor;\n  return pattern.test(toSource_default(value));\n}\nvar reRegExpChar, reIsHostCtor, funcProto2, objectProto3, funcToString2, hasOwnProperty2, reIsNative, baseIsNative_default;\nvar init_baseIsNative = __esm({\n  \"node_modules/lodash-es/_baseIsNative.js\"() {\n    init_process_global();\n    init_isFunction();\n    init_isMasked();\n    init_isObject();\n    init_toSource();\n    reRegExpChar = /[\\\\^$.*+?()[\\]{}|]/g;\n    reIsHostCtor = /^\\[object .+?Constructor\\]$/;\n    funcProto2 = Function.prototype;\n    objectProto3 = Object.prototype;\n    funcToString2 = funcProto2.toString;\n    hasOwnProperty2 = objectProto3.hasOwnProperty;\n    reIsNative = RegExp(\n      \"^\" + funcToString2.call(hasOwnProperty2).replace(reRegExpChar, \"\\\\$&\").replace(/hasOwnProperty|(function).*?(?=\\\\\\()| for .+?(?=\\\\\\])/g, \"$1.*?\") + \"$\"\n    );\n    __name(baseIsNative, \"baseIsNative\");\n    baseIsNative_default = baseIsNative;\n  }\n});\n\n// node_modules/lodash-es/_getValue.js\nfunction getValue(object, key) {\n  return object == null ? void 0 : object[key];\n}\nvar getValue_default;\nvar init_getValue = __esm({\n  \"node_modules/lodash-es/_getValue.js\"() {\n    init_process_global();\n    __name(getValue, \"getValue\");\n    getValue_default = getValue;\n  }\n});\n\n// node_modules/lodash-es/_getNative.js\nfunction getNative(object, key) {\n  var value = getValue_default(object, key);\n  return baseIsNative_default(value) ? value : void 0;\n}\nvar getNative_default;\nvar init_getNative = __esm({\n  \"node_modules/lodash-es/_getNative.js\"() {\n    init_process_global();\n    init_baseIsNative();\n    init_getValue();\n    __name(getNative, \"getNative\");\n    getNative_default = getNative;\n  }\n});\n\n// node_modules/lodash-es/_WeakMap.js\nvar WeakMap2, WeakMap_default;\nvar init_WeakMap = __esm({\n  \"node_modules/lodash-es/_WeakMap.js\"() {\n    init_process_global();\n    init_getNative();\n    init_root();\n    WeakMap2 = getNative_default(root_default, \"WeakMap\");\n    WeakMap_default = WeakMap2;\n  }\n});\n\n// node_modules/lodash-es/_isIndex.js\nfunction isIndex(value, length) {\n  var type = typeof value;\n  length = length == null ? MAX_SAFE_INTEGER : length;\n  return !!length && (type == \"number\" || type != \"symbol\" && reIsUint.test(value)) && (value > -1 && value % 1 == 0 && value < length);\n}\nvar MAX_SAFE_INTEGER, reIsUint, isIndex_default;\nvar init_isIndex = __esm({\n  \"node_modules/lodash-es/_isIndex.js\"() {\n    init_process_global();\n    MAX_SAFE_INTEGER = 9007199254740991;\n    reIsUint = /^(?:0|[1-9]\\d*)$/;\n    __name(isIndex, \"isIndex\");\n    isIndex_default = isIndex;\n  }\n});\n\n// node_modules/lodash-es/eq.js\nfunction eq(value, other) {\n  return value === other || value !== value && other !== other;\n}\nvar eq_default;\nvar init_eq = __esm({\n  \"node_modules/lodash-es/eq.js\"() {\n    init_process_global();\n    __name(eq, \"eq\");\n    eq_default = eq;\n  }\n});\n\n// node_modules/lodash-es/isLength.js\nfunction isLength(value) {\n  return typeof value == \"number\" && value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER2;\n}\nvar MAX_SAFE_INTEGER2, isLength_default;\nvar init_isLength = __esm({\n  \"node_modules/lodash-es/isLength.js\"() {\n    init_process_global();\n    MAX_SAFE_INTEGER2 = 9007199254740991;\n    __name(isLength, \"isLength\");\n    isLength_default = isLength;\n  }\n});\n\n// node_modules/lodash-es/isArrayLike.js\nfunction isArrayLike(value) {\n  return value != null && isLength_default(value.length) && !isFunction_default(value);\n}\nvar isArrayLike_default;\nvar init_isArrayLike = __esm({\n  \"node_modules/lodash-es/isArrayLike.js\"() {\n    init_process_global();\n    init_isFunction();\n    init_isLength();\n    __name(isArrayLike, \"isArrayLike\");\n    isArrayLike_default = isArrayLike;\n  }\n});\n\n// node_modules/lodash-es/_isPrototype.js\nfunction isPrototype(value) {\n  var Ctor = value && value.constructor, proto = typeof Ctor == \"function\" && Ctor.prototype || objectProto4;\n  return value === proto;\n}\nvar objectProto4, isPrototype_default;\nvar init_isPrototype = __esm({\n  \"node_modules/lodash-es/_isPrototype.js\"() {\n    init_process_global();\n    objectProto4 = Object.prototype;\n    __name(isPrototype, \"isPrototype\");\n    isPrototype_default = isPrototype;\n  }\n});\n\n// node_modules/lodash-es/_baseTimes.js\nfunction baseTimes(n, iteratee) {\n  var index = -1, result = Array(n);\n  while (++index < n) {\n    result[index] = iteratee(index);\n  }\n  return result;\n}\nvar baseTimes_default;\nvar init_baseTimes = __esm({\n  \"node_modules/lodash-es/_baseTimes.js\"() {\n    init_process_global();\n    __name(baseTimes, \"baseTimes\");\n    baseTimes_default = baseTimes;\n  }\n});\n\n// node_modules/lodash-es/_baseIsArguments.js\nfunction baseIsArguments(value) {\n  return isObjectLike_default(value) && baseGetTag_default(value) == argsTag;\n}\nvar argsTag, baseIsArguments_default;\nvar init_baseIsArguments = __esm({\n  \"node_modules/lodash-es/_baseIsArguments.js\"() {\n    init_process_global();\n    init_baseGetTag();\n    init_isObjectLike();\n    argsTag = \"[object Arguments]\";\n    __name(baseIsArguments, \"baseIsArguments\");\n    baseIsArguments_default = baseIsArguments;\n  }\n});\n\n// node_modules/lodash-es/isArguments.js\nvar objectProto5, hasOwnProperty3, propertyIsEnumerable, isArguments, isArguments_default;\nvar init_isArguments = __esm({\n  \"node_modules/lodash-es/isArguments.js\"() {\n    init_process_global();\n    init_baseIsArguments();\n    init_isObjectLike();\n    objectProto5 = Object.prototype;\n    hasOwnProperty3 = objectProto5.hasOwnProperty;\n    propertyIsEnumerable = objectProto5.propertyIsEnumerable;\n    isArguments = baseIsArguments_default(/* @__PURE__ */ (function() {\n      return arguments;\n    })()) ? baseIsArguments_default : function(value) {\n      return isObjectLike_default(value) && hasOwnProperty3.call(value, \"callee\") && !propertyIsEnumerable.call(value, \"callee\");\n    };\n    isArguments_default = isArguments;\n  }\n});\n\n// node_modules/lodash-es/stubFalse.js\nfunction stubFalse() {\n  return false;\n}\nvar stubFalse_default;\nvar init_stubFalse = __esm({\n  \"node_modules/lodash-es/stubFalse.js\"() {\n    init_process_global();\n    __name(stubFalse, \"stubFalse\");\n    stubFalse_default = stubFalse;\n  }\n});\n\n// node_modules/lodash-es/isBuffer.js\nvar freeExports, freeModule, moduleExports, Buffer2, nativeIsBuffer, isBuffer, isBuffer_default;\nvar init_isBuffer = __esm({\n  \"node_modules/lodash-es/isBuffer.js\"() {\n    init_process_global();\n    init_root();\n    init_stubFalse();\n    freeExports = typeof exports == \"object\" && exports && !exports.nodeType && exports;\n    freeModule = freeExports && typeof module == \"object\" && module && !module.nodeType && module;\n    moduleExports = freeModule && freeModule.exports === freeExports;\n    Buffer2 = moduleExports ? root_default.Buffer : void 0;\n    nativeIsBuffer = Buffer2 ? Buffer2.isBuffer : void 0;\n    isBuffer = nativeIsBuffer || stubFalse_default;\n    isBuffer_default = isBuffer;\n  }\n});\n\n// node_modules/lodash-es/_baseIsTypedArray.js\nfunction baseIsTypedArray(value) {\n  return isObjectLike_default(value) && isLength_default(value.length) && !!typedArrayTags[baseGetTag_default(value)];\n}\nvar argsTag2, arrayTag, boolTag, dateTag, errorTag, funcTag2, mapTag, numberTag, objectTag, regexpTag, setTag, stringTag, weakMapTag, arrayBufferTag, dataViewTag, float32Tag, float64Tag, int8Tag, int16Tag, int32Tag, uint8Tag, uint8ClampedTag, uint16Tag, uint32Tag, typedArrayTags, baseIsTypedArray_default;\nvar init_baseIsTypedArray = __esm({\n  \"node_modules/lodash-es/_baseIsTypedArray.js\"() {\n    init_process_global();\n    init_baseGetTag();\n    init_isLength();\n    init_isObjectLike();\n    argsTag2 = \"[object Arguments]\";\n    arrayTag = \"[object Array]\";\n    boolTag = \"[object Boolean]\";\n    dateTag = \"[object Date]\";\n    errorTag = \"[object Error]\";\n    funcTag2 = \"[object Function]\";\n    mapTag = \"[object Map]\";\n    numberTag = \"[object Number]\";\n    objectTag = \"[object Object]\";\n    regexpTag = \"[object RegExp]\";\n    setTag = \"[object Set]\";\n    stringTag = \"[object String]\";\n    weakMapTag = \"[object WeakMap]\";\n    arrayBufferTag = \"[object ArrayBuffer]\";\n    dataViewTag = \"[object DataView]\";\n    float32Tag = \"[object Float32Array]\";\n    float64Tag = \"[object Float64Array]\";\n    int8Tag = \"[object Int8Array]\";\n    int16Tag = \"[object Int16Array]\";\n    int32Tag = \"[object Int32Array]\";\n    uint8Tag = \"[object Uint8Array]\";\n    uint8ClampedTag = \"[object Uint8ClampedArray]\";\n    uint16Tag = \"[object Uint16Array]\";\n    uint32Tag = \"[object Uint32Array]\";\n    typedArrayTags = {};\n    typedArrayTags[float32Tag] = typedArrayTags[float64Tag] = typedArrayTags[int8Tag] = typedArrayTags[int16Tag] = typedArrayTags[int32Tag] = typedArrayTags[uint8Tag] = typedArrayTags[uint8ClampedTag] = typedArrayTags[uint16Tag] = typedArrayTags[uint32Tag] = true;\n    typedArrayTags[argsTag2] = typedArrayTags[arrayTag] = typedArrayTags[arrayBufferTag] = typedArrayTags[boolTag] = typedArrayTags[dataViewTag] = typedArrayTags[dateTag] = typedArrayTags[errorTag] = typedArrayTags[funcTag2] = typedArrayTags[mapTag] = typedArrayTags[numberTag] = typedArrayTags[objectTag] = typedArrayTags[regexpTag] = typedArrayTags[setTag] = typedArrayTags[stringTag] = typedArrayTags[weakMapTag] = false;\n    __name(baseIsTypedArray, \"baseIsTypedArray\");\n    baseIsTypedArray_default = baseIsTypedArray;\n  }\n});\n\n// node_modules/lodash-es/_baseUnary.js\nfunction baseUnary(func) {\n  return function(value) {\n    return func(value);\n  };\n}\nvar baseUnary_default;\nvar init_baseUnary = __esm({\n  \"node_modules/lodash-es/_baseUnary.js\"() {\n    init_process_global();\n    __name(baseUnary, \"baseUnary\");\n    baseUnary_default = baseUnary;\n  }\n});\n\n// node_modules/lodash-es/_nodeUtil.js\nvar freeExports2, freeModule2, moduleExports2, freeProcess, nodeUtil, nodeUtil_default;\nvar init_nodeUtil = __esm({\n  \"node_modules/lodash-es/_nodeUtil.js\"() {\n    init_process_global();\n    init_freeGlobal();\n    freeExports2 = typeof exports == \"object\" && exports && !exports.nodeType && exports;\n    freeModule2 = freeExports2 && typeof module == \"object\" && module && !module.nodeType && module;\n    moduleExports2 = freeModule2 && freeModule2.exports === freeExports2;\n    freeProcess = moduleExports2 && freeGlobal_default.process;\n    nodeUtil = (function() {\n      try {\n        var types = freeModule2 && freeModule2.require && freeModule2.require(\"util\").types;\n        if (types) {\n          return types;\n        }\n        return freeProcess && freeProcess.binding && freeProcess.binding(\"util\");\n      } catch (e) {\n      }\n    })();\n    nodeUtil_default = nodeUtil;\n  }\n});\n\n// node_modules/lodash-es/isTypedArray.js\nvar nodeIsTypedArray, isTypedArray, isTypedArray_default;\nvar init_isTypedArray = __esm({\n  \"node_modules/lodash-es/isTypedArray.js\"() {\n    init_process_global();\n    init_baseIsTypedArray();\n    init_baseUnary();\n    init_nodeUtil();\n    nodeIsTypedArray = nodeUtil_default && nodeUtil_default.isTypedArray;\n    isTypedArray = nodeIsTypedArray ? baseUnary_default(nodeIsTypedArray) : baseIsTypedArray_default;\n    isTypedArray_default = isTypedArray;\n  }\n});\n\n// node_modules/lodash-es/_arrayLikeKeys.js\nfunction arrayLikeKeys(value, inherited) {\n  var isArr = isArray_default(value), isArg = !isArr && isArguments_default(value), isBuff = !isArr && !isArg && isBuffer_default(value), isType = !isArr && !isArg && !isBuff && isTypedArray_default(value), skipIndexes = isArr || isArg || isBuff || isType, result = skipIndexes ? baseTimes_default(value.length, String) : [], length = result.length;\n  for (var key in value) {\n    if ((inherited || hasOwnProperty4.call(value, key)) && !(skipIndexes && // Safari 9 has enumerable `arguments.length` in strict mode.\n    (key == \"length\" || // Node.js 0.10 has enumerable non-index properties on buffers.\n    isBuff && (key == \"offset\" || key == \"parent\") || // PhantomJS 2 has enumerable non-index properties on typed arrays.\n    isType && (key == \"buffer\" || key == \"byteLength\" || key == \"byteOffset\") || // Skip index properties.\n    isIndex_default(key, length)))) {\n      result.push(key);\n    }\n  }\n  return result;\n}\nvar objectProto6, hasOwnProperty4, arrayLikeKeys_default;\nvar init_arrayLikeKeys = __esm({\n  \"node_modules/lodash-es/_arrayLikeKeys.js\"() {\n    init_process_global();\n    init_baseTimes();\n    init_isArguments();\n    init_isArray();\n    init_isBuffer();\n    init_isIndex();\n    init_isTypedArray();\n    objectProto6 = Object.prototype;\n    hasOwnProperty4 = objectProto6.hasOwnProperty;\n    __name(arrayLikeKeys, \"arrayLikeKeys\");\n    arrayLikeKeys_default = arrayLikeKeys;\n  }\n});\n\n// node_modules/lodash-es/_overArg.js\nfunction overArg(func, transform) {\n  return function(arg) {\n    return func(transform(arg));\n  };\n}\nvar overArg_default;\nvar init_overArg = __esm({\n  \"node_modules/lodash-es/_overArg.js\"() {\n    init_process_global();\n    __name(overArg, \"overArg\");\n    overArg_default = overArg;\n  }\n});\n\n// node_modules/lodash-es/_nativeKeys.js\nvar nativeKeys, nativeKeys_default;\nvar init_nativeKeys = __esm({\n  \"node_modules/lodash-es/_nativeKeys.js\"() {\n    init_process_global();\n    init_overArg();\n    nativeKeys = overArg_default(Object.keys, Object);\n    nativeKeys_default = nativeKeys;\n  }\n});\n\n// node_modules/lodash-es/_baseKeys.js\nfunction baseKeys(object) {\n  if (!isPrototype_default(object)) {\n    return nativeKeys_default(object);\n  }\n  var result = [];\n  for (var key in Object(object)) {\n    if (hasOwnProperty5.call(object, key) && key != \"constructor\") {\n      result.push(key);\n    }\n  }\n  return result;\n}\nvar objectProto7, hasOwnProperty5, baseKeys_default;\nvar init_baseKeys = __esm({\n  \"node_modules/lodash-es/_baseKeys.js\"() {\n    init_process_global();\n    init_isPrototype();\n    init_nativeKeys();\n    objectProto7 = Object.prototype;\n    hasOwnProperty5 = objectProto7.hasOwnProperty;\n    __name(baseKeys, \"baseKeys\");\n    baseKeys_default = baseKeys;\n  }\n});\n\n// node_modules/lodash-es/keys.js\nfunction keys(object) {\n  return isArrayLike_default(object) ? arrayLikeKeys_default(object) : baseKeys_default(object);\n}\nvar keys_default;\nvar init_keys = __esm({\n  \"node_modules/lodash-es/keys.js\"() {\n    init_process_global();\n    init_arrayLikeKeys();\n    init_baseKeys();\n    init_isArrayLike();\n    __name(keys, \"keys\");\n    keys_default = keys;\n  }\n});\n\n// node_modules/lodash-es/_nativeCreate.js\nvar nativeCreate, nativeCreate_default;\nvar init_nativeCreate = __esm({\n  \"node_modules/lodash-es/_nativeCreate.js\"() {\n    init_process_global();\n    init_getNative();\n    nativeCreate = getNative_default(Object, \"create\");\n    nativeCreate_default = nativeCreate;\n  }\n});\n\n// node_modules/lodash-es/_hashClear.js\nfunction hashClear() {\n  this.__data__ = nativeCreate_default ? nativeCreate_default(null) : {};\n  this.size = 0;\n}\nvar hashClear_default;\nvar init_hashClear = __esm({\n  \"node_modules/lodash-es/_hashClear.js\"() {\n    init_process_global();\n    init_nativeCreate();\n    __name(hashClear, \"hashClear\");\n    hashClear_default = hashClear;\n  }\n});\n\n// node_modules/lodash-es/_hashDelete.js\nfunction hashDelete(key) {\n  var result = this.has(key) && delete this.__data__[key];\n  this.size -= result ? 1 : 0;\n  return result;\n}\nvar hashDelete_default;\nvar init_hashDelete = __esm({\n  \"node_modules/lodash-es/_hashDelete.js\"() {\n    init_process_global();\n    __name(hashDelete, \"hashDelete\");\n    hashDelete_default = hashDelete;\n  }\n});\n\n// node_modules/lodash-es/_hashGet.js\nfunction hashGet(key) {\n  var data31 = this.__data__;\n  if (nativeCreate_default) {\n    var result = data31[key];\n    return result === HASH_UNDEFINED ? void 0 : result;\n  }\n  return hasOwnProperty6.call(data31, key) ? data31[key] : void 0;\n}\nvar HASH_UNDEFINED, objectProto8, hasOwnProperty6, hashGet_default;\nvar init_hashGet = __esm({\n  \"node_modules/lodash-es/_hashGet.js\"() {\n    init_process_global();\n    init_nativeCreate();\n    HASH_UNDEFINED = \"__lodash_hash_undefined__\";\n    objectProto8 = Object.prototype;\n    hasOwnProperty6 = objectProto8.hasOwnProperty;\n    __name(hashGet, \"hashGet\");\n    hashGet_default = hashGet;\n  }\n});\n\n// node_modules/lodash-es/_hashHas.js\nfunction hashHas(key) {\n  var data31 = this.__data__;\n  return nativeCreate_default ? data31[key] !== void 0 : hasOwnProperty7.call(data31, key);\n}\nvar objectProto9, hasOwnProperty7, hashHas_default;\nvar init_hashHas = __esm({\n  \"node_modules/lodash-es/_hashHas.js\"() {\n    init_process_global();\n    init_nativeCreate();\n    objectProto9 = Object.prototype;\n    hasOwnProperty7 = objectProto9.hasOwnProperty;\n    __name(hashHas, \"hashHas\");\n    hashHas_default = hashHas;\n  }\n});\n\n// node_modules/lodash-es/_hashSet.js\nfunction hashSet(key, value) {\n  var data31 = this.__data__;\n  this.size += this.has(key) ? 0 : 1;\n  data31[key] = nativeCreate_default && value === void 0 ? HASH_UNDEFINED2 : value;\n  return this;\n}\nvar HASH_UNDEFINED2, hashSet_default;\nvar init_hashSet = __esm({\n  \"node_modules/lodash-es/_hashSet.js\"() {\n    init_process_global();\n    init_nativeCreate();\n    HASH_UNDEFINED2 = \"__lodash_hash_undefined__\";\n    __name(hashSet, \"hashSet\");\n    hashSet_default = hashSet;\n  }\n});\n\n// node_modules/lodash-es/_Hash.js\nfunction Hash(entries) {\n  var index = -1, length = entries == null ? 0 : entries.length;\n  this.clear();\n  while (++index < length) {\n    var entry = entries[index];\n    this.set(entry[0], entry[1]);\n  }\n}\nvar Hash_default;\nvar init_Hash = __esm({\n  \"node_modules/lodash-es/_Hash.js\"() {\n    init_process_global();\n    init_hashClear();\n    init_hashDelete();\n    init_hashGet();\n    init_hashHas();\n    init_hashSet();\n    __name(Hash, \"Hash\");\n    Hash.prototype.clear = hashClear_default;\n    Hash.prototype[\"delete\"] = hashDelete_default;\n    Hash.prototype.get = hashGet_default;\n    Hash.prototype.has = hashHas_default;\n    Hash.prototype.set = hashSet_default;\n    Hash_default = Hash;\n  }\n});\n\n// node_modules/lodash-es/_listCacheClear.js\nfunction listCacheClear() {\n  this.__data__ = [];\n  this.size = 0;\n}\nvar listCacheClear_default;\nvar init_listCacheClear = __esm({\n  \"node_modules/lodash-es/_listCacheClear.js\"() {\n    init_process_global();\n    __name(listCacheClear, \"listCacheClear\");\n    listCacheClear_default = listCacheClear;\n  }\n});\n\n// node_modules/lodash-es/_assocIndexOf.js\nfunction assocIndexOf(array, key) {\n  var length = array.length;\n  while (length--) {\n    if (eq_default(array[length][0], key)) {\n      return length;\n    }\n  }\n  return -1;\n}\nvar assocIndexOf_default;\nvar init_assocIndexOf = __esm({\n  \"node_modules/lodash-es/_assocIndexOf.js\"() {\n    init_process_global();\n    init_eq();\n    __name(assocIndexOf, \"assocIndexOf\");\n    assocIndexOf_default = assocIndexOf;\n  }\n});\n\n// node_modules/lodash-es/_listCacheDelete.js\nfunction listCacheDelete(key) {\n  var data31 = this.__data__, index = assocIndexOf_default(data31, key);\n  if (index < 0) {\n    return false;\n  }\n  var lastIndex = data31.length - 1;\n  if (index == lastIndex) {\n    data31.pop();\n  } else {\n    splice.call(data31, index, 1);\n  }\n  --this.size;\n  return true;\n}\nvar arrayProto, splice, listCacheDelete_default;\nvar init_listCacheDelete = __esm({\n  \"node_modules/lodash-es/_listCacheDelete.js\"() {\n    init_process_global();\n    init_assocIndexOf();\n    arrayProto = Array.prototype;\n    splice = arrayProto.splice;\n    __name(listCacheDelete, \"listCacheDelete\");\n    listCacheDelete_default = listCacheDelete;\n  }\n});\n\n// node_modules/lodash-es/_listCacheGet.js\nfunction listCacheGet(key) {\n  var data31 = this.__data__, index = assocIndexOf_default(data31, key);\n  return index < 0 ? void 0 : data31[index][1];\n}\nvar listCacheGet_default;\nvar init_listCacheGet = __esm({\n  \"node_modules/lodash-es/_listCacheGet.js\"() {\n    init_process_global();\n    init_assocIndexOf();\n    __name(listCacheGet, \"listCacheGet\");\n    listCacheGet_default = listCacheGet;\n  }\n});\n\n// node_modules/lodash-es/_listCacheHas.js\nfunction listCacheHas(key) {\n  return assocIndexOf_default(this.__data__, key) > -1;\n}\nvar listCacheHas_default;\nvar init_listCacheHas = __esm({\n  \"node_modules/lodash-es/_listCacheHas.js\"() {\n    init_process_global();\n    init_assocIndexOf();\n    __name(listCacheHas, \"listCacheHas\");\n    listCacheHas_default = listCacheHas;\n  }\n});\n\n// node_modules/lodash-es/_listCacheSet.js\nfunction listCacheSet(key, value) {\n  var data31 = this.__data__, index = assocIndexOf_default(data31, key);\n  if (index < 0) {\n    ++this.size;\n    data31.push([key, value]);\n  } else {\n    data31[index][1] = value;\n  }\n  return this;\n}\nvar listCacheSet_default;\nvar init_listCacheSet = __esm({\n  \"node_modules/lodash-es/_listCacheSet.js\"() {\n    init_process_global();\n    init_assocIndexOf();\n    __name(listCacheSet, \"listCacheSet\");\n    listCacheSet_default = listCacheSet;\n  }\n});\n\n// node_modules/lodash-es/_ListCache.js\nfunction ListCache(entries) {\n  var index = -1, length = entries == null ? 0 : entries.length;\n  this.clear();\n  while (++index < length) {\n    var entry = entries[index];\n    this.set(entry[0], entry[1]);\n  }\n}\nvar ListCache_default;\nvar init_ListCache = __esm({\n  \"node_modules/lodash-es/_ListCache.js\"() {\n    init_process_global();\n    init_listCacheClear();\n    init_listCacheDelete();\n    init_listCacheGet();\n    init_listCacheHas();\n    init_listCacheSet();\n    __name(ListCache, \"ListCache\");\n    ListCache.prototype.clear = listCacheClear_default;\n    ListCache.prototype[\"delete\"] = listCacheDelete_default;\n    ListCache.prototype.get = listCacheGet_default;\n    ListCache.prototype.has = listCacheHas_default;\n    ListCache.prototype.set = listCacheSet_default;\n    ListCache_default = ListCache;\n  }\n});\n\n// node_modules/lodash-es/_Map.js\nvar Map2, Map_default;\nvar init_Map = __esm({\n  \"node_modules/lodash-es/_Map.js\"() {\n    init_process_global();\n    init_getNative();\n    init_root();\n    Map2 = getNative_default(root_default, \"Map\");\n    Map_default = Map2;\n  }\n});\n\n// node_modules/lodash-es/_mapCacheClear.js\nfunction mapCacheClear() {\n  this.size = 0;\n  this.__data__ = {\n    \"hash\": new Hash_default(),\n    \"map\": new (Map_default || ListCache_default)(),\n    \"string\": new Hash_default()\n  };\n}\nvar mapCacheClear_default;\nvar init_mapCacheClear = __esm({\n  \"node_modules/lodash-es/_mapCacheClear.js\"() {\n    init_process_global();\n    init_Hash();\n    init_ListCache();\n    init_Map();\n    __name(mapCacheClear, \"mapCacheClear\");\n    mapCacheClear_default = mapCacheClear;\n  }\n});\n\n// node_modules/lodash-es/_isKeyable.js\nfunction isKeyable(value) {\n  var type = typeof value;\n  return type == \"string\" || type == \"number\" || type == \"symbol\" || type == \"boolean\" ? value !== \"__proto__\" : value === null;\n}\nvar isKeyable_default;\nvar init_isKeyable = __esm({\n  \"node_modules/lodash-es/_isKeyable.js\"() {\n    init_process_global();\n    __name(isKeyable, \"isKeyable\");\n    isKeyable_default = isKeyable;\n  }\n});\n\n// node_modules/lodash-es/_getMapData.js\nfunction getMapData(map, key) {\n  var data31 = map.__data__;\n  return isKeyable_default(key) ? data31[typeof key == \"string\" ? \"string\" : \"hash\"] : data31.map;\n}\nvar getMapData_default;\nvar init_getMapData = __esm({\n  \"node_modules/lodash-es/_getMapData.js\"() {\n    init_process_global();\n    init_isKeyable();\n    __name(getMapData, \"getMapData\");\n    getMapData_default = getMapData;\n  }\n});\n\n// node_modules/lodash-es/_mapCacheDelete.js\nfunction mapCacheDelete(key) {\n  var result = getMapData_default(this, key)[\"delete\"](key);\n  this.size -= result ? 1 : 0;\n  return result;\n}\nvar mapCacheDelete_default;\nvar init_mapCacheDelete = __esm({\n  \"node_modules/lodash-es/_mapCacheDelete.js\"() {\n    init_process_global();\n    init_getMapData();\n    __name(mapCacheDelete, \"mapCacheDelete\");\n    mapCacheDelete_default = mapCacheDelete;\n  }\n});\n\n// node_modules/lodash-es/_mapCacheGet.js\nfunction mapCacheGet(key) {\n  return getMapData_default(this, key).get(key);\n}\nvar mapCacheGet_default;\nvar init_mapCacheGet = __esm({\n  \"node_modules/lodash-es/_mapCacheGet.js\"() {\n    init_process_global();\n    init_getMapData();\n    __name(mapCacheGet, \"mapCacheGet\");\n    mapCacheGet_default = mapCacheGet;\n  }\n});\n\n// node_modules/lodash-es/_mapCacheHas.js\nfunction mapCacheHas(key) {\n  return getMapData_default(this, key).has(key);\n}\nvar mapCacheHas_default;\nvar init_mapCacheHas = __esm({\n  \"node_modules/lodash-es/_mapCacheHas.js\"() {\n    init_process_global();\n    init_getMapData();\n    __name(mapCacheHas, \"mapCacheHas\");\n    mapCacheHas_default = mapCacheHas;\n  }\n});\n\n// node_modules/lodash-es/_mapCacheSet.js\nfunction mapCacheSet(key, value) {\n  var data31 = getMapData_default(this, key), size = data31.size;\n  data31.set(key, value);\n  this.size += data31.size == size ? 0 : 1;\n  return this;\n}\nvar mapCacheSet_default;\nvar init_mapCacheSet = __esm({\n  \"node_modules/lodash-es/_mapCacheSet.js\"() {\n    init_process_global();\n    init_getMapData();\n    __name(mapCacheSet, \"mapCacheSet\");\n    mapCacheSet_default = mapCacheSet;\n  }\n});\n\n// node_modules/lodash-es/_MapCache.js\nfunction MapCache(entries) {\n  var index = -1, length = entries == null ? 0 : entries.length;\n  this.clear();\n  while (++index < length) {\n    var entry = entries[index];\n    this.set(entry[0], entry[1]);\n  }\n}\nvar MapCache_default;\nvar init_MapCache = __esm({\n  \"node_modules/lodash-es/_MapCache.js\"() {\n    init_process_global();\n    init_mapCacheClear();\n    init_mapCacheDelete();\n    init_mapCacheGet();\n    init_mapCacheHas();\n    init_mapCacheSet();\n    __name(MapCache, \"MapCache\");\n    MapCache.prototype.clear = mapCacheClear_default;\n    MapCache.prototype[\"delete\"] = mapCacheDelete_default;\n    MapCache.prototype.get = mapCacheGet_default;\n    MapCache.prototype.has = mapCacheHas_default;\n    MapCache.prototype.set = mapCacheSet_default;\n    MapCache_default = MapCache;\n  }\n});\n\n// node_modules/lodash-es/_arrayPush.js\nfunction arrayPush(array, values) {\n  var index = -1, length = values.length, offset = array.length;\n  while (++index < length) {\n    array[offset + index] = values[index];\n  }\n  return array;\n}\nvar arrayPush_default;\nvar init_arrayPush = __esm({\n  \"node_modules/lodash-es/_arrayPush.js\"() {\n    init_process_global();\n    __name(arrayPush, \"arrayPush\");\n    arrayPush_default = arrayPush;\n  }\n});\n\n// node_modules/lodash-es/_stackClear.js\nfunction stackClear() {\n  this.__data__ = new ListCache_default();\n  this.size = 0;\n}\nvar stackClear_default;\nvar init_stackClear = __esm({\n  \"node_modules/lodash-es/_stackClear.js\"() {\n    init_process_global();\n    init_ListCache();\n    __name(stackClear, \"stackClear\");\n    stackClear_default = stackClear;\n  }\n});\n\n// node_modules/lodash-es/_stackDelete.js\nfunction stackDelete(key) {\n  var data31 = this.__data__, result = data31[\"delete\"](key);\n  this.size = data31.size;\n  return result;\n}\nvar stackDelete_default;\nvar init_stackDelete = __esm({\n  \"node_modules/lodash-es/_stackDelete.js\"() {\n    init_process_global();\n    __name(stackDelete, \"stackDelete\");\n    stackDelete_default = stackDelete;\n  }\n});\n\n// node_modules/lodash-es/_stackGet.js\nfunction stackGet(key) {\n  return this.__data__.get(key);\n}\nvar stackGet_default;\nvar init_stackGet = __esm({\n  \"node_modules/lodash-es/_stackGet.js\"() {\n    init_process_global();\n    __name(stackGet, \"stackGet\");\n    stackGet_default = stackGet;\n  }\n});\n\n// node_modules/lodash-es/_stackHas.js\nfunction stackHas(key) {\n  return this.__data__.has(key);\n}\nvar stackHas_default;\nvar init_stackHas = __esm({\n  \"node_modules/lodash-es/_stackHas.js\"() {\n    init_process_global();\n    __name(stackHas, \"stackHas\");\n    stackHas_default = stackHas;\n  }\n});\n\n// node_modules/lodash-es/_stackSet.js\nfunction stackSet(key, value) {\n  var data31 = this.__data__;\n  if (data31 instanceof ListCache_default) {\n    var pairs = data31.__data__;\n    if (!Map_default || pairs.length < LARGE_ARRAY_SIZE - 1) {\n      pairs.push([key, value]);\n      this.size = ++data31.size;\n      return this;\n    }\n    data31 = this.__data__ = new MapCache_default(pairs);\n  }\n  data31.set(key, value);\n  this.size = data31.size;\n  return this;\n}\nvar LARGE_ARRAY_SIZE, stackSet_default;\nvar init_stackSet = __esm({\n  \"node_modules/lodash-es/_stackSet.js\"() {\n    init_process_global();\n    init_ListCache();\n    init_Map();\n    init_MapCache();\n    LARGE_ARRAY_SIZE = 200;\n    __name(stackSet, \"stackSet\");\n    stackSet_default = stackSet;\n  }\n});\n\n// node_modules/lodash-es/_Stack.js\nfunction Stack(entries) {\n  var data31 = this.__data__ = new ListCache_default(entries);\n  this.size = data31.size;\n}\nvar Stack_default;\nvar init_Stack = __esm({\n  \"node_modules/lodash-es/_Stack.js\"() {\n    init_process_global();\n    init_ListCache();\n    init_stackClear();\n    init_stackDelete();\n    init_stackGet();\n    init_stackHas();\n    init_stackSet();\n    __name(Stack, \"Stack\");\n    Stack.prototype.clear = stackClear_default;\n    Stack.prototype[\"delete\"] = stackDelete_default;\n    Stack.prototype.get = stackGet_default;\n    Stack.prototype.has = stackHas_default;\n    Stack.prototype.set = stackSet_default;\n    Stack_default = Stack;\n  }\n});\n\n// node_modules/lodash-es/_arrayFilter.js\nfunction arrayFilter(array, predicate) {\n  var index = -1, length = array == null ? 0 : array.length, resIndex = 0, result = [];\n  while (++index < length) {\n    var value = array[index];\n    if (predicate(value, index, array)) {\n      result[resIndex++] = value;\n    }\n  }\n  return result;\n}\nvar arrayFilter_default;\nvar init_arrayFilter = __esm({\n  \"node_modules/lodash-es/_arrayFilter.js\"() {\n    init_process_global();\n    __name(arrayFilter, \"arrayFilter\");\n    arrayFilter_default = arrayFilter;\n  }\n});\n\n// node_modules/lodash-es/stubArray.js\nfunction stubArray() {\n  return [];\n}\nvar stubArray_default;\nvar init_stubArray = __esm({\n  \"node_modules/lodash-es/stubArray.js\"() {\n    init_process_global();\n    __name(stubArray, \"stubArray\");\n    stubArray_default = stubArray;\n  }\n});\n\n// node_modules/lodash-es/_getSymbols.js\nvar objectProto10, propertyIsEnumerable2, nativeGetSymbols, getSymbols, getSymbols_default;\nvar init_getSymbols = __esm({\n  \"node_modules/lodash-es/_getSymbols.js\"() {\n    init_process_global();\n    init_arrayFilter();\n    init_stubArray();\n    objectProto10 = Object.prototype;\n    propertyIsEnumerable2 = objectProto10.propertyIsEnumerable;\n    nativeGetSymbols = Object.getOwnPropertySymbols;\n    getSymbols = !nativeGetSymbols ? stubArray_default : function(object) {\n      if (object == null) {\n        return [];\n      }\n      object = Object(object);\n      return arrayFilter_default(nativeGetSymbols(object), function(symbol) {\n        return propertyIsEnumerable2.call(object, symbol);\n      });\n    };\n    getSymbols_default = getSymbols;\n  }\n});\n\n// node_modules/lodash-es/_baseGetAllKeys.js\nfunction baseGetAllKeys(object, keysFunc, symbolsFunc) {\n  var result = keysFunc(object);\n  return isArray_default(object) ? result : arrayPush_default(result, symbolsFunc(object));\n}\nvar baseGetAllKeys_default;\nvar init_baseGetAllKeys = __esm({\n  \"node_modules/lodash-es/_baseGetAllKeys.js\"() {\n    init_process_global();\n    init_arrayPush();\n    init_isArray();\n    __name(baseGetAllKeys, \"baseGetAllKeys\");\n    baseGetAllKeys_default = baseGetAllKeys;\n  }\n});\n\n// node_modules/lodash-es/_getAllKeys.js\nfunction getAllKeys(object) {\n  return baseGetAllKeys_default(object, keys_default, getSymbols_default);\n}\nvar getAllKeys_default;\nvar init_getAllKeys = __esm({\n  \"node_modules/lodash-es/_getAllKeys.js\"() {\n    init_process_global();\n    init_baseGetAllKeys();\n    init_getSymbols();\n    init_keys();\n    __name(getAllKeys, \"getAllKeys\");\n    getAllKeys_default = getAllKeys;\n  }\n});\n\n// node_modules/lodash-es/_DataView.js\nvar DataView, DataView_default;\nvar init_DataView = __esm({\n  \"node_modules/lodash-es/_DataView.js\"() {\n    init_process_global();\n    init_getNative();\n    init_root();\n    DataView = getNative_default(root_default, \"DataView\");\n    DataView_default = DataView;\n  }\n});\n\n// node_modules/lodash-es/_Promise.js\nvar Promise2, Promise_default;\nvar init_Promise = __esm({\n  \"node_modules/lodash-es/_Promise.js\"() {\n    init_process_global();\n    init_getNative();\n    init_root();\n    Promise2 = getNative_default(root_default, \"Promise\");\n    Promise_default = Promise2;\n  }\n});\n\n// node_modules/lodash-es/_Set.js\nvar Set2, Set_default;\nvar init_Set = __esm({\n  \"node_modules/lodash-es/_Set.js\"() {\n    init_process_global();\n    init_getNative();\n    init_root();\n    Set2 = getNative_default(root_default, \"Set\");\n    Set_default = Set2;\n  }\n});\n\n// node_modules/lodash-es/_getTag.js\nvar mapTag2, objectTag2, promiseTag, setTag2, weakMapTag2, dataViewTag2, dataViewCtorString, mapCtorString, promiseCtorString, setCtorString, weakMapCtorString, getTag, getTag_default;\nvar init_getTag = __esm({\n  \"node_modules/lodash-es/_getTag.js\"() {\n    init_process_global();\n    init_DataView();\n    init_Map();\n    init_Promise();\n    init_Set();\n    init_WeakMap();\n    init_baseGetTag();\n    init_toSource();\n    mapTag2 = \"[object Map]\";\n    objectTag2 = \"[object Object]\";\n    promiseTag = \"[object Promise]\";\n    setTag2 = \"[object Set]\";\n    weakMapTag2 = \"[object WeakMap]\";\n    dataViewTag2 = \"[object DataView]\";\n    dataViewCtorString = toSource_default(DataView_default);\n    mapCtorString = toSource_default(Map_default);\n    promiseCtorString = toSource_default(Promise_default);\n    setCtorString = toSource_default(Set_default);\n    weakMapCtorString = toSource_default(WeakMap_default);\n    getTag = baseGetTag_default;\n    if (DataView_default && getTag(new DataView_default(new ArrayBuffer(1))) != dataViewTag2 || Map_default && getTag(new Map_default()) != mapTag2 || Promise_default && getTag(Promise_default.resolve()) != promiseTag || Set_default && getTag(new Set_default()) != setTag2 || WeakMap_default && getTag(new WeakMap_default()) != weakMapTag2) {\n      getTag = /* @__PURE__ */ __name(function(value) {\n        var result = baseGetTag_default(value), Ctor = result == objectTag2 ? value.constructor : void 0, ctorString = Ctor ? toSource_default(Ctor) : \"\";\n        if (ctorString) {\n          switch (ctorString) {\n            case dataViewCtorString:\n              return dataViewTag2;\n            case mapCtorString:\n              return mapTag2;\n            case promiseCtorString:\n              return promiseTag;\n            case setCtorString:\n              return setTag2;\n            case weakMapCtorString:\n              return weakMapTag2;\n          }\n        }\n        return result;\n      }, \"getTag\");\n    }\n    getTag_default = getTag;\n  }\n});\n\n// node_modules/lodash-es/_Uint8Array.js\nvar Uint8Array2, Uint8Array_default;\nvar init_Uint8Array = __esm({\n  \"node_modules/lodash-es/_Uint8Array.js\"() {\n    init_process_global();\n    init_root();\n    Uint8Array2 = root_default.Uint8Array;\n    Uint8Array_default = Uint8Array2;\n  }\n});\n\n// node_modules/lodash-es/_setCacheAdd.js\nfunction setCacheAdd(value) {\n  this.__data__.set(value, HASH_UNDEFINED3);\n  return this;\n}\nvar HASH_UNDEFINED3, setCacheAdd_default;\nvar init_setCacheAdd = __esm({\n  \"node_modules/lodash-es/_setCacheAdd.js\"() {\n    init_process_global();\n    HASH_UNDEFINED3 = \"__lodash_hash_undefined__\";\n    __name(setCacheAdd, \"setCacheAdd\");\n    setCacheAdd_default = setCacheAdd;\n  }\n});\n\n// node_modules/lodash-es/_setCacheHas.js\nfunction setCacheHas(value) {\n  return this.__data__.has(value);\n}\nvar setCacheHas_default;\nvar init_setCacheHas = __esm({\n  \"node_modules/lodash-es/_setCacheHas.js\"() {\n    init_process_global();\n    __name(setCacheHas, \"setCacheHas\");\n    setCacheHas_default = setCacheHas;\n  }\n});\n\n// node_modules/lodash-es/_SetCache.js\nfunction SetCache(values) {\n  var index = -1, length = values == null ? 0 : values.length;\n  this.__data__ = new MapCache_default();\n  while (++index < length) {\n    this.add(values[index]);\n  }\n}\nvar SetCache_default;\nvar init_SetCache = __esm({\n  \"node_modules/lodash-es/_SetCache.js\"() {\n    init_process_global();\n    init_MapCache();\n    init_setCacheAdd();\n    init_setCacheHas();\n    __name(SetCache, \"SetCache\");\n    SetCache.prototype.add = SetCache.prototype.push = setCacheAdd_default;\n    SetCache.prototype.has = setCacheHas_default;\n    SetCache_default = SetCache;\n  }\n});\n\n// node_modules/lodash-es/_arraySome.js\nfunction arraySome(array, predicate) {\n  var index = -1, length = array == null ? 0 : array.length;\n  while (++index < length) {\n    if (predicate(array[index], index, array)) {\n      return true;\n    }\n  }\n  return false;\n}\nvar arraySome_default;\nvar init_arraySome = __esm({\n  \"node_modules/lodash-es/_arraySome.js\"() {\n    init_process_global();\n    __name(arraySome, \"arraySome\");\n    arraySome_default = arraySome;\n  }\n});\n\n// node_modules/lodash-es/_cacheHas.js\nfunction cacheHas(cache, key) {\n  return cache.has(key);\n}\nvar cacheHas_default;\nvar init_cacheHas = __esm({\n  \"node_modules/lodash-es/_cacheHas.js\"() {\n    init_process_global();\n    __name(cacheHas, \"cacheHas\");\n    cacheHas_default = cacheHas;\n  }\n});\n\n// node_modules/lodash-es/_equalArrays.js\nfunction equalArrays(array, other, bitmask, customizer, equalFunc, stack) {\n  var isPartial = bitmask & COMPARE_PARTIAL_FLAG, arrLength = array.length, othLength = other.length;\n  if (arrLength != othLength && !(isPartial && othLength > arrLength)) {\n    return false;\n  }\n  var arrStacked = stack.get(array);\n  var othStacked = stack.get(other);\n  if (arrStacked && othStacked) {\n    return arrStacked == other && othStacked == array;\n  }\n  var index = -1, result = true, seen = bitmask & COMPARE_UNORDERED_FLAG ? new SetCache_default() : void 0;\n  stack.set(array, other);\n  stack.set(other, array);\n  while (++index < arrLength) {\n    var arrValue = array[index], othValue = other[index];\n    if (customizer) {\n      var compared = isPartial ? customizer(othValue, arrValue, index, other, array, stack) : customizer(arrValue, othValue, index, array, other, stack);\n    }\n    if (compared !== void 0) {\n      if (compared) {\n        continue;\n      }\n      result = false;\n      break;\n    }\n    if (seen) {\n      if (!arraySome_default(other, function(othValue2, othIndex) {\n        if (!cacheHas_default(seen, othIndex) && (arrValue === othValue2 || equalFunc(arrValue, othValue2, bitmask, customizer, stack))) {\n          return seen.push(othIndex);\n        }\n      })) {\n        result = false;\n        break;\n      }\n    } else if (!(arrValue === othValue || equalFunc(arrValue, othValue, bitmask, customizer, stack))) {\n      result = false;\n      break;\n    }\n  }\n  stack[\"delete\"](array);\n  stack[\"delete\"](other);\n  return result;\n}\nvar COMPARE_PARTIAL_FLAG, COMPARE_UNORDERED_FLAG, equalArrays_default;\nvar init_equalArrays = __esm({\n  \"node_modules/lodash-es/_equalArrays.js\"() {\n    init_process_global();\n    init_SetCache();\n    init_arraySome();\n    init_cacheHas();\n    COMPARE_PARTIAL_FLAG = 1;\n    COMPARE_UNORDERED_FLAG = 2;\n    __name(equalArrays, \"equalArrays\");\n    equalArrays_default = equalArrays;\n  }\n});\n\n// node_modules/lodash-es/_mapToArray.js\nfunction mapToArray(map) {\n  var index = -1, result = Array(map.size);\n  map.forEach(function(value, key) {\n    result[++index] = [key, value];\n  });\n  return result;\n}\nvar mapToArray_default;\nvar init_mapToArray = __esm({\n  \"node_modules/lodash-es/_mapToArray.js\"() {\n    init_process_global();\n    __name(mapToArray, \"mapToArray\");\n    mapToArray_default = mapToArray;\n  }\n});\n\n// node_modules/lodash-es/_setToArray.js\nfunction setToArray(set) {\n  var index = -1, result = Array(set.size);\n  set.forEach(function(value) {\n    result[++index] = value;\n  });\n  return result;\n}\nvar setToArray_default;\nvar init_setToArray = __esm({\n  \"node_modules/lodash-es/_setToArray.js\"() {\n    init_process_global();\n    __name(setToArray, \"setToArray\");\n    setToArray_default = setToArray;\n  }\n});\n\n// node_modules/lodash-es/_equalByTag.js\nfunction equalByTag(object, other, tag, bitmask, customizer, equalFunc, stack) {\n  switch (tag) {\n    case dataViewTag3:\n      if (object.byteLength != other.byteLength || object.byteOffset != other.byteOffset) {\n        return false;\n      }\n      object = object.buffer;\n      other = other.buffer;\n    case arrayBufferTag2:\n      if (object.byteLength != other.byteLength || !equalFunc(new Uint8Array_default(object), new Uint8Array_default(other))) {\n        return false;\n      }\n      return true;\n    case boolTag2:\n    case dateTag2:\n    case numberTag2:\n      return eq_default(+object, +other);\n    case errorTag2:\n      return object.name == other.name && object.message == other.message;\n    case regexpTag2:\n    case stringTag2:\n      return object == other + \"\";\n    case mapTag3:\n      var convert = mapToArray_default;\n    case setTag3:\n      var isPartial = bitmask & COMPARE_PARTIAL_FLAG2;\n      convert || (convert = setToArray_default);\n      if (object.size != other.size && !isPartial) {\n        return false;\n      }\n      var stacked = stack.get(object);\n      if (stacked) {\n        return stacked == other;\n      }\n      bitmask |= COMPARE_UNORDERED_FLAG2;\n      stack.set(object, other);\n      var result = equalArrays_default(convert(object), convert(other), bitmask, customizer, equalFunc, stack);\n      stack[\"delete\"](object);\n      return result;\n    case symbolTag:\n      if (symbolValueOf) {\n        return symbolValueOf.call(object) == symbolValueOf.call(other);\n      }\n  }\n  return false;\n}\nvar COMPARE_PARTIAL_FLAG2, COMPARE_UNORDERED_FLAG2, boolTag2, dateTag2, errorTag2, mapTag3, numberTag2, regexpTag2, setTag3, stringTag2, symbolTag, arrayBufferTag2, dataViewTag3, symbolProto, symbolValueOf, equalByTag_default;\nvar init_equalByTag = __esm({\n  \"node_modules/lodash-es/_equalByTag.js\"() {\n    init_process_global();\n    init_Symbol();\n    init_Uint8Array();\n    init_eq();\n    init_equalArrays();\n    init_mapToArray();\n    init_setToArray();\n    COMPARE_PARTIAL_FLAG2 = 1;\n    COMPARE_UNORDERED_FLAG2 = 2;\n    boolTag2 = \"[object Boolean]\";\n    dateTag2 = \"[object Date]\";\n    errorTag2 = \"[object Error]\";\n    mapTag3 = \"[object Map]\";\n    numberTag2 = \"[object Number]\";\n    regexpTag2 = \"[object RegExp]\";\n    setTag3 = \"[object Set]\";\n    stringTag2 = \"[object String]\";\n    symbolTag = \"[object Symbol]\";\n    arrayBufferTag2 = \"[object ArrayBuffer]\";\n    dataViewTag3 = \"[object DataView]\";\n    symbolProto = Symbol_default ? Symbol_default.prototype : void 0;\n    symbolValueOf = symbolProto ? symbolProto.valueOf : void 0;\n    __name(equalByTag, \"equalByTag\");\n    equalByTag_default = equalByTag;\n  }\n});\n\n// node_modules/lodash-es/_equalObjects.js\nfunction equalObjects(object, other, bitmask, customizer, equalFunc, stack) {\n  var isPartial = bitmask & COMPARE_PARTIAL_FLAG3, objProps = getAllKeys_default(object), objLength = objProps.length, othProps = getAllKeys_default(other), othLength = othProps.length;\n  if (objLength != othLength && !isPartial) {\n    return false;\n  }\n  var index = objLength;\n  while (index--) {\n    var key = objProps[index];\n    if (!(isPartial ? key in other : hasOwnProperty8.call(other, key))) {\n      return false;\n    }\n  }\n  var objStacked = stack.get(object);\n  var othStacked = stack.get(other);\n  if (objStacked && othStacked) {\n    return objStacked == other && othStacked == object;\n  }\n  var result = true;\n  stack.set(object, other);\n  stack.set(other, object);\n  var skipCtor = isPartial;\n  while (++index < objLength) {\n    key = objProps[index];\n    var objValue = object[key], othValue = other[key];\n    if (customizer) {\n      var compared = isPartial ? customizer(othValue, objValue, key, other, object, stack) : customizer(objValue, othValue, key, object, other, stack);\n    }\n    if (!(compared === void 0 ? objValue === othValue || equalFunc(objValue, othValue, bitmask, customizer, stack) : compared)) {\n      result = false;\n      break;\n    }\n    skipCtor || (skipCtor = key == \"constructor\");\n  }\n  if (result && !skipCtor) {\n    var objCtor = object.constructor, othCtor = other.constructor;\n    if (objCtor != othCtor && (\"constructor\" in object && \"constructor\" in other) && !(typeof objCtor == \"function\" && objCtor instanceof objCtor && typeof othCtor == \"function\" && othCtor instanceof othCtor)) {\n      result = false;\n    }\n  }\n  stack[\"delete\"](object);\n  stack[\"delete\"](other);\n  return result;\n}\nvar COMPARE_PARTIAL_FLAG3, objectProto11, hasOwnProperty8, equalObjects_default;\nvar init_equalObjects = __esm({\n  \"node_modules/lodash-es/_equalObjects.js\"() {\n    init_process_global();\n    init_getAllKeys();\n    COMPARE_PARTIAL_FLAG3 = 1;\n    objectProto11 = Object.prototype;\n    hasOwnProperty8 = objectProto11.hasOwnProperty;\n    __name(equalObjects, \"equalObjects\");\n    equalObjects_default = equalObjects;\n  }\n});\n\n// node_modules/lodash-es/_baseIsEqualDeep.js\nfunction baseIsEqualDeep(object, other, bitmask, customizer, equalFunc, stack) {\n  var objIsArr = isArray_default(object), othIsArr = isArray_default(other), objTag = objIsArr ? arrayTag2 : getTag_default(object), othTag = othIsArr ? arrayTag2 : getTag_default(other);\n  objTag = objTag == argsTag3 ? objectTag3 : objTag;\n  othTag = othTag == argsTag3 ? objectTag3 : othTag;\n  var objIsObj = objTag == objectTag3, othIsObj = othTag == objectTag3, isSameTag = objTag == othTag;\n  if (isSameTag && isBuffer_default(object)) {\n    if (!isBuffer_default(other)) {\n      return false;\n    }\n    objIsArr = true;\n    objIsObj = false;\n  }\n  if (isSameTag && !objIsObj) {\n    stack || (stack = new Stack_default());\n    return objIsArr || isTypedArray_default(object) ? equalArrays_default(object, other, bitmask, customizer, equalFunc, stack) : equalByTag_default(object, other, objTag, bitmask, customizer, equalFunc, stack);\n  }\n  if (!(bitmask & COMPARE_PARTIAL_FLAG4)) {\n    var objIsWrapped = objIsObj && hasOwnProperty9.call(object, \"__wrapped__\"), othIsWrapped = othIsObj && hasOwnProperty9.call(other, \"__wrapped__\");\n    if (objIsWrapped || othIsWrapped) {\n      var objUnwrapped = objIsWrapped ? object.value() : object, othUnwrapped = othIsWrapped ? other.value() : other;\n      stack || (stack = new Stack_default());\n      return equalFunc(objUnwrapped, othUnwrapped, bitmask, customizer, stack);\n    }\n  }\n  if (!isSameTag) {\n    return false;\n  }\n  stack || (stack = new Stack_default());\n  return equalObjects_default(object, other, bitmask, customizer, equalFunc, stack);\n}\nvar COMPARE_PARTIAL_FLAG4, argsTag3, arrayTag2, objectTag3, objectProto12, hasOwnProperty9, baseIsEqualDeep_default;\nvar init_baseIsEqualDeep = __esm({\n  \"node_modules/lodash-es/_baseIsEqualDeep.js\"() {\n    init_process_global();\n    init_Stack();\n    init_equalArrays();\n    init_equalByTag();\n    init_equalObjects();\n    init_getTag();\n    init_isArray();\n    init_isBuffer();\n    init_isTypedArray();\n    COMPARE_PARTIAL_FLAG4 = 1;\n    argsTag3 = \"[object Arguments]\";\n    arrayTag2 = \"[object Array]\";\n    objectTag3 = \"[object Object]\";\n    objectProto12 = Object.prototype;\n    hasOwnProperty9 = objectProto12.hasOwnProperty;\n    __name(baseIsEqualDeep, \"baseIsEqualDeep\");\n    baseIsEqualDeep_default = baseIsEqualDeep;\n  }\n});\n\n// node_modules/lodash-es/_baseIsEqual.js\nfunction baseIsEqual(value, other, bitmask, customizer, stack) {\n  if (value === other) {\n    return true;\n  }\n  if (value == null || other == null || !isObjectLike_default(value) && !isObjectLike_default(other)) {\n    return value !== value && other !== other;\n  }\n  return baseIsEqualDeep_default(value, other, bitmask, customizer, baseIsEqual, stack);\n}\nvar baseIsEqual_default;\nvar init_baseIsEqual = __esm({\n  \"node_modules/lodash-es/_baseIsEqual.js\"() {\n    init_process_global();\n    init_baseIsEqualDeep();\n    init_isObjectLike();\n    __name(baseIsEqual, \"baseIsEqual\");\n    baseIsEqual_default = baseIsEqual;\n  }\n});\n\n// node_modules/lodash-es/isEqual.js\nfunction isEqual(value, other) {\n  return baseIsEqual_default(value, other);\n}\nvar isEqual_default;\nvar init_isEqual = __esm({\n  \"node_modules/lodash-es/isEqual.js\"() {\n    init_process_global();\n    init_baseIsEqual();\n    __name(isEqual, \"isEqual\");\n    isEqual_default = isEqual;\n  }\n});\n\n// node_modules/lodash-es/lodash.js\nvar init_lodash = __esm({\n  \"node_modules/lodash-es/lodash.js\"() {\n    init_process_global();\n    init_isEqual();\n    /**\n     * @license\n     * Lodash (Custom Build) <https://lodash.com/>\n     * Build: `lodash modularize exports=\"es\" -o ./`\n     * Copyright OpenJS Foundation and other contributors <https://openjsf.org/>\n     * Released under MIT license <https://lodash.com/license>\n     * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>\n     * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors\n     */\n  }\n});\n\n// core/lib/lh-env.js\nimport process4 from \"process\";\nvar isUnderTest;\nvar init_lh_env = __esm({\n  \"core/lib/lh-env.js\"() {\n    \"use strict\";\n    init_process_global();\n    /**\n     * @license\n     * Copyright 2020 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    isUnderTest = !!process4.env.CI || process4.env.NODE_ENV === \"test\";\n  }\n});\n\n// shared/statistics.js\nfunction erf(x) {\n  const sign = Math.sign(x);\n  x = Math.abs(x);\n  const a1 = 0.254829592;\n  const a2 = -0.284496736;\n  const a3 = 1.421413741;\n  const a4 = -1.453152027;\n  const a5 = 1.061405429;\n  const p = 0.3275911;\n  const t = 1 / (1 + p * x);\n  const y = t * (a1 + t * (a2 + t * (a3 + t * (a4 + t * a5))));\n  return sign * (1 - y * Math.exp(-x * x));\n}\nfunction getLogNormalScore({ median, p10 }, value) {\n  if (median <= 0) throw new Error(\"median must be greater than zero\");\n  if (p10 <= 0) throw new Error(\"p10 must be greater than zero\");\n  if (p10 >= median) throw new Error(\"p10 must be less than the median\");\n  if (value <= 0) return 1;\n  const INVERSE_ERFC_ONE_FIFTH = 0.9061938024368232;\n  const xRatio = Math.max(Number.MIN_VALUE, value / median);\n  const xLogRatio = Math.log(xRatio);\n  const p10Ratio = Math.max(Number.MIN_VALUE, p10 / median);\n  const p10LogRatio = -Math.log(p10Ratio);\n  const standardizedX = xLogRatio * INVERSE_ERFC_ONE_FIFTH / p10LogRatio;\n  const complementaryPercentile = (1 - erf(standardizedX)) / 2;\n  let score;\n  if (value <= p10) {\n    score = Math.max(MIN_PASSING_SCORE, Math.min(1, complementaryPercentile));\n  } else if (value <= median) {\n    score = Math.max(MIN_AVERAGE_SCORE, Math.min(MAX_AVERAGE_SCORE, complementaryPercentile));\n  } else {\n    score = Math.max(0, Math.min(MAX_FAILING_SCORE, complementaryPercentile));\n  }\n  return score;\n}\nvar MIN_PASSING_SCORE, MAX_AVERAGE_SCORE, MIN_AVERAGE_SCORE, MAX_FAILING_SCORE;\nvar init_statistics = __esm({\n  \"shared/statistics.js\"() {\n    \"use strict\";\n    init_process_global();\n    /**\n     * @license\n     * Copyright 2017 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    MIN_PASSING_SCORE = 0.9;\n    MAX_AVERAGE_SCORE = 0.8999999999999999;\n    MIN_AVERAGE_SCORE = 0.5;\n    MAX_FAILING_SCORE = 0.49999999999999994;\n    __name(erf, \"erf\");\n    __name(getLogNormalScore, \"getLogNormalScore\");\n  }\n});\n\n// shared/util.js\nvar ELLIPSIS, NBSP, PASS_THRESHOLD, RATINGS, listOfTlds, Util;\nvar init_util = __esm({\n  \"shared/util.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_statistics();\n    /**\n     * @license\n     * Copyright 2017 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    ELLIPSIS = \"…\";\n    NBSP = \" \";\n    PASS_THRESHOLD = 0.9;\n    RATINGS = {\n      PASS: { label: \"pass\", minScore: PASS_THRESHOLD },\n      AVERAGE: { label: \"average\", minScore: 0.5 },\n      FAIL: { label: \"fail\" },\n      ERROR: { label: \"error\" }\n    };\n    listOfTlds = [\n      \"com\",\n      \"co\",\n      \"gov\",\n      \"edu\",\n      \"ac\",\n      \"org\",\n      \"go\",\n      \"gob\",\n      \"or\",\n      \"net\",\n      \"in\",\n      \"ne\",\n      \"nic\",\n      \"gouv\",\n      \"web\",\n      \"spb\",\n      \"blog\",\n      \"jus\",\n      \"kiev\",\n      \"mil\",\n      \"wi\",\n      \"qc\",\n      \"ca\",\n      \"bel\",\n      \"on\"\n    ];\n    Util = class _Util {\n      static {\n        __name(this, \"Util\");\n      }\n      static get RATINGS() {\n        return RATINGS;\n      }\n      static get PASS_THRESHOLD() {\n        return PASS_THRESHOLD;\n      }\n      static get MS_DISPLAY_VALUE() {\n        return `%10d${NBSP}ms`;\n      }\n      /**\n       * If LHR is older than 10.0 it will not have the `finalDisplayedUrl` property.\n       * Old LHRs should have the `finalUrl` property which will work fine for the report.\n       *\n       * @param {LH.Result} lhr\n       */\n      static getFinalDisplayedUrl(lhr) {\n        if (lhr.finalDisplayedUrl) return lhr.finalDisplayedUrl;\n        if (lhr.finalUrl) return lhr.finalUrl;\n        throw new Error(\"Could not determine final displayed URL\");\n      }\n      /**\n       * If LHR is older than 10.0 it will not have the `mainDocumentUrl` property.\n       * Old LHRs should have the `finalUrl` property which is the same as `mainDocumentUrl`.\n       *\n       * @param {LH.Result} lhr\n       */\n      static getMainDocumentUrl(lhr) {\n        return lhr.mainDocumentUrl || lhr.finalUrl;\n      }\n      /**\n       * @param {LH.Result} lhr\n       * @return {LH.Result.FullPageScreenshot=}\n       */\n      static getFullPageScreenshot(lhr) {\n        if (lhr.fullPageScreenshot) {\n          return lhr.fullPageScreenshot;\n        }\n        const details = (\n          /** @type {LH.Result.FullPageScreenshot=} */\n          lhr.audits[\"full-page-screenshot\"]?.details\n        );\n        return details;\n      }\n      /**\n       * Given the entity classification dataset and a URL, identify the entity.\n       * @param {string} url\n       * @param {LH.Result.Entities=} entities\n       * @return {LH.Result.LhrEntity|string}\n       */\n      static getEntityFromUrl(url, entities) {\n        if (!entities) {\n          return _Util.getPseudoRootDomain(url);\n        }\n        const entity = entities.find((e) => e.origins.find((origin) => url.startsWith(origin)));\n        return entity || _Util.getPseudoRootDomain(url);\n      }\n      /**\n       * Split a string by markdown code spans (enclosed in `backticks`), splitting\n       * into segments that were enclosed in backticks (marked as `isCode === true`)\n       * and those that outside the backticks (`isCode === false`).\n       * @param {string} text\n       * @return {Array<{isCode: true, text: string}|{isCode: false, text: string}>}\n       */\n      static splitMarkdownCodeSpans(text) {\n        const segments = [];\n        const parts = text.split(/`(.*?)`/g);\n        for (let i = 0; i < parts.length; i++) {\n          const text2 = parts[i];\n          if (!text2) continue;\n          const isCode = i % 2 !== 0;\n          segments.push({\n            isCode,\n            text: text2\n          });\n        }\n        return segments;\n      }\n      /**\n       * Split a string on markdown links (e.g. [some link](https://...)) into\n       * segments of plain text that weren't part of a link (marked as\n       * `isLink === false`), and segments with text content and a URL that did make\n       * up a link (marked as `isLink === true`).\n       * @param {string} text\n       * @return {Array<{isLink: true, text: string, linkHref: string}|{isLink: false, text: string}>}\n       */\n      static splitMarkdownLink(text) {\n        const segments = [];\n        const parts = text.split(/\\[([^\\]]+?)\\]\\((https?:\\/\\/.*?)\\)/g);\n        while (parts.length) {\n          const [preambleText, linkText, linkHref] = parts.splice(0, 3);\n          if (preambleText) {\n            segments.push({\n              isLink: false,\n              text: preambleText\n            });\n          }\n          if (linkText && linkHref) {\n            segments.push({\n              isLink: true,\n              text: linkText,\n              linkHref\n            });\n          }\n        }\n        return segments;\n      }\n      /**\n       * @param {string} string\n       * @param {number} characterLimit\n       * @param {string} ellipseSuffix\n       */\n      static truncate(string, characterLimit, ellipseSuffix = \"…\") {\n        if (string.length <= characterLimit) {\n          return string;\n        }\n        const segmenter = new Intl.Segmenter(void 0, { granularity: \"grapheme\" });\n        const iterator = segmenter.segment(string)[Symbol.iterator]();\n        let lastSegmentIndex = 0;\n        for (let i = 0; i <= characterLimit - ellipseSuffix.length; i++) {\n          const result = iterator.next();\n          if (result.done) {\n            return string;\n          }\n          lastSegmentIndex = result.value.index;\n        }\n        for (let i = 0; i < ellipseSuffix.length; i++) {\n          if (iterator.next().done) {\n            return string;\n          }\n        }\n        return string.slice(0, lastSegmentIndex) + ellipseSuffix;\n      }\n      /**\n       * @param {URL} parsedUrl\n       * @param {{numPathParts?: number, preserveQuery?: boolean, preserveHost?: boolean}=} options\n       * @return {string}\n       */\n      static getURLDisplayName(parsedUrl, options) {\n        options = options || {\n          numPathParts: void 0,\n          preserveQuery: void 0,\n          preserveHost: void 0\n        };\n        const numPathParts = options.numPathParts !== void 0 ? options.numPathParts : 2;\n        const preserveQuery = options.preserveQuery !== void 0 ? options.preserveQuery : true;\n        const preserveHost = options.preserveHost || false;\n        let name;\n        if (parsedUrl.protocol === \"about:\" || parsedUrl.protocol === \"data:\") {\n          name = parsedUrl.href;\n        } else {\n          name = parsedUrl.pathname;\n          const parts = name.split(\"/\").filter((part) => part.length);\n          if (numPathParts && parts.length > numPathParts) {\n            name = ELLIPSIS + parts.slice(-1 * numPathParts).join(\"/\");\n          }\n          if (preserveHost) {\n            name = `${parsedUrl.host}/${name.replace(/^\\//, \"\")}`;\n          }\n          if (preserveQuery) {\n            name = `${name}${parsedUrl.search}`;\n          }\n        }\n        const MAX_LENGTH = 64;\n        if (parsedUrl.protocol !== \"data:\") {\n          name = name.slice(0, 200);\n          name = name.replace(/([a-f0-9]{7})[a-f0-9]{13}[a-f0-9]*/g, `$1${ELLIPSIS}`);\n          name = name.replace(\n            /([a-zA-Z0-9-_]{9})(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])[a-zA-Z0-9-_]{10,}/g,\n            `$1${ELLIPSIS}`\n          );\n          name = name.replace(/(\\d{3})\\d{6,}/g, `$1${ELLIPSIS}`);\n          name = name.replace(/\\u2026+/g, ELLIPSIS);\n          if (name.length > MAX_LENGTH && name.includes(\"?\")) {\n            name = name.replace(/\\?([^=]*)(=)?.*/, `?$1$2${ELLIPSIS}`);\n            if (name.length > MAX_LENGTH) {\n              name = name.replace(/\\?.*/, `?${ELLIPSIS}`);\n            }\n          }\n        }\n        if (name.length > MAX_LENGTH) {\n          const dotIndex = name.lastIndexOf(\".\");\n          if (dotIndex >= 0) {\n            name = name.slice(0, MAX_LENGTH - 1 - (name.length - dotIndex)) + // Show file extension\n            `${ELLIPSIS}${name.slice(dotIndex)}`;\n          } else {\n            name = name.slice(0, MAX_LENGTH - 1) + ELLIPSIS;\n          }\n        }\n        return name;\n      }\n      /**\n       * Returns the origin portion of a Chrome extension URL.\n       * @param {string} url\n       * @return {string}\n       */\n      static getChromeExtensionOrigin(url) {\n        const parsedUrl = new URL(url);\n        return parsedUrl.protocol + \"//\" + parsedUrl.host;\n      }\n      /**\n       * Split a URL into a file, hostname and origin for easy display.\n       * @param {string} url\n       * @return {{file: string, hostname: string, origin: string}}\n       */\n      static parseURL(url) {\n        const parsedUrl = new URL(url);\n        return {\n          file: _Util.getURLDisplayName(parsedUrl),\n          hostname: parsedUrl.hostname,\n          // Node's URL parsing behavior is different than Chrome and returns 'null'\n          // for chrome-extension:// URLs. See https://github.com/nodejs/node/issues/21955.\n          origin: parsedUrl.protocol === \"chrome-extension:\" ? _Util.getChromeExtensionOrigin(url) : parsedUrl.origin\n        };\n      }\n      /**\n       * @param {string|URL} value\n       * @return {!URL}\n       */\n      static createOrReturnURL(value) {\n        if (value instanceof URL) {\n          return value;\n        }\n        return new URL(value);\n      }\n      /**\n       * Gets the tld of a domain\n       * This function is used only while rendering pre-10.0 LHRs.\n       *\n       * @param {string} hostname\n       * @return {string} tld\n       */\n      static getPseudoTld(hostname) {\n        const tlds = hostname.split(\".\").slice(-2);\n        if (!listOfTlds.includes(tlds[0])) {\n          return `.${tlds[tlds.length - 1]}`;\n        }\n        return `.${tlds.join(\".\")}`;\n      }\n      /**\n       * Returns a primary domain for provided hostname (e.g. www.example.com -> example.com).\n       * As it doesn't consult the Public Suffix List, it can sometimes lose detail.\n       * See the `listOfTlds` comment above for more.\n       * This function is used only while rendering pre-10.0 LHRs. See UrlUtils.getRootDomain\n       * for the current method that makes use of PSL.\n       * @param {string|URL} url hostname or URL object\n       * @return {string}\n       */\n      static getPseudoRootDomain(url) {\n        const hostname = _Util.createOrReturnURL(url).hostname;\n        const tld = _Util.getPseudoTld(hostname);\n        const splitTld = tld.split(\".\");\n        return hostname.split(\".\").slice(-splitTld.length).join(\".\");\n      }\n      /**\n       * Returns only lines that are near a message, or the first few lines if there are\n       * no line messages.\n       * @param {SnippetValue['lines']} lines\n       * @param {SnippetValue['lineMessages']} lineMessages\n       * @param {number} surroundingLineCount Number of lines to include before and after\n       * the message. If this is e.g. 2 this function might return 5 lines.\n       */\n      static filterRelevantLines(lines, lineMessages, surroundingLineCount) {\n        if (lineMessages.length === 0) {\n          return lines.slice(0, surroundingLineCount * 2 + 1);\n        }\n        const minGapSize = 3;\n        const lineNumbersToKeep = /* @__PURE__ */ new Set();\n        lineMessages = lineMessages.sort((a, b) => (a.lineNumber || 0) - (b.lineNumber || 0));\n        lineMessages.forEach(({ lineNumber }) => {\n          let firstSurroundingLineNumber = lineNumber - surroundingLineCount;\n          let lastSurroundingLineNumber = lineNumber + surroundingLineCount;\n          while (firstSurroundingLineNumber < 1) {\n            firstSurroundingLineNumber++;\n            lastSurroundingLineNumber++;\n          }\n          if (lineNumbersToKeep.has(firstSurroundingLineNumber - minGapSize - 1)) {\n            firstSurroundingLineNumber -= minGapSize;\n          }\n          for (let i = firstSurroundingLineNumber; i <= lastSurroundingLineNumber; i++) {\n            const surroundingLineNumber = i;\n            lineNumbersToKeep.add(surroundingLineNumber);\n          }\n        });\n        return lines.filter((line) => lineNumbersToKeep.has(line.lineNumber));\n      }\n      /**\n       * Computes a score between 0 and 1 based on the measured `value`. Score is determined by\n       * considering a log-normal distribution governed by two control points (the 10th\n       * percentile value and the median value) and represents the percentage of sites that are\n       * greater than `value`.\n       *\n       * Score characteristics:\n       * - within [0, 1]\n       * - rounded to two digits\n       * - value must meet or beat a controlPoint value to meet or exceed its percentile score:\n       *   - value > median will give a score < 0.5; value ≤ median will give a score ≥ 0.5.\n       *   - value > p10 will give a score < 0.9; value ≤ p10 will give a score ≥ 0.9.\n       * - values < p10 will get a slight boost so a score of 1 is achievable by a\n       *   `value` other than those close to 0. Scores of > ~0.99524 end up rounded to 1.\n       * @param {{median: number, p10: number}} controlPoints\n       * @param {number} value\n       * @return {number}\n       */\n      static computeLogNormalScore(controlPoints, value) {\n        let percentile = getLogNormalScore(controlPoints, value);\n        if (percentile > 0.9) {\n          percentile += 0.05 * (percentile - 0.9);\n        }\n        return Math.floor(percentile * 100) / 100;\n      }\n    };\n  }\n});\n\n// core/audits/audit.js\nvar METRIC_SAVINGS_PRECISION, clampTo2Decimals, Audit;\nvar init_audit = __esm({\n  \"core/audits/audit.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_lh();\n    init_lh_env();\n    init_util();\n    /**\n     * @license\n     * Copyright 2016 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    METRIC_SAVINGS_PRECISION = {\n      FCP: 50,\n      LCP: 50,\n      INP: 50,\n      TBT: 50,\n      CLS: 1e-3\n    };\n    clampTo2Decimals = /* @__PURE__ */ __name((val) => Math.round(val * 100) / 100, \"clampTo2Decimals\");\n    Audit = class _Audit {\n      static {\n        __name(this, \"Audit\");\n      }\n      /**\n       * @return {LH.Audit.ScoreDisplayModes}\n       */\n      static get SCORING_MODES() {\n        return {\n          NUMERIC: \"numeric\",\n          METRIC_SAVINGS: \"metricSavings\",\n          BINARY: \"binary\",\n          MANUAL: \"manual\",\n          INFORMATIVE: \"informative\",\n          NOT_APPLICABLE: \"notApplicable\",\n          ERROR: \"error\"\n        };\n      }\n      /**\n       * @return {LH.Audit.Meta}\n       */\n      static get meta() {\n        throw new Error(\"Audit meta information must be overridden.\");\n      }\n      /**\n       * @return {Object}\n       */\n      static get defaultOptions() {\n        return {};\n      }\n      /* eslint-disable no-unused-vars */\n      /**\n       *\n       * @param {LH.Artifacts} artifacts\n       * @param {LH.Audit.Context} context\n       * @return {LH.Audit.Product|Promise<LH.Audit.Product>}\n       */\n      static audit(artifacts, context) {\n        throw new Error(\"audit() method must be overridden\");\n      }\n      /* eslint-enable no-unused-vars */\n      /**\n       * Computes a score between 0 and 1 based on the measured `value`. Score is determined by\n       * considering a log-normal distribution governed by two control points (the 10th\n       * percentile value and the median value) and represents the percentage of sites that are\n       * greater than `value`.\n       *\n       * Score characteristics:\n       * - within [0, 1]\n       * - rounded to two digits\n       * - value must meet or beat a controlPoint value to meet or exceed its percentile score:\n       *   - value > median will give a score < 0.5; value ≤ median will give a score ≥ 0.5.\n       *   - value > p10 will give a score < 0.9; value ≤ p10 will give a score ≥ 0.9.\n       * - values < p10 will get a slight boost so a score of 1 is achievable by a\n       *   `value` other than those close to 0. Scores of > ~0.99524 end up rounded to 1.\n       * @param {{median: number, p10: number}} controlPoints\n       * @param {number} value\n       * @return {number}\n       */\n      static computeLogNormalScore(controlPoints, value) {\n        return Util.computeLogNormalScore(controlPoints, value);\n      }\n      /**\n       * This catches typos in the `key` property of a heading definition of table/opportunity details.\n       * Throws an error if any of keys referenced by headings don't exist in at least one of the items.\n       *\n       * @param {LH.Audit.Details.Table['headings']|LH.Audit.Details.Opportunity['headings']} headings\n       * @param {LH.Audit.Details.Opportunity['items']|LH.Audit.Details.Table['items']} items\n       */\n      static assertHeadingKeysExist(headings, items) {\n        if (!items.length) return;\n        if (!isUnderTest) return;\n        for (const heading of headings) {\n          if (heading.key === null) continue;\n          const key = heading.key;\n          if (items.some((item) => key in item)) continue;\n          throw new Error(`\"${heading.key}\" is missing from items`);\n        }\n      }\n      /**\n       * @param {LH.Audit.Details.Checklist['items']} items\n       * @return {LH.Audit.Details.Checklist}\n       */\n      static makeChecklistDetails(items) {\n        return {\n          type: \"checklist\",\n          items\n        };\n      }\n      /**\n       * @param {LH.Audit.Details.Table['headings']} headings\n       * @param {LH.Audit.Details.Table['items']} results\n       * @param {TableOptions=} options\n       * @return {LH.Audit.Details.Table}\n       */\n      static makeTableDetails(headings, results, options = {}) {\n        const { wastedBytes, wastedMs, sortedBy, skipSumming, isEntityGrouped } = options;\n        const summary = wastedBytes || wastedMs ? { wastedBytes, wastedMs } : void 0;\n        if (results.length === 0) {\n          return {\n            type: \"table\",\n            headings,\n            items: [],\n            summary\n          };\n        }\n        _Audit.assertHeadingKeysExist(headings, results);\n        return {\n          type: \"table\",\n          headings,\n          items: results,\n          summary,\n          sortedBy,\n          skipSumming,\n          isEntityGrouped\n        };\n      }\n      /**\n       * @param {LH.Audit.Details.List['items']} items\n       * @return {LH.Audit.Details.List}\n       */\n      static makeListDetails(items) {\n        return {\n          type: \"list\",\n          items\n        };\n      }\n      /**\n       * @param {LH.IcuMessage | string=} title\n       * @param {LH.IcuMessage | string=} description\n       * @param {LH.Audit.Details.ListableDetail} value\n       * @return {LH.Audit.Details.ListSectionItem}\n       */\n      static makeListDetailSectionItem(value, title, description) {\n        return {\n          type: \"list-section\",\n          title,\n          description,\n          value\n        };\n      }\n      /** @typedef {{\n       * content: string;\n       * title: string;\n       * lineMessages: LH.Audit.Details.SnippetValue['lineMessages'];\n       * generalMessages: LH.Audit.Details.SnippetValue['generalMessages'];\n       * node?: LH.Audit.Details.NodeValue;\n       * maxLineLength?: number;\n       * maxLinesAroundMessage?: number;\n       * }} SnippetInfo */\n      /**\n       * @param {SnippetInfo} snippetInfo\n       * @return {LH.Audit.Details.SnippetValue}\n       */\n      static makeSnippetDetails({\n        content,\n        title,\n        lineMessages,\n        generalMessages,\n        node,\n        maxLineLength = 200,\n        maxLinesAroundMessage = 20\n      }) {\n        const allLines = _Audit._makeSnippetLinesArray(content, maxLineLength);\n        const lines = Util.filterRelevantLines(allLines, lineMessages, maxLinesAroundMessage);\n        return {\n          type: \"snippet\",\n          lines,\n          title,\n          lineMessages,\n          generalMessages,\n          lineCount: allLines.length,\n          node\n        };\n      }\n      /**\n       * @param {string} content\n       * @param {number} maxLineLength\n       * @return {LH.Audit.Details.SnippetValue['lines']}\n       */\n      static _makeSnippetLinesArray(content, maxLineLength) {\n        return content.split(\"\\n\").map((line, lineIndex) => {\n          const lineNumber = lineIndex + 1;\n          const lineDetail = {\n            content: Util.truncate(line, maxLineLength),\n            lineNumber\n          };\n          if (line.length > maxLineLength) {\n            lineDetail.truncated = true;\n          }\n          return lineDetail;\n        });\n      }\n      /**\n       * @param {LH.Audit.Details.Opportunity['headings']} headings\n       * @param {LH.Audit.Details.Opportunity['items']} items\n       * @param {OpportunityOptions} options\n       * @return {LH.Audit.Details.Opportunity}\n       */\n      static makeOpportunityDetails(headings, items, options) {\n        _Audit.assertHeadingKeysExist(headings, items);\n        const { overallSavingsMs, overallSavingsBytes, sortedBy, skipSumming, isEntityGrouped } = options;\n        return {\n          type: \"opportunity\",\n          headings: items.length === 0 ? [] : headings,\n          items,\n          overallSavingsMs,\n          overallSavingsBytes,\n          sortedBy,\n          skipSumming,\n          isEntityGrouped\n        };\n      }\n      /**\n       * @param {LH.Artifacts.NodeDetails} node\n       * @return {LH.Audit.Details.NodeValue}\n       */\n      static makeNodeItem(node) {\n        return {\n          type: \"node\",\n          lhId: node.lhId,\n          path: node.devtoolsNodePath,\n          selector: node.selector,\n          boundingRect: node.boundingRect,\n          snippet: node.snippet,\n          nodeLabel: node.nodeLabel\n        };\n      }\n      /**\n       * @param {LH.Artifacts.Bundle} bundle\n       * @param {number} generatedLine\n       * @param {number} generatedColumn\n       * @return {LH.Audit.Details.SourceLocationValue['original']}\n       */\n      static _findOriginalLocation(bundle, generatedLine, generatedColumn) {\n        const entry = bundle?.map.findEntry(generatedLine, generatedColumn);\n        if (!entry) return;\n        return {\n          file: entry.sourceURL || \"\",\n          line: entry.sourceLineNumber || 0,\n          column: entry.sourceColumnNumber || 0\n        };\n      }\n      /**\n       * @param {string} url\n       * @param {number} line 0-indexed\n       * @param {number} column 0-indexed\n       * @param {LH.Artifacts.Bundle=} bundle\n       * @return {LH.Audit.Details.SourceLocationValue}\n       */\n      static makeSourceLocation(url, line, column, bundle) {\n        return {\n          type: \"source-location\",\n          url,\n          urlProvider: \"network\",\n          line,\n          column,\n          original: bundle && this._findOriginalLocation(bundle, line, column)\n        };\n      }\n      /**\n       * @param {LH.Artifacts.ConsoleMessage} entry\n       * @param {LH.Artifacts.Bundle=} bundle\n       * @return {LH.Audit.Details.SourceLocationValue | undefined}\n       */\n      static makeSourceLocationFromConsoleMessage(entry, bundle) {\n        if (!entry.url) return;\n        const line = entry.lineNumber || 0;\n        const column = entry.columnNumber || 0;\n        return this.makeSourceLocation(entry.url, line, column, bundle);\n      }\n      /**\n       * @param {number|null} score\n       * @param {LH.Audit.ScoreDisplayMode} scoreDisplayMode\n       * @param {string} auditId\n       * @return {number|null}\n       */\n      static _normalizeAuditScore(score, scoreDisplayMode, auditId) {\n        if (scoreDisplayMode === _Audit.SCORING_MODES.INFORMATIVE) {\n          return 1;\n        }\n        if (scoreDisplayMode !== _Audit.SCORING_MODES.BINARY && scoreDisplayMode !== _Audit.SCORING_MODES.NUMERIC && scoreDisplayMode !== _Audit.SCORING_MODES.METRIC_SAVINGS) {\n          return null;\n        }\n        if (score === null || !Number.isFinite(score)) {\n          throw new Error(`Invalid score for ${auditId}: ${score}`);\n        }\n        if (score > 1) throw new Error(`Audit score for ${auditId} is > 1`);\n        if (score < 0) throw new Error(`Audit score for ${auditId} is < 0`);\n        score = clampTo2Decimals(score);\n        return score;\n      }\n      /**\n       * @param {LH.Audit.ProductMetricSavings|undefined} metricSavings\n       * @return {LH.Audit.ProductMetricSavings|undefined}\n       */\n      static _quantizeMetricSavings(metricSavings) {\n        if (!metricSavings) return;\n        const normalizedMetricSavings = { ...metricSavings };\n        for (\n          const key of\n          /** @type {Array<keyof LH.Audit.ProductMetricSavings>} */\n          Object.keys(metricSavings)\n        ) {\n          let value = metricSavings[key];\n          if (value === void 0) continue;\n          value = Math.max(value, 0);\n          const precision = METRIC_SAVINGS_PRECISION[key];\n          if (precision !== void 0) {\n            value = Math.round(value / precision) * precision;\n          }\n          normalizedMetricSavings[key] = value;\n        }\n        return normalizedMetricSavings;\n      }\n      /**\n       * @param {typeof Audit} audit\n       * @param {string | LH.IcuMessage} errorMessage\n       * @param {string=} errorStack\n       * @return {LH.RawIcu<LH.Audit.Result>}\n       */\n      static generateErrorAuditResult(audit, errorMessage, errorStack) {\n        return _Audit.generateAuditResult(audit, {\n          score: null,\n          errorMessage,\n          errorStack\n        });\n      }\n      /**\n       * @param {typeof Audit} audit\n       * @param {LH.Audit.Product} product\n       * @return {LH.RawIcu<LH.Audit.Result>}\n       */\n      static generateAuditResult(audit, product) {\n        if (product.score === void 0) {\n          throw new Error(\"generateAuditResult requires a score\");\n        }\n        let scoreDisplayMode = audit.meta.scoreDisplayMode || _Audit.SCORING_MODES.BINARY;\n        let score = product.score;\n        if (product.errorMessage !== void 0) {\n          scoreDisplayMode = _Audit.SCORING_MODES.ERROR;\n        } else if (product.notApplicable) {\n          scoreDisplayMode = _Audit.SCORING_MODES.NOT_APPLICABLE;\n        } else if (product.scoreDisplayMode) {\n          scoreDisplayMode = product.scoreDisplayMode;\n        }\n        const metricSavings = _Audit._quantizeMetricSavings(product.metricSavings);\n        const hasSomeSavings = Object.values(metricSavings || {}).some((v) => v);\n        if (scoreDisplayMode === _Audit.SCORING_MODES.METRIC_SAVINGS) {\n          if (score && score >= Util.PASS_THRESHOLD) {\n            score = 1;\n          } else if (hasSomeSavings) {\n            score = 0;\n          } else {\n            score = 0.5;\n          }\n        }\n        score = _Audit._normalizeAuditScore(score, scoreDisplayMode, audit.meta.id);\n        let auditTitle = audit.meta.title;\n        if (audit.meta.failureTitle) {\n          if (score !== null && score < Util.PASS_THRESHOLD) {\n            auditTitle = audit.meta.failureTitle;\n          }\n        }\n        const numericProduct = \"numericUnit\" in product ? product : void 0;\n        return {\n          id: audit.meta.id,\n          title: auditTitle,\n          description: audit.meta.description,\n          score,\n          scoreDisplayMode,\n          numericValue: numericProduct?.numericValue,\n          numericUnit: numericProduct?.numericUnit,\n          displayValue: product.displayValue,\n          explanation: product.explanation,\n          errorMessage: product.errorMessage,\n          errorStack: product.errorStack,\n          warnings: product.warnings,\n          scoringOptions: product.scoringOptions,\n          metricSavings,\n          details: product.details,\n          guidanceLevel: audit.meta.guidanceLevel\n        };\n      }\n      /**\n       * @param {LH.Artifacts} artifacts\n       * @param {LH.Audit.Context} context\n       * @returns {LH.Artifacts.MetricComputationDataInput}\n       */\n      static makeMetricComputationDataInput(artifacts, context) {\n        const trace = artifacts.Trace;\n        const devtoolsLog = artifacts.DevtoolsLog;\n        const gatherContext = artifacts.GatherContext;\n        const { URL: URL3, HostDPR, SourceMaps: SourceMaps2 } = artifacts;\n        return { trace, devtoolsLog, gatherContext, settings: context.settings, URL: URL3, SourceMaps: SourceMaps2, HostDPR, simulator: null };\n      }\n    };\n  }\n});\n\n// node_modules/intl-messageformat/node_modules/tslib/tslib.es6.mjs\nvar tslib_es6_exports = {};\n__export(tslib_es6_exports, {\n  __addDisposableResource: () => __addDisposableResource,\n  __assign: () => __assign,\n  __asyncDelegator: () => __asyncDelegator,\n  __asyncGenerator: () => __asyncGenerator,\n  __asyncValues: () => __asyncValues,\n  __await: () => __await,\n  __awaiter: () => __awaiter,\n  __classPrivateFieldGet: () => __classPrivateFieldGet,\n  __classPrivateFieldIn: () => __classPrivateFieldIn,\n  __classPrivateFieldSet: () => __classPrivateFieldSet,\n  __createBinding: () => __createBinding,\n  __decorate: () => __decorate,\n  __disposeResources: () => __disposeResources,\n  __esDecorate: () => __esDecorate,\n  __exportStar: () => __exportStar,\n  __extends: () => __extends,\n  __generator: () => __generator,\n  __importDefault: () => __importDefault,\n  __importStar: () => __importStar,\n  __makeTemplateObject: () => __makeTemplateObject,\n  __metadata: () => __metadata,\n  __param: () => __param,\n  __propKey: () => __propKey,\n  __read: () => __read,\n  __rest: () => __rest,\n  __runInitializers: () => __runInitializers,\n  __setFunctionName: () => __setFunctionName,\n  __spread: () => __spread,\n  __spreadArray: () => __spreadArray,\n  __spreadArrays: () => __spreadArrays,\n  __values: () => __values,\n  default: () => tslib_es6_default\n});\nfunction __extends(d, b) {\n  if (typeof b !== \"function\" && b !== null)\n    throw new TypeError(\"Class extends value \" + String(b) + \" is not a constructor or null\");\n  extendStatics(d, b);\n  function __() {\n    this.constructor = d;\n  }\n  __name(__, \"__\");\n  d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());\n}\nfunction __rest(s, e) {\n  var t = {};\n  for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)\n    t[p] = s[p];\n  if (s != null && typeof Object.getOwnPropertySymbols === \"function\")\n    for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {\n      if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))\n        t[p[i]] = s[p[i]];\n    }\n  return t;\n}\nfunction __decorate(decorators, target, key, desc) {\n  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\n  if (typeof Reflect === \"object\" && typeof Reflect.decorate === \"function\") r = Reflect.decorate(decorators, target, key, desc);\n  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\n  return c > 3 && r && Object.defineProperty(target, key, r), r;\n}\nfunction __param(paramIndex, decorator) {\n  return function(target, key) {\n    decorator(target, key, paramIndex);\n  };\n}\nfunction __esDecorate(ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {\n  function accept(f) {\n    if (f !== void 0 && typeof f !== \"function\") throw new TypeError(\"Function expected\");\n    return f;\n  }\n  __name(accept, \"accept\");\n  var kind = contextIn.kind, key = kind === \"getter\" ? \"get\" : kind === \"setter\" ? \"set\" : \"value\";\n  var target = !descriptorIn && ctor ? contextIn[\"static\"] ? ctor : ctor.prototype : null;\n  var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});\n  var _, done = false;\n  for (var i = decorators.length - 1; i >= 0; i--) {\n    var context = {};\n    for (var p in contextIn) context[p] = p === \"access\" ? {} : contextIn[p];\n    for (var p in contextIn.access) context.access[p] = contextIn.access[p];\n    context.addInitializer = function(f) {\n      if (done) throw new TypeError(\"Cannot add initializers after decoration has completed\");\n      extraInitializers.push(accept(f || null));\n    };\n    var result = (0, decorators[i])(kind === \"accessor\" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);\n    if (kind === \"accessor\") {\n      if (result === void 0) continue;\n      if (result === null || typeof result !== \"object\") throw new TypeError(\"Object expected\");\n      if (_ = accept(result.get)) descriptor.get = _;\n      if (_ = accept(result.set)) descriptor.set = _;\n      if (_ = accept(result.init)) initializers.unshift(_);\n    } else if (_ = accept(result)) {\n      if (kind === \"field\") initializers.unshift(_);\n      else descriptor[key] = _;\n    }\n  }\n  if (target) Object.defineProperty(target, contextIn.name, descriptor);\n  done = true;\n}\nfunction __runInitializers(thisArg, initializers, value) {\n  var useValue = arguments.length > 2;\n  for (var i = 0; i < initializers.length; i++) {\n    value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);\n  }\n  return useValue ? value : void 0;\n}\nfunction __propKey(x) {\n  return typeof x === \"symbol\" ? x : \"\".concat(x);\n}\nfunction __setFunctionName(f, name, prefix) {\n  if (typeof name === \"symbol\") name = name.description ? \"[\".concat(name.description, \"]\") : \"\";\n  return Object.defineProperty(f, \"name\", { configurable: true, value: prefix ? \"\".concat(prefix, \" \", name) : name });\n}\nfunction __metadata(metadataKey, metadataValue) {\n  if (typeof Reflect === \"object\" && typeof Reflect.metadata === \"function\") return Reflect.metadata(metadataKey, metadataValue);\n}\nfunction __awaiter(thisArg, _arguments, P, generator) {\n  function adopt(value) {\n    return value instanceof P ? value : new P(function(resolve) {\n      resolve(value);\n    });\n  }\n  __name(adopt, \"adopt\");\n  return new (P || (P = Promise))(function(resolve, reject) {\n    function fulfilled(value) {\n      try {\n        step(generator.next(value));\n      } catch (e) {\n        reject(e);\n      }\n    }\n    __name(fulfilled, \"fulfilled\");\n    function rejected(value) {\n      try {\n        step(generator[\"throw\"](value));\n      } catch (e) {\n        reject(e);\n      }\n    }\n    __name(rejected, \"rejected\");\n    function step(result) {\n      result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected);\n    }\n    __name(step, \"step\");\n    step((generator = generator.apply(thisArg, _arguments || [])).next());\n  });\n}\nfunction __generator(thisArg, body) {\n  var _ = { label: 0, sent: /* @__PURE__ */ __name(function() {\n    if (t[0] & 1) throw t[1];\n    return t[1];\n  }, \"sent\"), trys: [], ops: [] }, f, y, t, g;\n  return g = { next: verb(0), \"throw\": verb(1), \"return\": verb(2) }, typeof Symbol === \"function\" && (g[Symbol.iterator] = function() {\n    return this;\n  }), g;\n  function verb(n) {\n    return function(v) {\n      return step([n, v]);\n    };\n  }\n  __name(verb, \"verb\");\n  function step(op) {\n    if (f) throw new TypeError(\"Generator is already executing.\");\n    while (g && (g = 0, op[0] && (_ = 0)), _) try {\n      if (f = 1, y && (t = op[0] & 2 ? y[\"return\"] : op[0] ? y[\"throw\"] || ((t = y[\"return\"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;\n      if (y = 0, t) op = [op[0] & 2, t.value];\n      switch (op[0]) {\n        case 0:\n        case 1:\n          t = op;\n          break;\n        case 4:\n          _.label++;\n          return { value: op[1], done: false };\n        case 5:\n          _.label++;\n          y = op[1];\n          op = [0];\n          continue;\n        case 7:\n          op = _.ops.pop();\n          _.trys.pop();\n          continue;\n        default:\n          if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) {\n            _ = 0;\n            continue;\n          }\n          if (op[0] === 3 && (!t || op[1] > t[0] && op[1] < t[3])) {\n            _.label = op[1];\n            break;\n          }\n          if (op[0] === 6 && _.label < t[1]) {\n            _.label = t[1];\n            t = op;\n            break;\n          }\n          if (t && _.label < t[2]) {\n            _.label = t[2];\n            _.ops.push(op);\n            break;\n          }\n          if (t[2]) _.ops.pop();\n          _.trys.pop();\n          continue;\n      }\n      op = body.call(thisArg, _);\n    } catch (e) {\n      op = [6, e];\n      y = 0;\n    } finally {\n      f = t = 0;\n    }\n    if (op[0] & 5) throw op[1];\n    return { value: op[0] ? op[1] : void 0, done: true };\n  }\n  __name(step, \"step\");\n}\nfunction __exportStar(m, o) {\n  for (var p in m) if (p !== \"default\" && !Object.prototype.hasOwnProperty.call(o, p)) __createBinding(o, m, p);\n}\nfunction __values(o) {\n  var s = typeof Symbol === \"function\" && Symbol.iterator, m = s && o[s], i = 0;\n  if (m) return m.call(o);\n  if (o && typeof o.length === \"number\") return {\n    next: /* @__PURE__ */ __name(function() {\n      if (o && i >= o.length) o = void 0;\n      return { value: o && o[i++], done: !o };\n    }, \"next\")\n  };\n  throw new TypeError(s ? \"Object is not iterable.\" : \"Symbol.iterator is not defined.\");\n}\nfunction __read(o, n) {\n  var m = typeof Symbol === \"function\" && o[Symbol.iterator];\n  if (!m) return o;\n  var i = m.call(o), r, ar = [], e;\n  try {\n    while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);\n  } catch (error) {\n    e = { error };\n  } finally {\n    try {\n      if (r && !r.done && (m = i[\"return\"])) m.call(i);\n    } finally {\n      if (e) throw e.error;\n    }\n  }\n  return ar;\n}\nfunction __spread() {\n  for (var ar = [], i = 0; i < arguments.length; i++)\n    ar = ar.concat(__read(arguments[i]));\n  return ar;\n}\nfunction __spreadArrays() {\n  for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;\n  for (var r = Array(s), k = 0, i = 0; i < il; i++)\n    for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)\n      r[k] = a[j];\n  return r;\n}\nfunction __spreadArray(to, from, pack) {\n  if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {\n    if (ar || !(i in from)) {\n      if (!ar) ar = Array.prototype.slice.call(from, 0, i);\n      ar[i] = from[i];\n    }\n  }\n  return to.concat(ar || Array.prototype.slice.call(from));\n}\nfunction __await(v) {\n  return this instanceof __await ? (this.v = v, this) : new __await(v);\n}\nfunction __asyncGenerator(thisArg, _arguments, generator) {\n  if (!Symbol.asyncIterator) throw new TypeError(\"Symbol.asyncIterator is not defined.\");\n  var g = generator.apply(thisArg, _arguments || []), i, q = [];\n  return i = {}, verb(\"next\"), verb(\"throw\"), verb(\"return\"), i[Symbol.asyncIterator] = function() {\n    return this;\n  }, i;\n  function verb(n) {\n    if (g[n]) i[n] = function(v) {\n      return new Promise(function(a, b) {\n        q.push([n, v, a, b]) > 1 || resume(n, v);\n      });\n    };\n  }\n  __name(verb, \"verb\");\n  function resume(n, v) {\n    try {\n      step(g[n](v));\n    } catch (e) {\n      settle(q[0][3], e);\n    }\n  }\n  __name(resume, \"resume\");\n  function step(r) {\n    r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r);\n  }\n  __name(step, \"step\");\n  function fulfill(value) {\n    resume(\"next\", value);\n  }\n  __name(fulfill, \"fulfill\");\n  function reject(value) {\n    resume(\"throw\", value);\n  }\n  __name(reject, \"reject\");\n  function settle(f, v) {\n    if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]);\n  }\n  __name(settle, \"settle\");\n}\nfunction __asyncDelegator(o) {\n  var i, p;\n  return i = {}, verb(\"next\"), verb(\"throw\", function(e) {\n    throw e;\n  }), verb(\"return\"), i[Symbol.iterator] = function() {\n    return this;\n  }, i;\n  function verb(n, f) {\n    i[n] = o[n] ? function(v) {\n      return (p = !p) ? { value: __await(o[n](v)), done: false } : f ? f(v) : v;\n    } : f;\n  }\n  __name(verb, \"verb\");\n}\nfunction __asyncValues(o) {\n  if (!Symbol.asyncIterator) throw new TypeError(\"Symbol.asyncIterator is not defined.\");\n  var m = o[Symbol.asyncIterator], i;\n  return m ? m.call(o) : (o = typeof __values === \"function\" ? __values(o) : o[Symbol.iterator](), i = {}, verb(\"next\"), verb(\"throw\"), verb(\"return\"), i[Symbol.asyncIterator] = function() {\n    return this;\n  }, i);\n  function verb(n) {\n    i[n] = o[n] && function(v) {\n      return new Promise(function(resolve, reject) {\n        v = o[n](v), settle(resolve, reject, v.done, v.value);\n      });\n    };\n  }\n  __name(verb, \"verb\");\n  function settle(resolve, reject, d, v) {\n    Promise.resolve(v).then(function(v2) {\n      resolve({ value: v2, done: d });\n    }, reject);\n  }\n  __name(settle, \"settle\");\n}\nfunction __makeTemplateObject(cooked, raw) {\n  if (Object.defineProperty) {\n    Object.defineProperty(cooked, \"raw\", { value: raw });\n  } else {\n    cooked.raw = raw;\n  }\n  return cooked;\n}\nfunction __importStar(mod2) {\n  if (mod2 && mod2.__esModule) return mod2;\n  var result = {};\n  if (mod2 != null) {\n    for (var k in mod2) if (k !== \"default\" && Object.prototype.hasOwnProperty.call(mod2, k)) __createBinding(result, mod2, k);\n  }\n  __setModuleDefault(result, mod2);\n  return result;\n}\nfunction __importDefault(mod2) {\n  return mod2 && mod2.__esModule ? mod2 : { default: mod2 };\n}\nfunction __classPrivateFieldGet(receiver, state, kind, f) {\n  if (kind === \"a\" && !f) throw new TypeError(\"Private accessor was defined without a getter\");\n  if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n  return kind === \"m\" ? f : kind === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n}\nfunction __classPrivateFieldSet(receiver, state, value, kind, f) {\n  if (kind === \"m\") throw new TypeError(\"Private method is not writable\");\n  if (kind === \"a\" && !f) throw new TypeError(\"Private accessor was defined without a setter\");\n  if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n  return kind === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;\n}\nfunction __classPrivateFieldIn(state, receiver) {\n  if (receiver === null || typeof receiver !== \"object\" && typeof receiver !== \"function\") throw new TypeError(\"Cannot use 'in' operator on non-object\");\n  return typeof state === \"function\" ? receiver === state : state.has(receiver);\n}\nfunction __addDisposableResource(env, value, async) {\n  if (value !== null && value !== void 0) {\n    if (typeof value !== \"object\" && typeof value !== \"function\") throw new TypeError(\"Object expected.\");\n    var dispose;\n    if (async) {\n      if (!Symbol.asyncDispose) throw new TypeError(\"Symbol.asyncDispose is not defined.\");\n      dispose = value[Symbol.asyncDispose];\n    }\n    if (dispose === void 0) {\n      if (!Symbol.dispose) throw new TypeError(\"Symbol.dispose is not defined.\");\n      dispose = value[Symbol.dispose];\n    }\n    if (typeof dispose !== \"function\") throw new TypeError(\"Object not disposable.\");\n    env.stack.push({ value, dispose, async });\n  } else if (async) {\n    env.stack.push({ async: true });\n  }\n  return value;\n}\nfunction __disposeResources(env) {\n  function fail(e) {\n    env.error = env.hasError ? new _SuppressedError(e, env.error, \"An error was suppressed during disposal.\") : e;\n    env.hasError = true;\n  }\n  __name(fail, \"fail\");\n  function next() {\n    while (env.stack.length) {\n      var rec = env.stack.pop();\n      try {\n        var result = rec.dispose && rec.dispose.call(rec.value);\n        if (rec.async) return Promise.resolve(result).then(next, function(e) {\n          fail(e);\n          return next();\n        });\n      } catch (e) {\n        fail(e);\n      }\n    }\n    if (env.hasError) throw env.error;\n  }\n  __name(next, \"next\");\n  return next();\n}\nvar extendStatics, __assign, __createBinding, __setModuleDefault, _SuppressedError, tslib_es6_default;\nvar init_tslib_es6 = __esm({\n  \"node_modules/intl-messageformat/node_modules/tslib/tslib.es6.mjs\"() {\n    init_process_global();\n    extendStatics = /* @__PURE__ */ __name(function(d, b) {\n      extendStatics = Object.setPrototypeOf || { __proto__: [] } instanceof Array && function(d2, b2) {\n        d2.__proto__ = b2;\n      } || function(d2, b2) {\n        for (var p in b2) if (Object.prototype.hasOwnProperty.call(b2, p)) d2[p] = b2[p];\n      };\n      return extendStatics(d, b);\n    }, \"extendStatics\");\n    __name(__extends, \"__extends\");\n    __assign = /* @__PURE__ */ __name(function() {\n      __assign = Object.assign || /* @__PURE__ */ __name(function __assign4(t) {\n        for (var s, i = 1, n = arguments.length; i < n; i++) {\n          s = arguments[i];\n          for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];\n        }\n        return t;\n      }, \"__assign\");\n      return __assign.apply(this, arguments);\n    }, \"__assign\");\n    __name(__rest, \"__rest\");\n    __name(__decorate, \"__decorate\");\n    __name(__param, \"__param\");\n    __name(__esDecorate, \"__esDecorate\");\n    __name(__runInitializers, \"__runInitializers\");\n    __name(__propKey, \"__propKey\");\n    __name(__setFunctionName, \"__setFunctionName\");\n    __name(__metadata, \"__metadata\");\n    __name(__awaiter, \"__awaiter\");\n    __name(__generator, \"__generator\");\n    __createBinding = Object.create ? (function(o, m, k, k2) {\n      if (k2 === void 0) k2 = k;\n      var desc = Object.getOwnPropertyDescriptor(m, k);\n      if (!desc || (\"get\" in desc ? !m.__esModule : desc.writable || desc.configurable)) {\n        desc = { enumerable: true, get: /* @__PURE__ */ __name(function() {\n          return m[k];\n        }, \"get\") };\n      }\n      Object.defineProperty(o, k2, desc);\n    }) : (function(o, m, k, k2) {\n      if (k2 === void 0) k2 = k;\n      o[k2] = m[k];\n    });\n    __name(__exportStar, \"__exportStar\");\n    __name(__values, \"__values\");\n    __name(__read, \"__read\");\n    __name(__spread, \"__spread\");\n    __name(__spreadArrays, \"__spreadArrays\");\n    __name(__spreadArray, \"__spreadArray\");\n    __name(__await, \"__await\");\n    __name(__asyncGenerator, \"__asyncGenerator\");\n    __name(__asyncDelegator, \"__asyncDelegator\");\n    __name(__asyncValues, \"__asyncValues\");\n    __name(__makeTemplateObject, \"__makeTemplateObject\");\n    __setModuleDefault = Object.create ? (function(o, v) {\n      Object.defineProperty(o, \"default\", { enumerable: true, value: v });\n    }) : function(o, v) {\n      o[\"default\"] = v;\n    };\n    __name(__importStar, \"__importStar\");\n    __name(__importDefault, \"__importDefault\");\n    __name(__classPrivateFieldGet, \"__classPrivateFieldGet\");\n    __name(__classPrivateFieldSet, \"__classPrivateFieldSet\");\n    __name(__classPrivateFieldIn, \"__classPrivateFieldIn\");\n    __name(__addDisposableResource, \"__addDisposableResource\");\n    _SuppressedError = typeof SuppressedError === \"function\" ? SuppressedError : function(error, suppressed, message) {\n      var e = new Error(message);\n      return e.name = \"SuppressedError\", e.error = error, e.suppressed = suppressed, e;\n    };\n    __name(__disposeResources, \"__disposeResources\");\n    tslib_es6_default = {\n      __extends,\n      __assign,\n      __rest,\n      __decorate,\n      __param,\n      __metadata,\n      __awaiter,\n      __generator,\n      __createBinding,\n      __exportStar,\n      __values,\n      __read,\n      __spread,\n      __spreadArrays,\n      __spreadArray,\n      __await,\n      __asyncGenerator,\n      __asyncDelegator,\n      __asyncValues,\n      __makeTemplateObject,\n      __importStar,\n      __importDefault,\n      __classPrivateFieldGet,\n      __classPrivateFieldSet,\n      __classPrivateFieldIn,\n      __addDisposableResource,\n      __disposeResources\n    };\n  }\n});\n\n// node_modules/@formatjs/icu-messageformat-parser/node_modules/tslib/tslib.es6.mjs\nvar tslib_es6_exports2 = {};\n__export(tslib_es6_exports2, {\n  __addDisposableResource: () => __addDisposableResource2,\n  __assign: () => __assign2,\n  __asyncDelegator: () => __asyncDelegator2,\n  __asyncGenerator: () => __asyncGenerator2,\n  __asyncValues: () => __asyncValues2,\n  __await: () => __await2,\n  __awaiter: () => __awaiter2,\n  __classPrivateFieldGet: () => __classPrivateFieldGet2,\n  __classPrivateFieldIn: () => __classPrivateFieldIn2,\n  __classPrivateFieldSet: () => __classPrivateFieldSet2,\n  __createBinding: () => __createBinding2,\n  __decorate: () => __decorate2,\n  __disposeResources: () => __disposeResources2,\n  __esDecorate: () => __esDecorate2,\n  __exportStar: () => __exportStar2,\n  __extends: () => __extends2,\n  __generator: () => __generator2,\n  __importDefault: () => __importDefault2,\n  __importStar: () => __importStar2,\n  __makeTemplateObject: () => __makeTemplateObject2,\n  __metadata: () => __metadata2,\n  __param: () => __param2,\n  __propKey: () => __propKey2,\n  __read: () => __read2,\n  __rest: () => __rest2,\n  __runInitializers: () => __runInitializers2,\n  __setFunctionName: () => __setFunctionName2,\n  __spread: () => __spread2,\n  __spreadArray: () => __spreadArray2,\n  __spreadArrays: () => __spreadArrays2,\n  __values: () => __values2,\n  default: () => tslib_es6_default2\n});\nfunction __extends2(d, b) {\n  if (typeof b !== \"function\" && b !== null)\n    throw new TypeError(\"Class extends value \" + String(b) + \" is not a constructor or null\");\n  extendStatics2(d, b);\n  function __() {\n    this.constructor = d;\n  }\n  __name(__, \"__\");\n  d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());\n}\nfunction __rest2(s, e) {\n  var t = {};\n  for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)\n    t[p] = s[p];\n  if (s != null && typeof Object.getOwnPropertySymbols === \"function\")\n    for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {\n      if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))\n        t[p[i]] = s[p[i]];\n    }\n  return t;\n}\nfunction __decorate2(decorators, target, key, desc) {\n  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\n  if (typeof Reflect === \"object\" && typeof Reflect.decorate === \"function\") r = Reflect.decorate(decorators, target, key, desc);\n  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\n  return c > 3 && r && Object.defineProperty(target, key, r), r;\n}\nfunction __param2(paramIndex, decorator) {\n  return function(target, key) {\n    decorator(target, key, paramIndex);\n  };\n}\nfunction __esDecorate2(ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {\n  function accept(f) {\n    if (f !== void 0 && typeof f !== \"function\") throw new TypeError(\"Function expected\");\n    return f;\n  }\n  __name(accept, \"accept\");\n  var kind = contextIn.kind, key = kind === \"getter\" ? \"get\" : kind === \"setter\" ? \"set\" : \"value\";\n  var target = !descriptorIn && ctor ? contextIn[\"static\"] ? ctor : ctor.prototype : null;\n  var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});\n  var _, done = false;\n  for (var i = decorators.length - 1; i >= 0; i--) {\n    var context = {};\n    for (var p in contextIn) context[p] = p === \"access\" ? {} : contextIn[p];\n    for (var p in contextIn.access) context.access[p] = contextIn.access[p];\n    context.addInitializer = function(f) {\n      if (done) throw new TypeError(\"Cannot add initializers after decoration has completed\");\n      extraInitializers.push(accept(f || null));\n    };\n    var result = (0, decorators[i])(kind === \"accessor\" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);\n    if (kind === \"accessor\") {\n      if (result === void 0) continue;\n      if (result === null || typeof result !== \"object\") throw new TypeError(\"Object expected\");\n      if (_ = accept(result.get)) descriptor.get = _;\n      if (_ = accept(result.set)) descriptor.set = _;\n      if (_ = accept(result.init)) initializers.unshift(_);\n    } else if (_ = accept(result)) {\n      if (kind === \"field\") initializers.unshift(_);\n      else descriptor[key] = _;\n    }\n  }\n  if (target) Object.defineProperty(target, contextIn.name, descriptor);\n  done = true;\n}\nfunction __runInitializers2(thisArg, initializers, value) {\n  var useValue = arguments.length > 2;\n  for (var i = 0; i < initializers.length; i++) {\n    value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);\n  }\n  return useValue ? value : void 0;\n}\nfunction __propKey2(x) {\n  return typeof x === \"symbol\" ? x : \"\".concat(x);\n}\nfunction __setFunctionName2(f, name, prefix) {\n  if (typeof name === \"symbol\") name = name.description ? \"[\".concat(name.description, \"]\") : \"\";\n  return Object.defineProperty(f, \"name\", { configurable: true, value: prefix ? \"\".concat(prefix, \" \", name) : name });\n}\nfunction __metadata2(metadataKey, metadataValue) {\n  if (typeof Reflect === \"object\" && typeof Reflect.metadata === \"function\") return Reflect.metadata(metadataKey, metadataValue);\n}\nfunction __awaiter2(thisArg, _arguments, P, generator) {\n  function adopt(value) {\n    return value instanceof P ? value : new P(function(resolve) {\n      resolve(value);\n    });\n  }\n  __name(adopt, \"adopt\");\n  return new (P || (P = Promise))(function(resolve, reject) {\n    function fulfilled(value) {\n      try {\n        step(generator.next(value));\n      } catch (e) {\n        reject(e);\n      }\n    }\n    __name(fulfilled, \"fulfilled\");\n    function rejected(value) {\n      try {\n        step(generator[\"throw\"](value));\n      } catch (e) {\n        reject(e);\n      }\n    }\n    __name(rejected, \"rejected\");\n    function step(result) {\n      result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected);\n    }\n    __name(step, \"step\");\n    step((generator = generator.apply(thisArg, _arguments || [])).next());\n  });\n}\nfunction __generator2(thisArg, body) {\n  var _ = { label: 0, sent: /* @__PURE__ */ __name(function() {\n    if (t[0] & 1) throw t[1];\n    return t[1];\n  }, \"sent\"), trys: [], ops: [] }, f, y, t, g;\n  return g = { next: verb(0), \"throw\": verb(1), \"return\": verb(2) }, typeof Symbol === \"function\" && (g[Symbol.iterator] = function() {\n    return this;\n  }), g;\n  function verb(n) {\n    return function(v) {\n      return step([n, v]);\n    };\n  }\n  __name(verb, \"verb\");\n  function step(op) {\n    if (f) throw new TypeError(\"Generator is already executing.\");\n    while (g && (g = 0, op[0] && (_ = 0)), _) try {\n      if (f = 1, y && (t = op[0] & 2 ? y[\"return\"] : op[0] ? y[\"throw\"] || ((t = y[\"return\"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;\n      if (y = 0, t) op = [op[0] & 2, t.value];\n      switch (op[0]) {\n        case 0:\n        case 1:\n          t = op;\n          break;\n        case 4:\n          _.label++;\n          return { value: op[1], done: false };\n        case 5:\n          _.label++;\n          y = op[1];\n          op = [0];\n          continue;\n        case 7:\n          op = _.ops.pop();\n          _.trys.pop();\n          continue;\n        default:\n          if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) {\n            _ = 0;\n            continue;\n          }\n          if (op[0] === 3 && (!t || op[1] > t[0] && op[1] < t[3])) {\n            _.label = op[1];\n            break;\n          }\n          if (op[0] === 6 && _.label < t[1]) {\n            _.label = t[1];\n            t = op;\n            break;\n          }\n          if (t && _.label < t[2]) {\n            _.label = t[2];\n            _.ops.push(op);\n            break;\n          }\n          if (t[2]) _.ops.pop();\n          _.trys.pop();\n          continue;\n      }\n      op = body.call(thisArg, _);\n    } catch (e) {\n      op = [6, e];\n      y = 0;\n    } finally {\n      f = t = 0;\n    }\n    if (op[0] & 5) throw op[1];\n    return { value: op[0] ? op[1] : void 0, done: true };\n  }\n  __name(step, \"step\");\n}\nfunction __exportStar2(m, o) {\n  for (var p in m) if (p !== \"default\" && !Object.prototype.hasOwnProperty.call(o, p)) __createBinding2(o, m, p);\n}\nfunction __values2(o) {\n  var s = typeof Symbol === \"function\" && Symbol.iterator, m = s && o[s], i = 0;\n  if (m) return m.call(o);\n  if (o && typeof o.length === \"number\") return {\n    next: /* @__PURE__ */ __name(function() {\n      if (o && i >= o.length) o = void 0;\n      return { value: o && o[i++], done: !o };\n    }, \"next\")\n  };\n  throw new TypeError(s ? \"Object is not iterable.\" : \"Symbol.iterator is not defined.\");\n}\nfunction __read2(o, n) {\n  var m = typeof Symbol === \"function\" && o[Symbol.iterator];\n  if (!m) return o;\n  var i = m.call(o), r, ar = [], e;\n  try {\n    while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);\n  } catch (error) {\n    e = { error };\n  } finally {\n    try {\n      if (r && !r.done && (m = i[\"return\"])) m.call(i);\n    } finally {\n      if (e) throw e.error;\n    }\n  }\n  return ar;\n}\nfunction __spread2() {\n  for (var ar = [], i = 0; i < arguments.length; i++)\n    ar = ar.concat(__read2(arguments[i]));\n  return ar;\n}\nfunction __spreadArrays2() {\n  for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;\n  for (var r = Array(s), k = 0, i = 0; i < il; i++)\n    for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)\n      r[k] = a[j];\n  return r;\n}\nfunction __spreadArray2(to, from, pack) {\n  if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {\n    if (ar || !(i in from)) {\n      if (!ar) ar = Array.prototype.slice.call(from, 0, i);\n      ar[i] = from[i];\n    }\n  }\n  return to.concat(ar || Array.prototype.slice.call(from));\n}\nfunction __await2(v) {\n  return this instanceof __await2 ? (this.v = v, this) : new __await2(v);\n}\nfunction __asyncGenerator2(thisArg, _arguments, generator) {\n  if (!Symbol.asyncIterator) throw new TypeError(\"Symbol.asyncIterator is not defined.\");\n  var g = generator.apply(thisArg, _arguments || []), i, q = [];\n  return i = {}, verb(\"next\"), verb(\"throw\"), verb(\"return\"), i[Symbol.asyncIterator] = function() {\n    return this;\n  }, i;\n  function verb(n) {\n    if (g[n]) i[n] = function(v) {\n      return new Promise(function(a, b) {\n        q.push([n, v, a, b]) > 1 || resume(n, v);\n      });\n    };\n  }\n  __name(verb, \"verb\");\n  function resume(n, v) {\n    try {\n      step(g[n](v));\n    } catch (e) {\n      settle(q[0][3], e);\n    }\n  }\n  __name(resume, \"resume\");\n  function step(r) {\n    r.value instanceof __await2 ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r);\n  }\n  __name(step, \"step\");\n  function fulfill(value) {\n    resume(\"next\", value);\n  }\n  __name(fulfill, \"fulfill\");\n  function reject(value) {\n    resume(\"throw\", value);\n  }\n  __name(reject, \"reject\");\n  function settle(f, v) {\n    if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]);\n  }\n  __name(settle, \"settle\");\n}\nfunction __asyncDelegator2(o) {\n  var i, p;\n  return i = {}, verb(\"next\"), verb(\"throw\", function(e) {\n    throw e;\n  }), verb(\"return\"), i[Symbol.iterator] = function() {\n    return this;\n  }, i;\n  function verb(n, f) {\n    i[n] = o[n] ? function(v) {\n      return (p = !p) ? { value: __await2(o[n](v)), done: false } : f ? f(v) : v;\n    } : f;\n  }\n  __name(verb, \"verb\");\n}\nfunction __asyncValues2(o) {\n  if (!Symbol.asyncIterator) throw new TypeError(\"Symbol.asyncIterator is not defined.\");\n  var m = o[Symbol.asyncIterator], i;\n  return m ? m.call(o) : (o = typeof __values2 === \"function\" ? __values2(o) : o[Symbol.iterator](), i = {}, verb(\"next\"), verb(\"throw\"), verb(\"return\"), i[Symbol.asyncIterator] = function() {\n    return this;\n  }, i);\n  function verb(n) {\n    i[n] = o[n] && function(v) {\n      return new Promise(function(resolve, reject) {\n        v = o[n](v), settle(resolve, reject, v.done, v.value);\n      });\n    };\n  }\n  __name(verb, \"verb\");\n  function settle(resolve, reject, d, v) {\n    Promise.resolve(v).then(function(v2) {\n      resolve({ value: v2, done: d });\n    }, reject);\n  }\n  __name(settle, \"settle\");\n}\nfunction __makeTemplateObject2(cooked, raw) {\n  if (Object.defineProperty) {\n    Object.defineProperty(cooked, \"raw\", { value: raw });\n  } else {\n    cooked.raw = raw;\n  }\n  return cooked;\n}\nfunction __importStar2(mod2) {\n  if (mod2 && mod2.__esModule) return mod2;\n  var result = {};\n  if (mod2 != null) {\n    for (var k in mod2) if (k !== \"default\" && Object.prototype.hasOwnProperty.call(mod2, k)) __createBinding2(result, mod2, k);\n  }\n  __setModuleDefault2(result, mod2);\n  return result;\n}\nfunction __importDefault2(mod2) {\n  return mod2 && mod2.__esModule ? mod2 : { default: mod2 };\n}\nfunction __classPrivateFieldGet2(receiver, state, kind, f) {\n  if (kind === \"a\" && !f) throw new TypeError(\"Private accessor was defined without a getter\");\n  if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n  return kind === \"m\" ? f : kind === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n}\nfunction __classPrivateFieldSet2(receiver, state, value, kind, f) {\n  if (kind === \"m\") throw new TypeError(\"Private method is not writable\");\n  if (kind === \"a\" && !f) throw new TypeError(\"Private accessor was defined without a setter\");\n  if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n  return kind === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;\n}\nfunction __classPrivateFieldIn2(state, receiver) {\n  if (receiver === null || typeof receiver !== \"object\" && typeof receiver !== \"function\") throw new TypeError(\"Cannot use 'in' operator on non-object\");\n  return typeof state === \"function\" ? receiver === state : state.has(receiver);\n}\nfunction __addDisposableResource2(env, value, async) {\n  if (value !== null && value !== void 0) {\n    if (typeof value !== \"object\" && typeof value !== \"function\") throw new TypeError(\"Object expected.\");\n    var dispose;\n    if (async) {\n      if (!Symbol.asyncDispose) throw new TypeError(\"Symbol.asyncDispose is not defined.\");\n      dispose = value[Symbol.asyncDispose];\n    }\n    if (dispose === void 0) {\n      if (!Symbol.dispose) throw new TypeError(\"Symbol.dispose is not defined.\");\n      dispose = value[Symbol.dispose];\n    }\n    if (typeof dispose !== \"function\") throw new TypeError(\"Object not disposable.\");\n    env.stack.push({ value, dispose, async });\n  } else if (async) {\n    env.stack.push({ async: true });\n  }\n  return value;\n}\nfunction __disposeResources2(env) {\n  function fail(e) {\n    env.error = env.hasError ? new _SuppressedError2(e, env.error, \"An error was suppressed during disposal.\") : e;\n    env.hasError = true;\n  }\n  __name(fail, \"fail\");\n  function next() {\n    while (env.stack.length) {\n      var rec = env.stack.pop();\n      try {\n        var result = rec.dispose && rec.dispose.call(rec.value);\n        if (rec.async) return Promise.resolve(result).then(next, function(e) {\n          fail(e);\n          return next();\n        });\n      } catch (e) {\n        fail(e);\n      }\n    }\n    if (env.hasError) throw env.error;\n  }\n  __name(next, \"next\");\n  return next();\n}\nvar extendStatics2, __assign2, __createBinding2, __setModuleDefault2, _SuppressedError2, tslib_es6_default2;\nvar init_tslib_es62 = __esm({\n  \"node_modules/@formatjs/icu-messageformat-parser/node_modules/tslib/tslib.es6.mjs\"() {\n    init_process_global();\n    extendStatics2 = /* @__PURE__ */ __name(function(d, b) {\n      extendStatics2 = Object.setPrototypeOf || { __proto__: [] } instanceof Array && function(d2, b2) {\n        d2.__proto__ = b2;\n      } || function(d2, b2) {\n        for (var p in b2) if (Object.prototype.hasOwnProperty.call(b2, p)) d2[p] = b2[p];\n      };\n      return extendStatics2(d, b);\n    }, \"extendStatics\");\n    __name(__extends2, \"__extends\");\n    __assign2 = /* @__PURE__ */ __name(function() {\n      __assign2 = Object.assign || /* @__PURE__ */ __name(function __assign4(t) {\n        for (var s, i = 1, n = arguments.length; i < n; i++) {\n          s = arguments[i];\n          for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];\n        }\n        return t;\n      }, \"__assign\");\n      return __assign2.apply(this, arguments);\n    }, \"__assign\");\n    __name(__rest2, \"__rest\");\n    __name(__decorate2, \"__decorate\");\n    __name(__param2, \"__param\");\n    __name(__esDecorate2, \"__esDecorate\");\n    __name(__runInitializers2, \"__runInitializers\");\n    __name(__propKey2, \"__propKey\");\n    __name(__setFunctionName2, \"__setFunctionName\");\n    __name(__metadata2, \"__metadata\");\n    __name(__awaiter2, \"__awaiter\");\n    __name(__generator2, \"__generator\");\n    __createBinding2 = Object.create ? (function(o, m, k, k2) {\n      if (k2 === void 0) k2 = k;\n      var desc = Object.getOwnPropertyDescriptor(m, k);\n      if (!desc || (\"get\" in desc ? !m.__esModule : desc.writable || desc.configurable)) {\n        desc = { enumerable: true, get: /* @__PURE__ */ __name(function() {\n          return m[k];\n        }, \"get\") };\n      }\n      Object.defineProperty(o, k2, desc);\n    }) : (function(o, m, k, k2) {\n      if (k2 === void 0) k2 = k;\n      o[k2] = m[k];\n    });\n    __name(__exportStar2, \"__exportStar\");\n    __name(__values2, \"__values\");\n    __name(__read2, \"__read\");\n    __name(__spread2, \"__spread\");\n    __name(__spreadArrays2, \"__spreadArrays\");\n    __name(__spreadArray2, \"__spreadArray\");\n    __name(__await2, \"__await\");\n    __name(__asyncGenerator2, \"__asyncGenerator\");\n    __name(__asyncDelegator2, \"__asyncDelegator\");\n    __name(__asyncValues2, \"__asyncValues\");\n    __name(__makeTemplateObject2, \"__makeTemplateObject\");\n    __setModuleDefault2 = Object.create ? (function(o, v) {\n      Object.defineProperty(o, \"default\", { enumerable: true, value: v });\n    }) : function(o, v) {\n      o[\"default\"] = v;\n    };\n    __name(__importStar2, \"__importStar\");\n    __name(__importDefault2, \"__importDefault\");\n    __name(__classPrivateFieldGet2, \"__classPrivateFieldGet\");\n    __name(__classPrivateFieldSet2, \"__classPrivateFieldSet\");\n    __name(__classPrivateFieldIn2, \"__classPrivateFieldIn\");\n    __name(__addDisposableResource2, \"__addDisposableResource\");\n    _SuppressedError2 = typeof SuppressedError === \"function\" ? SuppressedError : function(error, suppressed, message) {\n      var e = new Error(message);\n      return e.name = \"SuppressedError\", e.error = error, e.suppressed = suppressed, e;\n    };\n    __name(__disposeResources2, \"__disposeResources\");\n    tslib_es6_default2 = {\n      __extends: __extends2,\n      __assign: __assign2,\n      __rest: __rest2,\n      __decorate: __decorate2,\n      __param: __param2,\n      __metadata: __metadata2,\n      __awaiter: __awaiter2,\n      __generator: __generator2,\n      __createBinding: __createBinding2,\n      __exportStar: __exportStar2,\n      __values: __values2,\n      __read: __read2,\n      __spread: __spread2,\n      __spreadArrays: __spreadArrays2,\n      __spreadArray: __spreadArray2,\n      __await: __await2,\n      __asyncGenerator: __asyncGenerator2,\n      __asyncDelegator: __asyncDelegator2,\n      __asyncValues: __asyncValues2,\n      __makeTemplateObject: __makeTemplateObject2,\n      __importStar: __importStar2,\n      __importDefault: __importDefault2,\n      __classPrivateFieldGet: __classPrivateFieldGet2,\n      __classPrivateFieldSet: __classPrivateFieldSet2,\n      __classPrivateFieldIn: __classPrivateFieldIn2,\n      __addDisposableResource: __addDisposableResource2,\n      __disposeResources: __disposeResources2\n    };\n  }\n});\n\n// node_modules/@formatjs/icu-messageformat-parser/error.js\nvar require_error = __commonJS({\n  \"node_modules/@formatjs/icu-messageformat-parser/error.js\"(exports2) {\n    \"use strict\";\n    init_process_global();\n    Object.defineProperty(exports2, \"__esModule\", { value: true });\n    exports2.ErrorKind = void 0;\n    var ErrorKind;\n    (function(ErrorKind2) {\n      ErrorKind2[ErrorKind2[\"EXPECT_ARGUMENT_CLOSING_BRACE\"] = 1] = \"EXPECT_ARGUMENT_CLOSING_BRACE\";\n      ErrorKind2[ErrorKind2[\"EMPTY_ARGUMENT\"] = 2] = \"EMPTY_ARGUMENT\";\n      ErrorKind2[ErrorKind2[\"MALFORMED_ARGUMENT\"] = 3] = \"MALFORMED_ARGUMENT\";\n      ErrorKind2[ErrorKind2[\"EXPECT_ARGUMENT_TYPE\"] = 4] = \"EXPECT_ARGUMENT_TYPE\";\n      ErrorKind2[ErrorKind2[\"INVALID_ARGUMENT_TYPE\"] = 5] = \"INVALID_ARGUMENT_TYPE\";\n      ErrorKind2[ErrorKind2[\"EXPECT_ARGUMENT_STYLE\"] = 6] = \"EXPECT_ARGUMENT_STYLE\";\n      ErrorKind2[ErrorKind2[\"INVALID_NUMBER_SKELETON\"] = 7] = \"INVALID_NUMBER_SKELETON\";\n      ErrorKind2[ErrorKind2[\"INVALID_DATE_TIME_SKELETON\"] = 8] = \"INVALID_DATE_TIME_SKELETON\";\n      ErrorKind2[ErrorKind2[\"EXPECT_NUMBER_SKELETON\"] = 9] = \"EXPECT_NUMBER_SKELETON\";\n      ErrorKind2[ErrorKind2[\"EXPECT_DATE_TIME_SKELETON\"] = 10] = \"EXPECT_DATE_TIME_SKELETON\";\n      ErrorKind2[ErrorKind2[\"UNCLOSED_QUOTE_IN_ARGUMENT_STYLE\"] = 11] = \"UNCLOSED_QUOTE_IN_ARGUMENT_STYLE\";\n      ErrorKind2[ErrorKind2[\"EXPECT_SELECT_ARGUMENT_OPTIONS\"] = 12] = \"EXPECT_SELECT_ARGUMENT_OPTIONS\";\n      ErrorKind2[ErrorKind2[\"EXPECT_PLURAL_ARGUMENT_OFFSET_VALUE\"] = 13] = \"EXPECT_PLURAL_ARGUMENT_OFFSET_VALUE\";\n      ErrorKind2[ErrorKind2[\"INVALID_PLURAL_ARGUMENT_OFFSET_VALUE\"] = 14] = \"INVALID_PLURAL_ARGUMENT_OFFSET_VALUE\";\n      ErrorKind2[ErrorKind2[\"EXPECT_SELECT_ARGUMENT_SELECTOR\"] = 15] = \"EXPECT_SELECT_ARGUMENT_SELECTOR\";\n      ErrorKind2[ErrorKind2[\"EXPECT_PLURAL_ARGUMENT_SELECTOR\"] = 16] = \"EXPECT_PLURAL_ARGUMENT_SELECTOR\";\n      ErrorKind2[ErrorKind2[\"EXPECT_SELECT_ARGUMENT_SELECTOR_FRAGMENT\"] = 17] = \"EXPECT_SELECT_ARGUMENT_SELECTOR_FRAGMENT\";\n      ErrorKind2[ErrorKind2[\"EXPECT_PLURAL_ARGUMENT_SELECTOR_FRAGMENT\"] = 18] = \"EXPECT_PLURAL_ARGUMENT_SELECTOR_FRAGMENT\";\n      ErrorKind2[ErrorKind2[\"INVALID_PLURAL_ARGUMENT_SELECTOR\"] = 19] = \"INVALID_PLURAL_ARGUMENT_SELECTOR\";\n      ErrorKind2[ErrorKind2[\"DUPLICATE_PLURAL_ARGUMENT_SELECTOR\"] = 20] = \"DUPLICATE_PLURAL_ARGUMENT_SELECTOR\";\n      ErrorKind2[ErrorKind2[\"DUPLICATE_SELECT_ARGUMENT_SELECTOR\"] = 21] = \"DUPLICATE_SELECT_ARGUMENT_SELECTOR\";\n      ErrorKind2[ErrorKind2[\"MISSING_OTHER_CLAUSE\"] = 22] = \"MISSING_OTHER_CLAUSE\";\n      ErrorKind2[ErrorKind2[\"INVALID_TAG\"] = 23] = \"INVALID_TAG\";\n      ErrorKind2[ErrorKind2[\"INVALID_TAG_NAME\"] = 25] = \"INVALID_TAG_NAME\";\n      ErrorKind2[ErrorKind2[\"UNMATCHED_CLOSING_TAG\"] = 26] = \"UNMATCHED_CLOSING_TAG\";\n      ErrorKind2[ErrorKind2[\"UNCLOSED_TAG\"] = 27] = \"UNCLOSED_TAG\";\n    })(ErrorKind = exports2.ErrorKind || (exports2.ErrorKind = {}));\n  }\n});\n\n// node_modules/@formatjs/icu-messageformat-parser/types.js\nvar require_types = __commonJS({\n  \"node_modules/@formatjs/icu-messageformat-parser/types.js\"(exports2) {\n    \"use strict\";\n    init_process_global();\n    Object.defineProperty(exports2, \"__esModule\", { value: true });\n    exports2.createNumberElement = exports2.createLiteralElement = exports2.isDateTimeSkeleton = exports2.isNumberSkeleton = exports2.isTagElement = exports2.isPoundElement = exports2.isPluralElement = exports2.isSelectElement = exports2.isTimeElement = exports2.isDateElement = exports2.isNumberElement = exports2.isArgumentElement = exports2.isLiteralElement = exports2.SKELETON_TYPE = exports2.TYPE = void 0;\n    var TYPE2;\n    (function(TYPE3) {\n      TYPE3[TYPE3[\"literal\"] = 0] = \"literal\";\n      TYPE3[TYPE3[\"argument\"] = 1] = \"argument\";\n      TYPE3[TYPE3[\"number\"] = 2] = \"number\";\n      TYPE3[TYPE3[\"date\"] = 3] = \"date\";\n      TYPE3[TYPE3[\"time\"] = 4] = \"time\";\n      TYPE3[TYPE3[\"select\"] = 5] = \"select\";\n      TYPE3[TYPE3[\"plural\"] = 6] = \"plural\";\n      TYPE3[TYPE3[\"pound\"] = 7] = \"pound\";\n      TYPE3[TYPE3[\"tag\"] = 8] = \"tag\";\n    })(TYPE2 = exports2.TYPE || (exports2.TYPE = {}));\n    var SKELETON_TYPE;\n    (function(SKELETON_TYPE2) {\n      SKELETON_TYPE2[SKELETON_TYPE2[\"number\"] = 0] = \"number\";\n      SKELETON_TYPE2[SKELETON_TYPE2[\"dateTime\"] = 1] = \"dateTime\";\n    })(SKELETON_TYPE = exports2.SKELETON_TYPE || (exports2.SKELETON_TYPE = {}));\n    function isLiteralElement(el) {\n      return el.type === TYPE2.literal;\n    }\n    __name(isLiteralElement, \"isLiteralElement\");\n    exports2.isLiteralElement = isLiteralElement;\n    function isArgumentElement(el) {\n      return el.type === TYPE2.argument;\n    }\n    __name(isArgumentElement, \"isArgumentElement\");\n    exports2.isArgumentElement = isArgumentElement;\n    function isNumberElement(el) {\n      return el.type === TYPE2.number;\n    }\n    __name(isNumberElement, \"isNumberElement\");\n    exports2.isNumberElement = isNumberElement;\n    function isDateElement(el) {\n      return el.type === TYPE2.date;\n    }\n    __name(isDateElement, \"isDateElement\");\n    exports2.isDateElement = isDateElement;\n    function isTimeElement(el) {\n      return el.type === TYPE2.time;\n    }\n    __name(isTimeElement, \"isTimeElement\");\n    exports2.isTimeElement = isTimeElement;\n    function isSelectElement(el) {\n      return el.type === TYPE2.select;\n    }\n    __name(isSelectElement, \"isSelectElement\");\n    exports2.isSelectElement = isSelectElement;\n    function isPluralElement(el) {\n      return el.type === TYPE2.plural;\n    }\n    __name(isPluralElement, \"isPluralElement\");\n    exports2.isPluralElement = isPluralElement;\n    function isPoundElement(el) {\n      return el.type === TYPE2.pound;\n    }\n    __name(isPoundElement, \"isPoundElement\");\n    exports2.isPoundElement = isPoundElement;\n    function isTagElement(el) {\n      return el.type === TYPE2.tag;\n    }\n    __name(isTagElement, \"isTagElement\");\n    exports2.isTagElement = isTagElement;\n    function isNumberSkeleton(el) {\n      return !!(el && typeof el === \"object\" && el.type === SKELETON_TYPE.number);\n    }\n    __name(isNumberSkeleton, \"isNumberSkeleton\");\n    exports2.isNumberSkeleton = isNumberSkeleton;\n    function isDateTimeSkeleton(el) {\n      return !!(el && typeof el === \"object\" && el.type === SKELETON_TYPE.dateTime);\n    }\n    __name(isDateTimeSkeleton, \"isDateTimeSkeleton\");\n    exports2.isDateTimeSkeleton = isDateTimeSkeleton;\n    function createLiteralElement(value) {\n      return {\n        type: TYPE2.literal,\n        value\n      };\n    }\n    __name(createLiteralElement, \"createLiteralElement\");\n    exports2.createLiteralElement = createLiteralElement;\n    function createNumberElement(value, style) {\n      return {\n        type: TYPE2.number,\n        value,\n        style\n      };\n    }\n    __name(createNumberElement, \"createNumberElement\");\n    exports2.createNumberElement = createNumberElement;\n  }\n});\n\n// node_modules/@formatjs/icu-messageformat-parser/regex.generated.js\nvar require_regex_generated = __commonJS({\n  \"node_modules/@formatjs/icu-messageformat-parser/regex.generated.js\"(exports2) {\n    \"use strict\";\n    init_process_global();\n    Object.defineProperty(exports2, \"__esModule\", { value: true });\n    exports2.WHITE_SPACE_REGEX = exports2.SPACE_SEPARATOR_REGEX = void 0;\n    exports2.SPACE_SEPARATOR_REGEX = /[ \\xA0\\u1680\\u2000-\\u200A\\u202F\\u205F\\u3000]/;\n    exports2.WHITE_SPACE_REGEX = /[\\t-\\r \\x85\\u200E\\u200F\\u2028\\u2029]/;\n  }\n});\n\n// node_modules/@formatjs/icu-skeleton-parser/node_modules/tslib/tslib.es6.mjs\nvar tslib_es6_exports3 = {};\n__export(tslib_es6_exports3, {\n  __addDisposableResource: () => __addDisposableResource3,\n  __assign: () => __assign3,\n  __asyncDelegator: () => __asyncDelegator3,\n  __asyncGenerator: () => __asyncGenerator3,\n  __asyncValues: () => __asyncValues3,\n  __await: () => __await3,\n  __awaiter: () => __awaiter3,\n  __classPrivateFieldGet: () => __classPrivateFieldGet3,\n  __classPrivateFieldIn: () => __classPrivateFieldIn3,\n  __classPrivateFieldSet: () => __classPrivateFieldSet3,\n  __createBinding: () => __createBinding3,\n  __decorate: () => __decorate3,\n  __disposeResources: () => __disposeResources3,\n  __esDecorate: () => __esDecorate3,\n  __exportStar: () => __exportStar3,\n  __extends: () => __extends3,\n  __generator: () => __generator3,\n  __importDefault: () => __importDefault3,\n  __importStar: () => __importStar3,\n  __makeTemplateObject: () => __makeTemplateObject3,\n  __metadata: () => __metadata3,\n  __param: () => __param3,\n  __propKey: () => __propKey3,\n  __read: () => __read3,\n  __rest: () => __rest3,\n  __runInitializers: () => __runInitializers3,\n  __setFunctionName: () => __setFunctionName3,\n  __spread: () => __spread3,\n  __spreadArray: () => __spreadArray3,\n  __spreadArrays: () => __spreadArrays3,\n  __values: () => __values3,\n  default: () => tslib_es6_default3\n});\nfunction __extends3(d, b) {\n  if (typeof b !== \"function\" && b !== null)\n    throw new TypeError(\"Class extends value \" + String(b) + \" is not a constructor or null\");\n  extendStatics3(d, b);\n  function __() {\n    this.constructor = d;\n  }\n  __name(__, \"__\");\n  d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());\n}\nfunction __rest3(s, e) {\n  var t = {};\n  for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)\n    t[p] = s[p];\n  if (s != null && typeof Object.getOwnPropertySymbols === \"function\")\n    for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {\n      if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))\n        t[p[i]] = s[p[i]];\n    }\n  return t;\n}\nfunction __decorate3(decorators, target, key, desc) {\n  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\n  if (typeof Reflect === \"object\" && typeof Reflect.decorate === \"function\") r = Reflect.decorate(decorators, target, key, desc);\n  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\n  return c > 3 && r && Object.defineProperty(target, key, r), r;\n}\nfunction __param3(paramIndex, decorator) {\n  return function(target, key) {\n    decorator(target, key, paramIndex);\n  };\n}\nfunction __esDecorate3(ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {\n  function accept(f) {\n    if (f !== void 0 && typeof f !== \"function\") throw new TypeError(\"Function expected\");\n    return f;\n  }\n  __name(accept, \"accept\");\n  var kind = contextIn.kind, key = kind === \"getter\" ? \"get\" : kind === \"setter\" ? \"set\" : \"value\";\n  var target = !descriptorIn && ctor ? contextIn[\"static\"] ? ctor : ctor.prototype : null;\n  var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});\n  var _, done = false;\n  for (var i = decorators.length - 1; i >= 0; i--) {\n    var context = {};\n    for (var p in contextIn) context[p] = p === \"access\" ? {} : contextIn[p];\n    for (var p in contextIn.access) context.access[p] = contextIn.access[p];\n    context.addInitializer = function(f) {\n      if (done) throw new TypeError(\"Cannot add initializers after decoration has completed\");\n      extraInitializers.push(accept(f || null));\n    };\n    var result = (0, decorators[i])(kind === \"accessor\" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);\n    if (kind === \"accessor\") {\n      if (result === void 0) continue;\n      if (result === null || typeof result !== \"object\") throw new TypeError(\"Object expected\");\n      if (_ = accept(result.get)) descriptor.get = _;\n      if (_ = accept(result.set)) descriptor.set = _;\n      if (_ = accept(result.init)) initializers.unshift(_);\n    } else if (_ = accept(result)) {\n      if (kind === \"field\") initializers.unshift(_);\n      else descriptor[key] = _;\n    }\n  }\n  if (target) Object.defineProperty(target, contextIn.name, descriptor);\n  done = true;\n}\nfunction __runInitializers3(thisArg, initializers, value) {\n  var useValue = arguments.length > 2;\n  for (var i = 0; i < initializers.length; i++) {\n    value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);\n  }\n  return useValue ? value : void 0;\n}\nfunction __propKey3(x) {\n  return typeof x === \"symbol\" ? x : \"\".concat(x);\n}\nfunction __setFunctionName3(f, name, prefix) {\n  if (typeof name === \"symbol\") name = name.description ? \"[\".concat(name.description, \"]\") : \"\";\n  return Object.defineProperty(f, \"name\", { configurable: true, value: prefix ? \"\".concat(prefix, \" \", name) : name });\n}\nfunction __metadata3(metadataKey, metadataValue) {\n  if (typeof Reflect === \"object\" && typeof Reflect.metadata === \"function\") return Reflect.metadata(metadataKey, metadataValue);\n}\nfunction __awaiter3(thisArg, _arguments, P, generator) {\n  function adopt(value) {\n    return value instanceof P ? value : new P(function(resolve) {\n      resolve(value);\n    });\n  }\n  __name(adopt, \"adopt\");\n  return new (P || (P = Promise))(function(resolve, reject) {\n    function fulfilled(value) {\n      try {\n        step(generator.next(value));\n      } catch (e) {\n        reject(e);\n      }\n    }\n    __name(fulfilled, \"fulfilled\");\n    function rejected(value) {\n      try {\n        step(generator[\"throw\"](value));\n      } catch (e) {\n        reject(e);\n      }\n    }\n    __name(rejected, \"rejected\");\n    function step(result) {\n      result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected);\n    }\n    __name(step, \"step\");\n    step((generator = generator.apply(thisArg, _arguments || [])).next());\n  });\n}\nfunction __generator3(thisArg, body) {\n  var _ = { label: 0, sent: /* @__PURE__ */ __name(function() {\n    if (t[0] & 1) throw t[1];\n    return t[1];\n  }, \"sent\"), trys: [], ops: [] }, f, y, t, g;\n  return g = { next: verb(0), \"throw\": verb(1), \"return\": verb(2) }, typeof Symbol === \"function\" && (g[Symbol.iterator] = function() {\n    return this;\n  }), g;\n  function verb(n) {\n    return function(v) {\n      return step([n, v]);\n    };\n  }\n  __name(verb, \"verb\");\n  function step(op) {\n    if (f) throw new TypeError(\"Generator is already executing.\");\n    while (g && (g = 0, op[0] && (_ = 0)), _) try {\n      if (f = 1, y && (t = op[0] & 2 ? y[\"return\"] : op[0] ? y[\"throw\"] || ((t = y[\"return\"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;\n      if (y = 0, t) op = [op[0] & 2, t.value];\n      switch (op[0]) {\n        case 0:\n        case 1:\n          t = op;\n          break;\n        case 4:\n          _.label++;\n          return { value: op[1], done: false };\n        case 5:\n          _.label++;\n          y = op[1];\n          op = [0];\n          continue;\n        case 7:\n          op = _.ops.pop();\n          _.trys.pop();\n          continue;\n        default:\n          if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) {\n            _ = 0;\n            continue;\n          }\n          if (op[0] === 3 && (!t || op[1] > t[0] && op[1] < t[3])) {\n            _.label = op[1];\n            break;\n          }\n          if (op[0] === 6 && _.label < t[1]) {\n            _.label = t[1];\n            t = op;\n            break;\n          }\n          if (t && _.label < t[2]) {\n            _.label = t[2];\n            _.ops.push(op);\n            break;\n          }\n          if (t[2]) _.ops.pop();\n          _.trys.pop();\n          continue;\n      }\n      op = body.call(thisArg, _);\n    } catch (e) {\n      op = [6, e];\n      y = 0;\n    } finally {\n      f = t = 0;\n    }\n    if (op[0] & 5) throw op[1];\n    return { value: op[0] ? op[1] : void 0, done: true };\n  }\n  __name(step, \"step\");\n}\nfunction __exportStar3(m, o) {\n  for (var p in m) if (p !== \"default\" && !Object.prototype.hasOwnProperty.call(o, p)) __createBinding3(o, m, p);\n}\nfunction __values3(o) {\n  var s = typeof Symbol === \"function\" && Symbol.iterator, m = s && o[s], i = 0;\n  if (m) return m.call(o);\n  if (o && typeof o.length === \"number\") return {\n    next: /* @__PURE__ */ __name(function() {\n      if (o && i >= o.length) o = void 0;\n      return { value: o && o[i++], done: !o };\n    }, \"next\")\n  };\n  throw new TypeError(s ? \"Object is not iterable.\" : \"Symbol.iterator is not defined.\");\n}\nfunction __read3(o, n) {\n  var m = typeof Symbol === \"function\" && o[Symbol.iterator];\n  if (!m) return o;\n  var i = m.call(o), r, ar = [], e;\n  try {\n    while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);\n  } catch (error) {\n    e = { error };\n  } finally {\n    try {\n      if (r && !r.done && (m = i[\"return\"])) m.call(i);\n    } finally {\n      if (e) throw e.error;\n    }\n  }\n  return ar;\n}\nfunction __spread3() {\n  for (var ar = [], i = 0; i < arguments.length; i++)\n    ar = ar.concat(__read3(arguments[i]));\n  return ar;\n}\nfunction __spreadArrays3() {\n  for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;\n  for (var r = Array(s), k = 0, i = 0; i < il; i++)\n    for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)\n      r[k] = a[j];\n  return r;\n}\nfunction __spreadArray3(to, from, pack) {\n  if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {\n    if (ar || !(i in from)) {\n      if (!ar) ar = Array.prototype.slice.call(from, 0, i);\n      ar[i] = from[i];\n    }\n  }\n  return to.concat(ar || Array.prototype.slice.call(from));\n}\nfunction __await3(v) {\n  return this instanceof __await3 ? (this.v = v, this) : new __await3(v);\n}\nfunction __asyncGenerator3(thisArg, _arguments, generator) {\n  if (!Symbol.asyncIterator) throw new TypeError(\"Symbol.asyncIterator is not defined.\");\n  var g = generator.apply(thisArg, _arguments || []), i, q = [];\n  return i = {}, verb(\"next\"), verb(\"throw\"), verb(\"return\"), i[Symbol.asyncIterator] = function() {\n    return this;\n  }, i;\n  function verb(n) {\n    if (g[n]) i[n] = function(v) {\n      return new Promise(function(a, b) {\n        q.push([n, v, a, b]) > 1 || resume(n, v);\n      });\n    };\n  }\n  __name(verb, \"verb\");\n  function resume(n, v) {\n    try {\n      step(g[n](v));\n    } catch (e) {\n      settle(q[0][3], e);\n    }\n  }\n  __name(resume, \"resume\");\n  function step(r) {\n    r.value instanceof __await3 ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r);\n  }\n  __name(step, \"step\");\n  function fulfill(value) {\n    resume(\"next\", value);\n  }\n  __name(fulfill, \"fulfill\");\n  function reject(value) {\n    resume(\"throw\", value);\n  }\n  __name(reject, \"reject\");\n  function settle(f, v) {\n    if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]);\n  }\n  __name(settle, \"settle\");\n}\nfunction __asyncDelegator3(o) {\n  var i, p;\n  return i = {}, verb(\"next\"), verb(\"throw\", function(e) {\n    throw e;\n  }), verb(\"return\"), i[Symbol.iterator] = function() {\n    return this;\n  }, i;\n  function verb(n, f) {\n    i[n] = o[n] ? function(v) {\n      return (p = !p) ? { value: __await3(o[n](v)), done: false } : f ? f(v) : v;\n    } : f;\n  }\n  __name(verb, \"verb\");\n}\nfunction __asyncValues3(o) {\n  if (!Symbol.asyncIterator) throw new TypeError(\"Symbol.asyncIterator is not defined.\");\n  var m = o[Symbol.asyncIterator], i;\n  return m ? m.call(o) : (o = typeof __values3 === \"function\" ? __values3(o) : o[Symbol.iterator](), i = {}, verb(\"next\"), verb(\"throw\"), verb(\"return\"), i[Symbol.asyncIterator] = function() {\n    return this;\n  }, i);\n  function verb(n) {\n    i[n] = o[n] && function(v) {\n      return new Promise(function(resolve, reject) {\n        v = o[n](v), settle(resolve, reject, v.done, v.value);\n      });\n    };\n  }\n  __name(verb, \"verb\");\n  function settle(resolve, reject, d, v) {\n    Promise.resolve(v).then(function(v2) {\n      resolve({ value: v2, done: d });\n    }, reject);\n  }\n  __name(settle, \"settle\");\n}\nfunction __makeTemplateObject3(cooked, raw) {\n  if (Object.defineProperty) {\n    Object.defineProperty(cooked, \"raw\", { value: raw });\n  } else {\n    cooked.raw = raw;\n  }\n  return cooked;\n}\nfunction __importStar3(mod2) {\n  if (mod2 && mod2.__esModule) return mod2;\n  var result = {};\n  if (mod2 != null) {\n    for (var k in mod2) if (k !== \"default\" && Object.prototype.hasOwnProperty.call(mod2, k)) __createBinding3(result, mod2, k);\n  }\n  __setModuleDefault3(result, mod2);\n  return result;\n}\nfunction __importDefault3(mod2) {\n  return mod2 && mod2.__esModule ? mod2 : { default: mod2 };\n}\nfunction __classPrivateFieldGet3(receiver, state, kind, f) {\n  if (kind === \"a\" && !f) throw new TypeError(\"Private accessor was defined without a getter\");\n  if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n  return kind === \"m\" ? f : kind === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n}\nfunction __classPrivateFieldSet3(receiver, state, value, kind, f) {\n  if (kind === \"m\") throw new TypeError(\"Private method is not writable\");\n  if (kind === \"a\" && !f) throw new TypeError(\"Private accessor was defined without a setter\");\n  if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n  return kind === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;\n}\nfunction __classPrivateFieldIn3(state, receiver) {\n  if (receiver === null || typeof receiver !== \"object\" && typeof receiver !== \"function\") throw new TypeError(\"Cannot use 'in' operator on non-object\");\n  return typeof state === \"function\" ? receiver === state : state.has(receiver);\n}\nfunction __addDisposableResource3(env, value, async) {\n  if (value !== null && value !== void 0) {\n    if (typeof value !== \"object\" && typeof value !== \"function\") throw new TypeError(\"Object expected.\");\n    var dispose;\n    if (async) {\n      if (!Symbol.asyncDispose) throw new TypeError(\"Symbol.asyncDispose is not defined.\");\n      dispose = value[Symbol.asyncDispose];\n    }\n    if (dispose === void 0) {\n      if (!Symbol.dispose) throw new TypeError(\"Symbol.dispose is not defined.\");\n      dispose = value[Symbol.dispose];\n    }\n    if (typeof dispose !== \"function\") throw new TypeError(\"Object not disposable.\");\n    env.stack.push({ value, dispose, async });\n  } else if (async) {\n    env.stack.push({ async: true });\n  }\n  return value;\n}\nfunction __disposeResources3(env) {\n  function fail(e) {\n    env.error = env.hasError ? new _SuppressedError3(e, env.error, \"An error was suppressed during disposal.\") : e;\n    env.hasError = true;\n  }\n  __name(fail, \"fail\");\n  function next() {\n    while (env.stack.length) {\n      var rec = env.stack.pop();\n      try {\n        var result = rec.dispose && rec.dispose.call(rec.value);\n        if (rec.async) return Promise.resolve(result).then(next, function(e) {\n          fail(e);\n          return next();\n        });\n      } catch (e) {\n        fail(e);\n      }\n    }\n    if (env.hasError) throw env.error;\n  }\n  __name(next, \"next\");\n  return next();\n}\nvar extendStatics3, __assign3, __createBinding3, __setModuleDefault3, _SuppressedError3, tslib_es6_default3;\nvar init_tslib_es63 = __esm({\n  \"node_modules/@formatjs/icu-skeleton-parser/node_modules/tslib/tslib.es6.mjs\"() {\n    init_process_global();\n    extendStatics3 = /* @__PURE__ */ __name(function(d, b) {\n      extendStatics3 = Object.setPrototypeOf || { __proto__: [] } instanceof Array && function(d2, b2) {\n        d2.__proto__ = b2;\n      } || function(d2, b2) {\n        for (var p in b2) if (Object.prototype.hasOwnProperty.call(b2, p)) d2[p] = b2[p];\n      };\n      return extendStatics3(d, b);\n    }, \"extendStatics\");\n    __name(__extends3, \"__extends\");\n    __assign3 = /* @__PURE__ */ __name(function() {\n      __assign3 = Object.assign || /* @__PURE__ */ __name(function __assign4(t) {\n        for (var s, i = 1, n = arguments.length; i < n; i++) {\n          s = arguments[i];\n          for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];\n        }\n        return t;\n      }, \"__assign\");\n      return __assign3.apply(this, arguments);\n    }, \"__assign\");\n    __name(__rest3, \"__rest\");\n    __name(__decorate3, \"__decorate\");\n    __name(__param3, \"__param\");\n    __name(__esDecorate3, \"__esDecorate\");\n    __name(__runInitializers3, \"__runInitializers\");\n    __name(__propKey3, \"__propKey\");\n    __name(__setFunctionName3, \"__setFunctionName\");\n    __name(__metadata3, \"__metadata\");\n    __name(__awaiter3, \"__awaiter\");\n    __name(__generator3, \"__generator\");\n    __createBinding3 = Object.create ? (function(o, m, k, k2) {\n      if (k2 === void 0) k2 = k;\n      var desc = Object.getOwnPropertyDescriptor(m, k);\n      if (!desc || (\"get\" in desc ? !m.__esModule : desc.writable || desc.configurable)) {\n        desc = { enumerable: true, get: /* @__PURE__ */ __name(function() {\n          return m[k];\n        }, \"get\") };\n      }\n      Object.defineProperty(o, k2, desc);\n    }) : (function(o, m, k, k2) {\n      if (k2 === void 0) k2 = k;\n      o[k2] = m[k];\n    });\n    __name(__exportStar3, \"__exportStar\");\n    __name(__values3, \"__values\");\n    __name(__read3, \"__read\");\n    __name(__spread3, \"__spread\");\n    __name(__spreadArrays3, \"__spreadArrays\");\n    __name(__spreadArray3, \"__spreadArray\");\n    __name(__await3, \"__await\");\n    __name(__asyncGenerator3, \"__asyncGenerator\");\n    __name(__asyncDelegator3, \"__asyncDelegator\");\n    __name(__asyncValues3, \"__asyncValues\");\n    __name(__makeTemplateObject3, \"__makeTemplateObject\");\n    __setModuleDefault3 = Object.create ? (function(o, v) {\n      Object.defineProperty(o, \"default\", { enumerable: true, value: v });\n    }) : function(o, v) {\n      o[\"default\"] = v;\n    };\n    __name(__importStar3, \"__importStar\");\n    __name(__importDefault3, \"__importDefault\");\n    __name(__classPrivateFieldGet3, \"__classPrivateFieldGet\");\n    __name(__classPrivateFieldSet3, \"__classPrivateFieldSet\");\n    __name(__classPrivateFieldIn3, \"__classPrivateFieldIn\");\n    __name(__addDisposableResource3, \"__addDisposableResource\");\n    _SuppressedError3 = typeof SuppressedError === \"function\" ? SuppressedError : function(error, suppressed, message) {\n      var e = new Error(message);\n      return e.name = \"SuppressedError\", e.error = error, e.suppressed = suppressed, e;\n    };\n    __name(__disposeResources3, \"__disposeResources\");\n    tslib_es6_default3 = {\n      __extends: __extends3,\n      __assign: __assign3,\n      __rest: __rest3,\n      __decorate: __decorate3,\n      __param: __param3,\n      __metadata: __metadata3,\n      __awaiter: __awaiter3,\n      __generator: __generator3,\n      __createBinding: __createBinding3,\n      __exportStar: __exportStar3,\n      __values: __values3,\n      __read: __read3,\n      __spread: __spread3,\n      __spreadArrays: __spreadArrays3,\n      __spreadArray: __spreadArray3,\n      __await: __await3,\n      __asyncGenerator: __asyncGenerator3,\n      __asyncDelegator: __asyncDelegator3,\n      __asyncValues: __asyncValues3,\n      __makeTemplateObject: __makeTemplateObject3,\n      __importStar: __importStar3,\n      __importDefault: __importDefault3,\n      __classPrivateFieldGet: __classPrivateFieldGet3,\n      __classPrivateFieldSet: __classPrivateFieldSet3,\n      __classPrivateFieldIn: __classPrivateFieldIn3,\n      __addDisposableResource: __addDisposableResource3,\n      __disposeResources: __disposeResources3\n    };\n  }\n});\n\n// node_modules/@formatjs/icu-skeleton-parser/date-time.js\nvar require_date_time = __commonJS({\n  \"node_modules/@formatjs/icu-skeleton-parser/date-time.js\"(exports2) {\n    \"use strict\";\n    init_process_global();\n    Object.defineProperty(exports2, \"__esModule\", { value: true });\n    exports2.parseDateTimeSkeleton = void 0;\n    var DATE_TIME_REGEX = /(?:[Eec]{1,6}|G{1,5}|[Qq]{1,5}|(?:[yYur]+|U{1,5})|[ML]{1,5}|d{1,2}|D{1,3}|F{1}|[abB]{1,5}|[hkHK]{1,2}|w{1,2}|W{1}|m{1,2}|s{1,2}|[zZOvVxX]{1,4})(?=([^']*'[^']*')*[^']*$)/g;\n    function parseDateTimeSkeleton(skeleton) {\n      var result = {};\n      skeleton.replace(DATE_TIME_REGEX, function(match) {\n        var len = match.length;\n        switch (match[0]) {\n          // Era\n          case \"G\":\n            result.era = len === 4 ? \"long\" : len === 5 ? \"narrow\" : \"short\";\n            break;\n          // Year\n          case \"y\":\n            result.year = len === 2 ? \"2-digit\" : \"numeric\";\n            break;\n          case \"Y\":\n          case \"u\":\n          case \"U\":\n          case \"r\":\n            throw new RangeError(\"`Y/u/U/r` (year) patterns are not supported, use `y` instead\");\n          // Quarter\n          case \"q\":\n          case \"Q\":\n            throw new RangeError(\"`q/Q` (quarter) patterns are not supported\");\n          // Month\n          case \"M\":\n          case \"L\":\n            result.month = [\"numeric\", \"2-digit\", \"short\", \"long\", \"narrow\"][len - 1];\n            break;\n          // Week\n          case \"w\":\n          case \"W\":\n            throw new RangeError(\"`w/W` (week) patterns are not supported\");\n          case \"d\":\n            result.day = [\"numeric\", \"2-digit\"][len - 1];\n            break;\n          case \"D\":\n          case \"F\":\n          case \"g\":\n            throw new RangeError(\"`D/F/g` (day) patterns are not supported, use `d` instead\");\n          // Weekday\n          case \"E\":\n            result.weekday = len === 4 ? \"short\" : len === 5 ? \"narrow\" : \"short\";\n            break;\n          case \"e\":\n            if (len < 4) {\n              throw new RangeError(\"`e..eee` (weekday) patterns are not supported\");\n            }\n            result.weekday = [\"short\", \"long\", \"narrow\", \"short\"][len - 4];\n            break;\n          case \"c\":\n            if (len < 4) {\n              throw new RangeError(\"`c..ccc` (weekday) patterns are not supported\");\n            }\n            result.weekday = [\"short\", \"long\", \"narrow\", \"short\"][len - 4];\n            break;\n          // Period\n          case \"a\":\n            result.hour12 = true;\n            break;\n          case \"b\":\n          // am, pm, noon, midnight\n          case \"B\":\n            throw new RangeError(\"`b/B` (period) patterns are not supported, use `a` instead\");\n          // Hour\n          case \"h\":\n            result.hourCycle = \"h12\";\n            result.hour = [\"numeric\", \"2-digit\"][len - 1];\n            break;\n          case \"H\":\n            result.hourCycle = \"h23\";\n            result.hour = [\"numeric\", \"2-digit\"][len - 1];\n            break;\n          case \"K\":\n            result.hourCycle = \"h11\";\n            result.hour = [\"numeric\", \"2-digit\"][len - 1];\n            break;\n          case \"k\":\n            result.hourCycle = \"h24\";\n            result.hour = [\"numeric\", \"2-digit\"][len - 1];\n            break;\n          case \"j\":\n          case \"J\":\n          case \"C\":\n            throw new RangeError(\"`j/J/C` (hour) patterns are not supported, use `h/H/K/k` instead\");\n          // Minute\n          case \"m\":\n            result.minute = [\"numeric\", \"2-digit\"][len - 1];\n            break;\n          // Second\n          case \"s\":\n            result.second = [\"numeric\", \"2-digit\"][len - 1];\n            break;\n          case \"S\":\n          case \"A\":\n            throw new RangeError(\"`S/A` (second) patterns are not supported, use `s` instead\");\n          // Zone\n          case \"z\":\n            result.timeZoneName = len < 4 ? \"short\" : \"long\";\n            break;\n          case \"Z\":\n          // 1..3, 4, 5: The ISO8601 varios formats\n          case \"O\":\n          // 1, 4: miliseconds in day short, long\n          case \"v\":\n          // 1, 4: generic non-location format\n          case \"V\":\n          // 1, 2, 3, 4: time zone ID or city\n          case \"X\":\n          // 1, 2, 3, 4: The ISO8601 varios formats\n          case \"x\":\n            throw new RangeError(\"`Z/O/v/V/X/x` (timeZone) patterns are not supported, use `z` instead\");\n        }\n        return \"\";\n      });\n      return result;\n    }\n    __name(parseDateTimeSkeleton, \"parseDateTimeSkeleton\");\n    exports2.parseDateTimeSkeleton = parseDateTimeSkeleton;\n  }\n});\n\n// node_modules/@formatjs/icu-skeleton-parser/regex.generated.js\nvar require_regex_generated2 = __commonJS({\n  \"node_modules/@formatjs/icu-skeleton-parser/regex.generated.js\"(exports2) {\n    \"use strict\";\n    init_process_global();\n    Object.defineProperty(exports2, \"__esModule\", { value: true });\n    exports2.WHITE_SPACE_REGEX = void 0;\n    exports2.WHITE_SPACE_REGEX = /[\\t-\\r \\x85\\u200E\\u200F\\u2028\\u2029]/i;\n  }\n});\n\n// node_modules/@formatjs/icu-skeleton-parser/number.js\nvar require_number = __commonJS({\n  \"node_modules/@formatjs/icu-skeleton-parser/number.js\"(exports2) {\n    \"use strict\";\n    init_process_global();\n    Object.defineProperty(exports2, \"__esModule\", { value: true });\n    exports2.parseNumberSkeleton = exports2.parseNumberSkeletonFromString = void 0;\n    var tslib_1 = (init_tslib_es63(), __toCommonJS(tslib_es6_exports3));\n    var regex_generated_1 = require_regex_generated2();\n    function parseNumberSkeletonFromString(skeleton) {\n      if (skeleton.length === 0) {\n        throw new Error(\"Number skeleton cannot be empty\");\n      }\n      var stringTokens = skeleton.split(regex_generated_1.WHITE_SPACE_REGEX).filter(function(x) {\n        return x.length > 0;\n      });\n      var tokens = [];\n      for (var _i = 0, stringTokens_1 = stringTokens; _i < stringTokens_1.length; _i++) {\n        var stringToken = stringTokens_1[_i];\n        var stemAndOptions = stringToken.split(\"/\");\n        if (stemAndOptions.length === 0) {\n          throw new Error(\"Invalid number skeleton\");\n        }\n        var stem = stemAndOptions[0], options = stemAndOptions.slice(1);\n        for (var _a3 = 0, options_1 = options; _a3 < options_1.length; _a3++) {\n          var option = options_1[_a3];\n          if (option.length === 0) {\n            throw new Error(\"Invalid number skeleton\");\n          }\n        }\n        tokens.push({ stem, options });\n      }\n      return tokens;\n    }\n    __name(parseNumberSkeletonFromString, \"parseNumberSkeletonFromString\");\n    exports2.parseNumberSkeletonFromString = parseNumberSkeletonFromString;\n    function icuUnitToEcma(unit) {\n      return unit.replace(/^(.*?)-/, \"\");\n    }\n    __name(icuUnitToEcma, \"icuUnitToEcma\");\n    var FRACTION_PRECISION_REGEX = /^\\.(?:(0+)(\\*)?|(#+)|(0+)(#+))$/g;\n    var SIGNIFICANT_PRECISION_REGEX = /^(@+)?(\\+|#+)?[rs]?$/g;\n    var INTEGER_WIDTH_REGEX = /(\\*)(0+)|(#+)(0+)|(0+)/g;\n    var CONCISE_INTEGER_WIDTH_REGEX = /^(0+)$/;\n    function parseSignificantPrecision(str) {\n      var result = {};\n      if (str[str.length - 1] === \"r\") {\n        result.roundingPriority = \"morePrecision\";\n      } else if (str[str.length - 1] === \"s\") {\n        result.roundingPriority = \"lessPrecision\";\n      }\n      str.replace(SIGNIFICANT_PRECISION_REGEX, function(_, g1, g2) {\n        if (typeof g2 !== \"string\") {\n          result.minimumSignificantDigits = g1.length;\n          result.maximumSignificantDigits = g1.length;\n        } else if (g2 === \"+\") {\n          result.minimumSignificantDigits = g1.length;\n        } else if (g1[0] === \"#\") {\n          result.maximumSignificantDigits = g1.length;\n        } else {\n          result.minimumSignificantDigits = g1.length;\n          result.maximumSignificantDigits = g1.length + (typeof g2 === \"string\" ? g2.length : 0);\n        }\n        return \"\";\n      });\n      return result;\n    }\n    __name(parseSignificantPrecision, \"parseSignificantPrecision\");\n    function parseSign(str) {\n      switch (str) {\n        case \"sign-auto\":\n          return {\n            signDisplay: \"auto\"\n          };\n        case \"sign-accounting\":\n        case \"()\":\n          return {\n            currencySign: \"accounting\"\n          };\n        case \"sign-always\":\n        case \"+!\":\n          return {\n            signDisplay: \"always\"\n          };\n        case \"sign-accounting-always\":\n        case \"()!\":\n          return {\n            signDisplay: \"always\",\n            currencySign: \"accounting\"\n          };\n        case \"sign-except-zero\":\n        case \"+?\":\n          return {\n            signDisplay: \"exceptZero\"\n          };\n        case \"sign-accounting-except-zero\":\n        case \"()?\":\n          return {\n            signDisplay: \"exceptZero\",\n            currencySign: \"accounting\"\n          };\n        case \"sign-never\":\n        case \"+_\":\n          return {\n            signDisplay: \"never\"\n          };\n      }\n    }\n    __name(parseSign, \"parseSign\");\n    function parseConciseScientificAndEngineeringStem(stem) {\n      var result;\n      if (stem[0] === \"E\" && stem[1] === \"E\") {\n        result = {\n          notation: \"engineering\"\n        };\n        stem = stem.slice(2);\n      } else if (stem[0] === \"E\") {\n        result = {\n          notation: \"scientific\"\n        };\n        stem = stem.slice(1);\n      }\n      if (result) {\n        var signDisplay = stem.slice(0, 2);\n        if (signDisplay === \"+!\") {\n          result.signDisplay = \"always\";\n          stem = stem.slice(2);\n        } else if (signDisplay === \"+?\") {\n          result.signDisplay = \"exceptZero\";\n          stem = stem.slice(2);\n        }\n        if (!CONCISE_INTEGER_WIDTH_REGEX.test(stem)) {\n          throw new Error(\"Malformed concise eng/scientific notation\");\n        }\n        result.minimumIntegerDigits = stem.length;\n      }\n      return result;\n    }\n    __name(parseConciseScientificAndEngineeringStem, \"parseConciseScientificAndEngineeringStem\");\n    function parseNotationOptions(opt) {\n      var result = {};\n      var signOpts = parseSign(opt);\n      if (signOpts) {\n        return signOpts;\n      }\n      return result;\n    }\n    __name(parseNotationOptions, \"parseNotationOptions\");\n    function parseNumberSkeleton(tokens) {\n      var result = {};\n      for (var _i = 0, tokens_1 = tokens; _i < tokens_1.length; _i++) {\n        var token = tokens_1[_i];\n        switch (token.stem) {\n          case \"percent\":\n          case \"%\":\n            result.style = \"percent\";\n            continue;\n          case \"%x100\":\n            result.style = \"percent\";\n            result.scale = 100;\n            continue;\n          case \"currency\":\n            result.style = \"currency\";\n            result.currency = token.options[0];\n            continue;\n          case \"group-off\":\n          case \",_\":\n            result.useGrouping = false;\n            continue;\n          case \"precision-integer\":\n          case \".\":\n            result.maximumFractionDigits = 0;\n            continue;\n          case \"measure-unit\":\n          case \"unit\":\n            result.style = \"unit\";\n            result.unit = icuUnitToEcma(token.options[0]);\n            continue;\n          case \"compact-short\":\n          case \"K\":\n            result.notation = \"compact\";\n            result.compactDisplay = \"short\";\n            continue;\n          case \"compact-long\":\n          case \"KK\":\n            result.notation = \"compact\";\n            result.compactDisplay = \"long\";\n            continue;\n          case \"scientific\":\n            result = tslib_1.__assign(tslib_1.__assign(tslib_1.__assign({}, result), { notation: \"scientific\" }), token.options.reduce(function(all, opt2) {\n              return tslib_1.__assign(tslib_1.__assign({}, all), parseNotationOptions(opt2));\n            }, {}));\n            continue;\n          case \"engineering\":\n            result = tslib_1.__assign(tslib_1.__assign(tslib_1.__assign({}, result), { notation: \"engineering\" }), token.options.reduce(function(all, opt2) {\n              return tslib_1.__assign(tslib_1.__assign({}, all), parseNotationOptions(opt2));\n            }, {}));\n            continue;\n          case \"notation-simple\":\n            result.notation = \"standard\";\n            continue;\n          // https://github.com/unicode-org/icu/blob/master/icu4c/source/i18n/unicode/unumberformatter.h\n          case \"unit-width-narrow\":\n            result.currencyDisplay = \"narrowSymbol\";\n            result.unitDisplay = \"narrow\";\n            continue;\n          case \"unit-width-short\":\n            result.currencyDisplay = \"code\";\n            result.unitDisplay = \"short\";\n            continue;\n          case \"unit-width-full-name\":\n            result.currencyDisplay = \"name\";\n            result.unitDisplay = \"long\";\n            continue;\n          case \"unit-width-iso-code\":\n            result.currencyDisplay = \"symbol\";\n            continue;\n          case \"scale\":\n            result.scale = parseFloat(token.options[0]);\n            continue;\n          // https://unicode-org.github.io/icu/userguide/format_parse/numbers/skeletons.html#integer-width\n          case \"integer-width\":\n            if (token.options.length > 1) {\n              throw new RangeError(\"integer-width stems only accept a single optional option\");\n            }\n            token.options[0].replace(INTEGER_WIDTH_REGEX, function(_, g1, g2, g3, g4, g5) {\n              if (g1) {\n                result.minimumIntegerDigits = g2.length;\n              } else if (g3 && g4) {\n                throw new Error(\"We currently do not support maximum integer digits\");\n              } else if (g5) {\n                throw new Error(\"We currently do not support exact integer digits\");\n              }\n              return \"\";\n            });\n            continue;\n        }\n        if (CONCISE_INTEGER_WIDTH_REGEX.test(token.stem)) {\n          result.minimumIntegerDigits = token.stem.length;\n          continue;\n        }\n        if (FRACTION_PRECISION_REGEX.test(token.stem)) {\n          if (token.options.length > 1) {\n            throw new RangeError(\"Fraction-precision stems only accept a single optional option\");\n          }\n          token.stem.replace(FRACTION_PRECISION_REGEX, function(_, g1, g2, g3, g4, g5) {\n            if (g2 === \"*\") {\n              result.minimumFractionDigits = g1.length;\n            } else if (g3 && g3[0] === \"#\") {\n              result.maximumFractionDigits = g3.length;\n            } else if (g4 && g5) {\n              result.minimumFractionDigits = g4.length;\n              result.maximumFractionDigits = g4.length + g5.length;\n            } else {\n              result.minimumFractionDigits = g1.length;\n              result.maximumFractionDigits = g1.length;\n            }\n            return \"\";\n          });\n          var opt = token.options[0];\n          if (opt === \"w\") {\n            result = tslib_1.__assign(tslib_1.__assign({}, result), { trailingZeroDisplay: \"stripIfInteger\" });\n          } else if (opt) {\n            result = tslib_1.__assign(tslib_1.__assign({}, result), parseSignificantPrecision(opt));\n          }\n          continue;\n        }\n        if (SIGNIFICANT_PRECISION_REGEX.test(token.stem)) {\n          result = tslib_1.__assign(tslib_1.__assign({}, result), parseSignificantPrecision(token.stem));\n          continue;\n        }\n        var signOpts = parseSign(token.stem);\n        if (signOpts) {\n          result = tslib_1.__assign(tslib_1.__assign({}, result), signOpts);\n        }\n        var conciseScientificAndEngineeringOpts = parseConciseScientificAndEngineeringStem(token.stem);\n        if (conciseScientificAndEngineeringOpts) {\n          result = tslib_1.__assign(tslib_1.__assign({}, result), conciseScientificAndEngineeringOpts);\n        }\n      }\n      return result;\n    }\n    __name(parseNumberSkeleton, \"parseNumberSkeleton\");\n    exports2.parseNumberSkeleton = parseNumberSkeleton;\n  }\n});\n\n// node_modules/@formatjs/icu-skeleton-parser/index.js\nvar require_icu_skeleton_parser = __commonJS({\n  \"node_modules/@formatjs/icu-skeleton-parser/index.js\"(exports2) {\n    \"use strict\";\n    init_process_global();\n    Object.defineProperty(exports2, \"__esModule\", { value: true });\n    var tslib_1 = (init_tslib_es63(), __toCommonJS(tslib_es6_exports3));\n    tslib_1.__exportStar(require_date_time(), exports2);\n    tslib_1.__exportStar(require_number(), exports2);\n  }\n});\n\n// node_modules/@formatjs/icu-messageformat-parser/time-data.generated.js\nvar require_time_data_generated = __commonJS({\n  \"node_modules/@formatjs/icu-messageformat-parser/time-data.generated.js\"(exports2) {\n    \"use strict\";\n    init_process_global();\n    Object.defineProperty(exports2, \"__esModule\", { value: true });\n    exports2.timeData = void 0;\n    exports2.timeData = {\n      \"001\": [\n        \"H\",\n        \"h\"\n      ],\n      \"AC\": [\n        \"H\",\n        \"h\",\n        \"hb\",\n        \"hB\"\n      ],\n      \"AD\": [\n        \"H\",\n        \"hB\"\n      ],\n      \"AE\": [\n        \"h\",\n        \"hB\",\n        \"hb\",\n        \"H\"\n      ],\n      \"AF\": [\n        \"H\",\n        \"hb\",\n        \"hB\",\n        \"h\"\n      ],\n      \"AG\": [\n        \"h\",\n        \"hb\",\n        \"H\",\n        \"hB\"\n      ],\n      \"AI\": [\n        \"H\",\n        \"h\",\n        \"hb\",\n        \"hB\"\n      ],\n      \"AL\": [\n        \"h\",\n        \"H\",\n        \"hB\"\n      ],\n      \"AM\": [\n        \"H\",\n        \"hB\"\n      ],\n      \"AO\": [\n        \"H\",\n        \"hB\"\n      ],\n      \"AR\": [\n        \"H\",\n        \"h\",\n        \"hB\",\n        \"hb\"\n      ],\n      \"AS\": [\n        \"h\",\n        \"H\"\n      ],\n      \"AT\": [\n        \"H\",\n        \"hB\"\n      ],\n      \"AU\": [\n        \"h\",\n        \"hb\",\n        \"H\",\n        \"hB\"\n      ],\n      \"AW\": [\n        \"H\",\n        \"hB\"\n      ],\n      \"AX\": [\n        \"H\"\n      ],\n      \"AZ\": [\n        \"H\",\n        \"hB\",\n        \"h\"\n      ],\n      \"BA\": [\n        \"H\",\n        \"hB\",\n        \"h\"\n      ],\n      \"BB\": [\n        \"h\",\n        \"hb\",\n        \"H\",\n        \"hB\"\n      ],\n      \"BD\": [\n        \"h\",\n        \"hB\",\n        \"H\"\n      ],\n      \"BE\": [\n        \"H\",\n        \"hB\"\n      ],\n      \"BF\": [\n        \"H\",\n        \"hB\"\n      ],\n      \"BG\": [\n        \"H\",\n        \"hB\",\n        \"h\"\n      ],\n      \"BH\": [\n        \"h\",\n        \"hB\",\n        \"hb\",\n        \"H\"\n      ],\n      \"BJ\": [\n        \"H\",\n        \"hB\"\n      ],\n      \"BL\": [\n        \"H\",\n        \"hB\"\n      ],\n      \"BM\": [\n        \"h\",\n        \"hb\",\n        \"H\",\n        \"hB\"\n      ],\n      \"BN\": [\n        \"hb\",\n        \"hB\",\n        \"h\",\n        \"H\"\n      ],\n      \"BO\": [\n        \"H\",\n        \"hB\",\n        \"h\",\n        \"hb\"\n      ],\n      \"BQ\": [\n        \"H\"\n      ],\n      \"BR\": [\n        \"H\",\n        \"hB\"\n      ],\n      \"BS\": [\n        \"h\",\n        \"hb\",\n        \"H\",\n        \"hB\"\n      ],\n      \"BT\": [\n        \"h\",\n        \"H\"\n      ],\n      \"BW\": [\n        \"H\",\n        \"h\",\n        \"hb\",\n        \"hB\"\n      ],\n      \"BZ\": [\n        \"H\",\n        \"h\",\n        \"hb\",\n        \"hB\"\n      ],\n      \"CA\": [\n        \"h\",\n        \"hb\",\n        \"H\",\n        \"hB\"\n      ],\n      \"CC\": [\n        \"H\",\n        \"h\",\n        \"hb\",\n        \"hB\"\n      ],\n      \"CD\": [\n        \"hB\",\n        \"H\"\n      ],\n      \"CF\": [\n        \"H\",\n        \"h\",\n        \"hB\"\n      ],\n      \"CG\": [\n        \"H\",\n        \"hB\"\n      ],\n      \"CH\": [\n        \"H\",\n        \"hB\",\n        \"h\"\n      ],\n      \"CI\": [\n        \"H\",\n        \"hB\"\n      ],\n      \"CK\": [\n        \"H\",\n        \"h\",\n        \"hb\",\n        \"hB\"\n      ],\n      \"CL\": [\n        \"H\",\n        \"h\",\n        \"hB\",\n        \"hb\"\n      ],\n      \"CM\": [\n        \"H\",\n        \"h\",\n        \"hB\"\n      ],\n      \"CN\": [\n        \"H\",\n        \"hB\",\n        \"hb\",\n        \"h\"\n      ],\n      \"CO\": [\n        \"h\",\n        \"H\",\n        \"hB\",\n        \"hb\"\n      ],\n      \"CP\": [\n        \"H\"\n      ],\n      \"CR\": [\n        \"H\",\n        \"h\",\n        \"hB\",\n        \"hb\"\n      ],\n      \"CU\": [\n        \"H\",\n        \"h\",\n        \"hB\",\n        \"hb\"\n      ],\n      \"CV\": [\n        \"H\",\n        \"hB\"\n      ],\n      \"CX\": [\n        \"H\",\n        \"h\",\n        \"hb\",\n        \"hB\"\n      ],\n      \"CY\": [\n        \"h\",\n        \"H\",\n        \"hb\",\n        \"hB\"\n      ],\n      \"CZ\": [\n        \"H\"\n      ],\n      \"DE\": [\n        \"H\",\n        \"hB\"\n      ],\n      \"DG\": [\n        \"H\",\n        \"h\",\n        \"hb\",\n        \"hB\"\n      ],\n      \"DJ\": [\n        \"h\",\n        \"H\"\n      ],\n      \"DK\": [\n        \"H\"\n      ],\n      \"DM\": [\n        \"h\",\n        \"hb\",\n        \"H\",\n        \"hB\"\n      ],\n      \"DO\": [\n        \"h\",\n        \"H\",\n        \"hB\",\n        \"hb\"\n      ],\n      \"DZ\": [\n        \"h\",\n        \"hB\",\n        \"hb\",\n        \"H\"\n      ],\n      \"EA\": [\n        \"H\",\n        \"h\",\n        \"hB\",\n        \"hb\"\n      ],\n      \"EC\": [\n        \"H\",\n        \"hB\",\n        \"h\",\n        \"hb\"\n      ],\n      \"EE\": [\n        \"H\",\n        \"hB\"\n      ],\n      \"EG\": [\n        \"h\",\n        \"hB\",\n        \"hb\",\n        \"H\"\n      ],\n      \"EH\": [\n        \"h\",\n        \"hB\",\n        \"hb\",\n        \"H\"\n      ],\n      \"ER\": [\n        \"h\",\n        \"H\"\n      ],\n      \"ES\": [\n        \"H\",\n        \"hB\",\n        \"h\",\n        \"hb\"\n      ],\n      \"ET\": [\n        \"hB\",\n        \"hb\",\n        \"h\",\n        \"H\"\n      ],\n      \"FI\": [\n        \"H\"\n      ],\n      \"FJ\": [\n        \"h\",\n        \"hb\",\n        \"H\",\n        \"hB\"\n      ],\n      \"FK\": [\n        \"H\",\n        \"h\",\n        \"hb\",\n        \"hB\"\n      ],\n      \"FM\": [\n        \"h\",\n        \"hb\",\n        \"H\",\n        \"hB\"\n      ],\n      \"FR\": [\n        \"H\",\n        \"hB\"\n      ],\n      \"GA\": [\n        \"H\",\n        \"hB\"\n      ],\n      \"GB\": [\n        \"H\",\n        \"h\",\n        \"hb\",\n        \"hB\"\n      ],\n      \"GD\": [\n        \"h\",\n        \"hb\",\n        \"H\",\n        \"hB\"\n      ],\n      \"GE\": [\n        \"H\",\n        \"hB\",\n        \"h\"\n      ],\n      \"GF\": [\n        \"H\",\n        \"hB\"\n      ],\n      \"GG\": [\n        \"H\",\n        \"h\",\n        \"hb\",\n        \"hB\"\n      ],\n      \"GH\": [\n        \"h\",\n        \"H\"\n      ],\n      \"GI\": [\n        \"H\",\n        \"h\",\n        \"hb\",\n        \"hB\"\n      ],\n      \"GM\": [\n        \"h\",\n        \"hb\",\n        \"H\",\n        \"hB\"\n      ],\n      \"GN\": [\n        \"H\",\n        \"hB\"\n      ],\n      \"GP\": [\n        \"H\",\n        \"hB\"\n      ],\n      \"GQ\": [\n        \"H\",\n        \"hB\",\n        \"h\",\n        \"hb\"\n      ],\n      \"GR\": [\n        \"h\",\n        \"H\",\n        \"hb\",\n        \"hB\"\n      ],\n      \"GT\": [\n        \"H\",\n        \"h\",\n        \"hB\",\n        \"hb\"\n      ],\n      \"GU\": [\n        \"h\",\n        \"hb\",\n        \"H\",\n        \"hB\"\n      ],\n      \"GW\": [\n        \"H\",\n        \"hB\"\n      ],\n      \"GY\": [\n        \"h\",\n        \"hb\",\n        \"H\",\n        \"hB\"\n      ],\n      \"HK\": [\n        \"h\",\n        \"hB\",\n        \"hb\",\n        \"H\"\n      ],\n      \"HN\": [\n        \"H\",\n        \"h\",\n        \"hB\",\n        \"hb\"\n      ],\n      \"HR\": [\n        \"H\",\n        \"hB\"\n      ],\n      \"IC\": [\n        \"H\",\n        \"h\",\n        \"hB\",\n        \"hb\"\n      ],\n      \"ID\": [\n        \"H\"\n      ],\n      \"IE\": [\n        \"H\",\n        \"h\",\n        \"hb\",\n        \"hB\"\n      ],\n      \"IL\": [\n        \"H\",\n        \"hB\"\n      ],\n      \"IM\": [\n        \"H\",\n        \"h\",\n        \"hb\",\n        \"hB\"\n      ],\n      \"IN\": [\n        \"h\",\n        \"H\"\n      ],\n      \"IO\": [\n        \"H\",\n        \"h\",\n        \"hb\",\n        \"hB\"\n      ],\n      \"IQ\": [\n        \"h\",\n        \"hB\",\n        \"hb\",\n        \"H\"\n      ],\n      \"IR\": [\n        \"hB\",\n        \"H\"\n      ],\n      \"IS\": [\n        \"H\"\n      ],\n      \"IT\": [\n        \"H\",\n        \"hB\"\n      ],\n      \"JE\": [\n        \"H\",\n        \"h\",\n        \"hb\",\n        \"hB\"\n      ],\n      \"JM\": [\n        \"h\",\n        \"hb\",\n        \"H\",\n        \"hB\"\n      ],\n      \"JO\": [\n        \"h\",\n        \"hB\",\n        \"hb\",\n        \"H\"\n      ],\n      \"JP\": [\n        \"H\",\n        \"h\",\n        \"K\"\n      ],\n      \"KE\": [\n        \"hB\",\n        \"hb\",\n        \"H\",\n        \"h\"\n      ],\n      \"KG\": [\n        \"H\",\n        \"h\",\n        \"hB\",\n        \"hb\"\n      ],\n      \"KH\": [\n        \"hB\",\n        \"h\",\n        \"H\",\n        \"hb\"\n      ],\n      \"KI\": [\n        \"h\",\n        \"hb\",\n        \"H\",\n        \"hB\"\n      ],\n      \"KM\": [\n        \"H\",\n        \"h\",\n        \"hB\",\n        \"hb\"\n      ],\n      \"KN\": [\n        \"h\",\n        \"hb\",\n        \"H\",\n        \"hB\"\n      ],\n      \"KP\": [\n        \"h\",\n        \"H\",\n        \"hB\",\n        \"hb\"\n      ],\n      \"KR\": [\n        \"h\",\n        \"H\",\n        \"hB\",\n        \"hb\"\n      ],\n      \"KW\": [\n        \"h\",\n        \"hB\",\n        \"hb\",\n        \"H\"\n      ],\n      \"KY\": [\n        \"h\",\n        \"hb\",\n        \"H\",\n        \"hB\"\n      ],\n      \"KZ\": [\n        \"H\",\n        \"hB\"\n      ],\n      \"LA\": [\n        \"H\",\n        \"hb\",\n        \"hB\",\n        \"h\"\n      ],\n      \"LB\": [\n        \"h\",\n        \"hB\",\n        \"hb\",\n        \"H\"\n      ],\n      \"LC\": [\n        \"h\",\n        \"hb\",\n        \"H\",\n        \"hB\"\n      ],\n      \"LI\": [\n        \"H\",\n        \"hB\",\n        \"h\"\n      ],\n      \"LK\": [\n        \"H\",\n        \"h\",\n        \"hB\",\n        \"hb\"\n      ],\n      \"LR\": [\n        \"h\",\n        \"hb\",\n        \"H\",\n        \"hB\"\n      ],\n      \"LS\": [\n        \"h\",\n        \"H\"\n      ],\n      \"LT\": [\n        \"H\",\n        \"h\",\n        \"hb\",\n        \"hB\"\n      ],\n      \"LU\": [\n        \"H\",\n        \"h\",\n        \"hB\"\n      ],\n      \"LV\": [\n        \"H\",\n        \"hB\",\n        \"hb\",\n        \"h\"\n      ],\n      \"LY\": [\n        \"h\",\n        \"hB\",\n        \"hb\",\n        \"H\"\n      ],\n      \"MA\": [\n        \"H\",\n        \"h\",\n        \"hB\",\n        \"hb\"\n      ],\n      \"MC\": [\n        \"H\",\n        \"hB\"\n      ],\n      \"MD\": [\n        \"H\",\n        \"hB\"\n      ],\n      \"ME\": [\n        \"H\",\n        \"hB\",\n        \"h\"\n      ],\n      \"MF\": [\n        \"H\",\n        \"hB\"\n      ],\n      \"MH\": [\n        \"h\",\n        \"hb\",\n        \"H\",\n        \"hB\"\n      ],\n      \"MK\": [\n        \"H\",\n        \"h\",\n        \"hb\",\n        \"hB\"\n      ],\n      \"ML\": [\n        \"H\"\n      ],\n      \"MM\": [\n        \"hB\",\n        \"hb\",\n        \"H\",\n        \"h\"\n      ],\n      \"MN\": [\n        \"H\",\n        \"h\",\n        \"hb\",\n        \"hB\"\n      ],\n      \"MO\": [\n        \"h\",\n        \"hB\",\n        \"hb\",\n        \"H\"\n      ],\n      \"MP\": [\n        \"h\",\n        \"hb\",\n        \"H\",\n        \"hB\"\n      ],\n      \"MQ\": [\n        \"H\",\n        \"hB\"\n      ],\n      \"MR\": [\n        \"h\",\n        \"hB\",\n        \"hb\",\n        \"H\"\n      ],\n      \"MS\": [\n        \"H\",\n        \"h\",\n        \"hb\",\n        \"hB\"\n      ],\n      \"MW\": [\n        \"h\",\n        \"hb\",\n        \"H\",\n        \"hB\"\n      ],\n      \"MX\": [\n        \"H\",\n        \"h\",\n        \"hB\",\n        \"hb\"\n      ],\n      \"MY\": [\n        \"hb\",\n        \"hB\",\n        \"h\",\n        \"H\"\n      ],\n      \"MZ\": [\n        \"H\",\n        \"hB\"\n      ],\n      \"NA\": [\n        \"h\",\n        \"H\",\n        \"hB\",\n        \"hb\"\n      ],\n      \"NC\": [\n        \"H\",\n        \"hB\"\n      ],\n      \"NE\": [\n        \"H\"\n      ],\n      \"NF\": [\n        \"H\",\n        \"h\",\n        \"hb\",\n        \"hB\"\n      ],\n      \"NG\": [\n        \"H\",\n        \"h\",\n        \"hb\",\n        \"hB\"\n      ],\n      \"NI\": [\n        \"H\",\n        \"h\",\n        \"hB\",\n        \"hb\"\n      ],\n      \"NL\": [\n        \"H\",\n        \"hB\"\n      ],\n      \"NP\": [\n        \"H\",\n        \"h\",\n        \"hB\"\n      ],\n      \"NR\": [\n        \"H\",\n        \"h\",\n        \"hb\",\n        \"hB\"\n      ],\n      \"NU\": [\n        \"H\",\n        \"h\",\n        \"hb\",\n        \"hB\"\n      ],\n      \"NZ\": [\n        \"h\",\n        \"hb\",\n        \"H\",\n        \"hB\"\n      ],\n      \"OM\": [\n        \"h\",\n        \"hB\",\n        \"hb\",\n        \"H\"\n      ],\n      \"PA\": [\n        \"h\",\n        \"H\",\n        \"hB\",\n        \"hb\"\n      ],\n      \"PE\": [\n        \"H\",\n        \"hB\",\n        \"h\",\n        \"hb\"\n      ],\n      \"PF\": [\n        \"H\",\n        \"h\",\n        \"hB\"\n      ],\n      \"PG\": [\n        \"h\",\n        \"H\"\n      ],\n      \"PH\": [\n        \"h\",\n        \"hB\",\n        \"hb\",\n        \"H\"\n      ],\n      \"PK\": [\n        \"h\",\n        \"hB\",\n        \"H\"\n      ],\n      \"PM\": [\n        \"H\",\n        \"hB\"\n      ],\n      \"PN\": [\n        \"H\",\n        \"h\",\n        \"hb\",\n        \"hB\"\n      ],\n      \"PR\": [\n        \"h\",\n        \"H\",\n        \"hB\",\n        \"hb\"\n      ],\n      \"PS\": [\n        \"h\",\n        \"hB\",\n        \"hb\",\n        \"H\"\n      ],\n      \"PT\": [\n        \"H\",\n        \"hB\"\n      ],\n      \"PW\": [\n        \"h\",\n        \"H\"\n      ],\n      \"PY\": [\n        \"H\",\n        \"h\",\n        \"hB\",\n        \"hb\"\n      ],\n      \"QA\": [\n        \"h\",\n        \"hB\",\n        \"hb\",\n        \"H\"\n      ],\n      \"RE\": [\n        \"H\",\n        \"hB\"\n      ],\n      \"RO\": [\n        \"H\",\n        \"hB\"\n      ],\n      \"RS\": [\n        \"H\",\n        \"hB\",\n        \"h\"\n      ],\n      \"RU\": [\n        \"H\"\n      ],\n      \"SA\": [\n        \"h\",\n        \"hB\",\n        \"hb\",\n        \"H\"\n      ],\n      \"SB\": [\n        \"h\",\n        \"hb\",\n        \"H\",\n        \"hB\"\n      ],\n      \"SC\": [\n        \"H\",\n        \"h\",\n        \"hB\"\n      ],\n      \"SD\": [\n        \"h\",\n        \"hB\",\n        \"hb\",\n        \"H\"\n      ],\n      \"SE\": [\n        \"H\"\n      ],\n      \"SG\": [\n        \"h\",\n        \"hb\",\n        \"H\",\n        \"hB\"\n      ],\n      \"SH\": [\n        \"H\",\n        \"h\",\n        \"hb\",\n        \"hB\"\n      ],\n      \"SI\": [\n        \"H\",\n        \"hB\"\n      ],\n      \"SJ\": [\n        \"H\"\n      ],\n      \"SK\": [\n        \"H\"\n      ],\n      \"SL\": [\n        \"h\",\n        \"hb\",\n        \"H\",\n        \"hB\"\n      ],\n      \"SM\": [\n        \"H\",\n        \"h\",\n        \"hB\"\n      ],\n      \"SN\": [\n        \"H\",\n        \"h\",\n        \"hB\"\n      ],\n      \"SO\": [\n        \"h\",\n        \"H\"\n      ],\n      \"SR\": [\n        \"H\",\n        \"hB\"\n      ],\n      \"SS\": [\n        \"h\",\n        \"hb\",\n        \"H\",\n        \"hB\"\n      ],\n      \"ST\": [\n        \"H\",\n        \"hB\"\n      ],\n      \"SV\": [\n        \"H\",\n        \"h\",\n        \"hB\",\n        \"hb\"\n      ],\n      \"SX\": [\n        \"H\",\n        \"h\",\n        \"hb\",\n        \"hB\"\n      ],\n      \"SY\": [\n        \"h\",\n        \"hB\",\n        \"hb\",\n        \"H\"\n      ],\n      \"SZ\": [\n        \"h\",\n        \"hb\",\n        \"H\",\n        \"hB\"\n      ],\n      \"TA\": [\n        \"H\",\n        \"h\",\n        \"hb\",\n        \"hB\"\n      ],\n      \"TC\": [\n        \"h\",\n        \"hb\",\n        \"H\",\n        \"hB\"\n      ],\n      \"TD\": [\n        \"h\",\n        \"H\",\n        \"hB\"\n      ],\n      \"TF\": [\n        \"H\",\n        \"h\",\n        \"hB\"\n      ],\n      \"TG\": [\n        \"H\",\n        \"hB\"\n      ],\n      \"TL\": [\n        \"H\",\n        \"hB\",\n        \"hb\",\n        \"h\"\n      ],\n      \"TN\": [\n        \"h\",\n        \"hB\",\n        \"hb\",\n        \"H\"\n      ],\n      \"TO\": [\n        \"h\",\n        \"H\"\n      ],\n      \"TR\": [\n        \"H\",\n        \"hB\"\n      ],\n      \"TT\": [\n        \"h\",\n        \"hb\",\n        \"H\",\n        \"hB\"\n      ],\n      \"TW\": [\n        \"hB\",\n        \"hb\",\n        \"h\",\n        \"H\"\n      ],\n      \"TZ\": [\n        \"hB\",\n        \"hb\",\n        \"H\",\n        \"h\"\n      ],\n      \"UA\": [\n        \"H\",\n        \"hB\",\n        \"h\"\n      ],\n      \"UG\": [\n        \"hB\",\n        \"hb\",\n        \"H\",\n        \"h\"\n      ],\n      \"UM\": [\n        \"h\",\n        \"hb\",\n        \"H\",\n        \"hB\"\n      ],\n      \"US\": [\n        \"h\",\n        \"hb\",\n        \"H\",\n        \"hB\"\n      ],\n      \"UY\": [\n        \"H\",\n        \"h\",\n        \"hB\",\n        \"hb\"\n      ],\n      \"UZ\": [\n        \"H\",\n        \"hB\",\n        \"h\"\n      ],\n      \"VA\": [\n        \"H\",\n        \"h\",\n        \"hB\"\n      ],\n      \"VC\": [\n        \"h\",\n        \"hb\",\n        \"H\",\n        \"hB\"\n      ],\n      \"VE\": [\n        \"h\",\n        \"H\",\n        \"hB\",\n        \"hb\"\n      ],\n      \"VG\": [\n        \"h\",\n        \"hb\",\n        \"H\",\n        \"hB\"\n      ],\n      \"VI\": [\n        \"h\",\n        \"hb\",\n        \"H\",\n        \"hB\"\n      ],\n      \"VU\": [\n        \"h\",\n        \"H\"\n      ],\n      \"WF\": [\n        \"H\",\n        \"hB\"\n      ],\n      \"WS\": [\n        \"h\",\n        \"H\"\n      ],\n      \"XK\": [\n        \"H\",\n        \"hB\",\n        \"h\"\n      ],\n      \"YE\": [\n        \"h\",\n        \"hB\",\n        \"hb\",\n        \"H\"\n      ],\n      \"YT\": [\n        \"H\",\n        \"hB\"\n      ],\n      \"ZA\": [\n        \"H\",\n        \"h\",\n        \"hb\",\n        \"hB\"\n      ],\n      \"ZM\": [\n        \"h\",\n        \"hb\",\n        \"H\",\n        \"hB\"\n      ],\n      \"af-ZA\": [\n        \"H\",\n        \"h\",\n        \"hB\",\n        \"hb\"\n      ],\n      \"ar-001\": [\n        \"h\",\n        \"hB\",\n        \"hb\",\n        \"H\"\n      ],\n      \"ca-ES\": [\n        \"H\",\n        \"h\",\n        \"hB\"\n      ],\n      \"en-001\": [\n        \"h\",\n        \"hb\",\n        \"H\",\n        \"hB\"\n      ],\n      \"es-BO\": [\n        \"H\",\n        \"h\",\n        \"hB\",\n        \"hb\"\n      ],\n      \"es-BR\": [\n        \"H\",\n        \"h\",\n        \"hB\",\n        \"hb\"\n      ],\n      \"es-EC\": [\n        \"H\",\n        \"h\",\n        \"hB\",\n        \"hb\"\n      ],\n      \"es-ES\": [\n        \"H\",\n        \"h\",\n        \"hB\",\n        \"hb\"\n      ],\n      \"es-GQ\": [\n        \"H\",\n        \"h\",\n        \"hB\",\n        \"hb\"\n      ],\n      \"es-PE\": [\n        \"H\",\n        \"h\",\n        \"hB\",\n        \"hb\"\n      ],\n      \"fr-CA\": [\n        \"H\",\n        \"h\",\n        \"hB\"\n      ],\n      \"gl-ES\": [\n        \"H\",\n        \"h\",\n        \"hB\"\n      ],\n      \"gu-IN\": [\n        \"hB\",\n        \"hb\",\n        \"h\",\n        \"H\"\n      ],\n      \"hi-IN\": [\n        \"hB\",\n        \"h\",\n        \"H\"\n      ],\n      \"it-CH\": [\n        \"H\",\n        \"h\",\n        \"hB\"\n      ],\n      \"it-IT\": [\n        \"H\",\n        \"h\",\n        \"hB\"\n      ],\n      \"kn-IN\": [\n        \"hB\",\n        \"h\",\n        \"H\"\n      ],\n      \"ml-IN\": [\n        \"hB\",\n        \"h\",\n        \"H\"\n      ],\n      \"mr-IN\": [\n        \"hB\",\n        \"hb\",\n        \"h\",\n        \"H\"\n      ],\n      \"pa-IN\": [\n        \"hB\",\n        \"hb\",\n        \"h\",\n        \"H\"\n      ],\n      \"ta-IN\": [\n        \"hB\",\n        \"h\",\n        \"hb\",\n        \"H\"\n      ],\n      \"te-IN\": [\n        \"hB\",\n        \"h\",\n        \"H\"\n      ],\n      \"zu-ZA\": [\n        \"H\",\n        \"hB\",\n        \"hb\",\n        \"h\"\n      ]\n    };\n  }\n});\n\n// node_modules/@formatjs/icu-messageformat-parser/date-time-pattern-generator.js\nvar require_date_time_pattern_generator = __commonJS({\n  \"node_modules/@formatjs/icu-messageformat-parser/date-time-pattern-generator.js\"(exports2) {\n    \"use strict\";\n    init_process_global();\n    Object.defineProperty(exports2, \"__esModule\", { value: true });\n    exports2.getBestPattern = void 0;\n    var time_data_generated_1 = require_time_data_generated();\n    function getBestPattern(skeleton, locale) {\n      var skeletonCopy = \"\";\n      for (var patternPos = 0; patternPos < skeleton.length; patternPos++) {\n        var patternChar = skeleton.charAt(patternPos);\n        if (patternChar === \"j\") {\n          var extraLength = 0;\n          while (patternPos + 1 < skeleton.length && skeleton.charAt(patternPos + 1) === patternChar) {\n            extraLength++;\n            patternPos++;\n          }\n          var hourLen = 1 + (extraLength & 1);\n          var dayPeriodLen = extraLength < 2 ? 1 : 3 + (extraLength >> 1);\n          var dayPeriodChar = \"a\";\n          var hourChar = getDefaultHourSymbolFromLocale(locale);\n          if (hourChar == \"H\" || hourChar == \"k\") {\n            dayPeriodLen = 0;\n          }\n          while (dayPeriodLen-- > 0) {\n            skeletonCopy += dayPeriodChar;\n          }\n          while (hourLen-- > 0) {\n            skeletonCopy = hourChar + skeletonCopy;\n          }\n        } else if (patternChar === \"J\") {\n          skeletonCopy += \"H\";\n        } else {\n          skeletonCopy += patternChar;\n        }\n      }\n      return skeletonCopy;\n    }\n    __name(getBestPattern, \"getBestPattern\");\n    exports2.getBestPattern = getBestPattern;\n    function getDefaultHourSymbolFromLocale(locale) {\n      var hourCycle = locale.hourCycle;\n      if (hourCycle === void 0 && // @ts-ignore hourCycle(s) is not identified yet\n      locale.hourCycles && // @ts-ignore\n      locale.hourCycles.length) {\n        hourCycle = locale.hourCycles[0];\n      }\n      if (hourCycle) {\n        switch (hourCycle) {\n          case \"h24\":\n            return \"k\";\n          case \"h23\":\n            return \"H\";\n          case \"h12\":\n            return \"h\";\n          case \"h11\":\n            return \"K\";\n          default:\n            throw new Error(\"Invalid hourCycle\");\n        }\n      }\n      var languageTag = locale.language;\n      var regionTag;\n      if (languageTag !== \"root\") {\n        regionTag = locale.maximize().region;\n      }\n      var hourCycles = time_data_generated_1.timeData[regionTag || \"\"] || time_data_generated_1.timeData[languageTag || \"\"] || time_data_generated_1.timeData[\"\".concat(languageTag, \"-001\")] || time_data_generated_1.timeData[\"001\"];\n      return hourCycles[0];\n    }\n    __name(getDefaultHourSymbolFromLocale, \"getDefaultHourSymbolFromLocale\");\n  }\n});\n\n// node_modules/@formatjs/icu-messageformat-parser/parser.js\nvar require_parser = __commonJS({\n  \"node_modules/@formatjs/icu-messageformat-parser/parser.js\"(exports2) {\n    \"use strict\";\n    init_process_global();\n    var _a3;\n    Object.defineProperty(exports2, \"__esModule\", { value: true });\n    exports2.Parser = void 0;\n    var tslib_1 = (init_tslib_es62(), __toCommonJS(tslib_es6_exports2));\n    var error_1 = require_error();\n    var types_1 = require_types();\n    var regex_generated_1 = require_regex_generated();\n    var icu_skeleton_parser_1 = require_icu_skeleton_parser();\n    var date_time_pattern_generator_1 = require_date_time_pattern_generator();\n    var SPACE_SEPARATOR_START_REGEX = new RegExp(\"^\".concat(regex_generated_1.SPACE_SEPARATOR_REGEX.source, \"*\"));\n    var SPACE_SEPARATOR_END_REGEX = new RegExp(\"\".concat(regex_generated_1.SPACE_SEPARATOR_REGEX.source, \"*$\"));\n    function createLocation(start, end) {\n      return { start, end };\n    }\n    __name(createLocation, \"createLocation\");\n    var hasNativeStartsWith = !!String.prototype.startsWith && \"_a\".startsWith(\"a\", 1);\n    var hasNativeFromCodePoint = !!String.fromCodePoint;\n    var hasNativeFromEntries = !!Object.fromEntries;\n    var hasNativeCodePointAt = !!String.prototype.codePointAt;\n    var hasTrimStart = !!String.prototype.trimStart;\n    var hasTrimEnd = !!String.prototype.trimEnd;\n    var hasNativeIsSafeInteger = !!Number.isSafeInteger;\n    var isSafeInteger = hasNativeIsSafeInteger ? Number.isSafeInteger : function(n) {\n      return typeof n === \"number\" && isFinite(n) && Math.floor(n) === n && Math.abs(n) <= 9007199254740991;\n    };\n    var REGEX_SUPPORTS_U_AND_Y = true;\n    try {\n      re = RE(\"([^\\\\p{White_Space}\\\\p{Pattern_Syntax}]*)\", \"yu\");\n      REGEX_SUPPORTS_U_AND_Y = ((_a3 = re.exec(\"a\")) === null || _a3 === void 0 ? void 0 : _a3[0]) === \"a\";\n    } catch (_) {\n      REGEX_SUPPORTS_U_AND_Y = false;\n    }\n    var re;\n    var startsWith = hasNativeStartsWith ? (\n      // Native\n      /* @__PURE__ */ __name(function startsWith2(s, search, position) {\n        return s.startsWith(search, position);\n      }, \"startsWith\")\n    ) : (\n      // For IE11\n      /* @__PURE__ */ __name(function startsWith2(s, search, position) {\n        return s.slice(position, position + search.length) === search;\n      }, \"startsWith\")\n    );\n    var fromCodePoint = hasNativeFromCodePoint ? String.fromCodePoint : (\n      // IE11\n      /* @__PURE__ */ __name(function fromCodePoint2() {\n        var codePoints = [];\n        for (var _i = 0; _i < arguments.length; _i++) {\n          codePoints[_i] = arguments[_i];\n        }\n        var elements = \"\";\n        var length = codePoints.length;\n        var i = 0;\n        var code;\n        while (length > i) {\n          code = codePoints[i++];\n          if (code > 1114111)\n            throw RangeError(code + \" is not a valid code point\");\n          elements += code < 65536 ? String.fromCharCode(code) : String.fromCharCode(((code -= 65536) >> 10) + 55296, code % 1024 + 56320);\n        }\n        return elements;\n      }, \"fromCodePoint\")\n    );\n    var fromEntries = (\n      // native\n      hasNativeFromEntries ? Object.fromEntries : (\n        // Ponyfill\n        /* @__PURE__ */ __name(function fromEntries2(entries) {\n          var obj = {};\n          for (var _i = 0, entries_1 = entries; _i < entries_1.length; _i++) {\n            var _a4 = entries_1[_i], k = _a4[0], v = _a4[1];\n            obj[k] = v;\n          }\n          return obj;\n        }, \"fromEntries\")\n      )\n    );\n    var codePointAt = hasNativeCodePointAt ? (\n      // Native\n      /* @__PURE__ */ __name(function codePointAt2(s, index) {\n        return s.codePointAt(index);\n      }, \"codePointAt\")\n    ) : (\n      // IE 11\n      /* @__PURE__ */ __name(function codePointAt2(s, index) {\n        var size = s.length;\n        if (index < 0 || index >= size) {\n          return void 0;\n        }\n        var first = s.charCodeAt(index);\n        var second;\n        return first < 55296 || first > 56319 || index + 1 === size || (second = s.charCodeAt(index + 1)) < 56320 || second > 57343 ? first : (first - 55296 << 10) + (second - 56320) + 65536;\n      }, \"codePointAt\")\n    );\n    var trimStart = hasTrimStart ? (\n      // Native\n      /* @__PURE__ */ __name(function trimStart2(s) {\n        return s.trimStart();\n      }, \"trimStart\")\n    ) : (\n      // Ponyfill\n      /* @__PURE__ */ __name(function trimStart2(s) {\n        return s.replace(SPACE_SEPARATOR_START_REGEX, \"\");\n      }, \"trimStart\")\n    );\n    var trimEnd = hasTrimEnd ? (\n      // Native\n      /* @__PURE__ */ __name(function trimEnd2(s) {\n        return s.trimEnd();\n      }, \"trimEnd\")\n    ) : (\n      // Ponyfill\n      /* @__PURE__ */ __name(function trimEnd2(s) {\n        return s.replace(SPACE_SEPARATOR_END_REGEX, \"\");\n      }, \"trimEnd\")\n    );\n    function RE(s, flag) {\n      return new RegExp(s, flag);\n    }\n    __name(RE, \"RE\");\n    var matchIdentifierAtIndex;\n    if (REGEX_SUPPORTS_U_AND_Y) {\n      IDENTIFIER_PREFIX_RE_1 = RE(\"([^\\\\p{White_Space}\\\\p{Pattern_Syntax}]*)\", \"yu\");\n      matchIdentifierAtIndex = /* @__PURE__ */ __name(function matchIdentifierAtIndex2(s, index) {\n        var _a4;\n        IDENTIFIER_PREFIX_RE_1.lastIndex = index;\n        var match = IDENTIFIER_PREFIX_RE_1.exec(s);\n        return (_a4 = match[1]) !== null && _a4 !== void 0 ? _a4 : \"\";\n      }, \"matchIdentifierAtIndex\");\n    } else {\n      matchIdentifierAtIndex = /* @__PURE__ */ __name(function matchIdentifierAtIndex2(s, index) {\n        var match = [];\n        while (true) {\n          var c = codePointAt(s, index);\n          if (c === void 0 || _isWhiteSpace(c) || _isPatternSyntax(c)) {\n            break;\n          }\n          match.push(c);\n          index += c >= 65536 ? 2 : 1;\n        }\n        return fromCodePoint.apply(void 0, match);\n      }, \"matchIdentifierAtIndex\");\n    }\n    var IDENTIFIER_PREFIX_RE_1;\n    var Parser = (\n      /** @class */\n      (function() {\n        function Parser2(message, options) {\n          if (options === void 0) {\n            options = {};\n          }\n          this.message = message;\n          this.position = { offset: 0, line: 1, column: 1 };\n          this.ignoreTag = !!options.ignoreTag;\n          this.locale = options.locale;\n          this.requiresOtherClause = !!options.requiresOtherClause;\n          this.shouldParseSkeletons = !!options.shouldParseSkeletons;\n        }\n        __name(Parser2, \"Parser\");\n        Parser2.prototype.parse = function() {\n          if (this.offset() !== 0) {\n            throw Error(\"parser can only be used once\");\n          }\n          return this.parseMessage(0, \"\", false);\n        };\n        Parser2.prototype.parseMessage = function(nestingLevel, parentArgType, expectingCloseTag) {\n          var elements = [];\n          while (!this.isEOF()) {\n            var char = this.char();\n            if (char === 123) {\n              var result = this.parseArgument(nestingLevel, expectingCloseTag);\n              if (result.err) {\n                return result;\n              }\n              elements.push(result.val);\n            } else if (char === 125 && nestingLevel > 0) {\n              break;\n            } else if (char === 35 && (parentArgType === \"plural\" || parentArgType === \"selectordinal\")) {\n              var position = this.clonePosition();\n              this.bump();\n              elements.push({\n                type: types_1.TYPE.pound,\n                location: createLocation(position, this.clonePosition())\n              });\n            } else if (char === 60 && !this.ignoreTag && this.peek() === 47) {\n              if (expectingCloseTag) {\n                break;\n              } else {\n                return this.error(error_1.ErrorKind.UNMATCHED_CLOSING_TAG, createLocation(this.clonePosition(), this.clonePosition()));\n              }\n            } else if (char === 60 && !this.ignoreTag && _isAlpha(this.peek() || 0)) {\n              var result = this.parseTag(nestingLevel, parentArgType);\n              if (result.err) {\n                return result;\n              }\n              elements.push(result.val);\n            } else {\n              var result = this.parseLiteral(nestingLevel, parentArgType);\n              if (result.err) {\n                return result;\n              }\n              elements.push(result.val);\n            }\n          }\n          return { val: elements, err: null };\n        };\n        Parser2.prototype.parseTag = function(nestingLevel, parentArgType) {\n          var startPosition = this.clonePosition();\n          this.bump();\n          var tagName = this.parseTagName();\n          this.bumpSpace();\n          if (this.bumpIf(\"/>\")) {\n            return {\n              val: {\n                type: types_1.TYPE.literal,\n                value: \"<\".concat(tagName, \"/>\"),\n                location: createLocation(startPosition, this.clonePosition())\n              },\n              err: null\n            };\n          } else if (this.bumpIf(\">\")) {\n            var childrenResult = this.parseMessage(nestingLevel + 1, parentArgType, true);\n            if (childrenResult.err) {\n              return childrenResult;\n            }\n            var children = childrenResult.val;\n            var endTagStartPosition = this.clonePosition();\n            if (this.bumpIf(\"</\")) {\n              if (this.isEOF() || !_isAlpha(this.char())) {\n                return this.error(error_1.ErrorKind.INVALID_TAG, createLocation(endTagStartPosition, this.clonePosition()));\n              }\n              var closingTagNameStartPosition = this.clonePosition();\n              var closingTagName = this.parseTagName();\n              if (tagName !== closingTagName) {\n                return this.error(error_1.ErrorKind.UNMATCHED_CLOSING_TAG, createLocation(closingTagNameStartPosition, this.clonePosition()));\n              }\n              this.bumpSpace();\n              if (!this.bumpIf(\">\")) {\n                return this.error(error_1.ErrorKind.INVALID_TAG, createLocation(endTagStartPosition, this.clonePosition()));\n              }\n              return {\n                val: {\n                  type: types_1.TYPE.tag,\n                  value: tagName,\n                  children,\n                  location: createLocation(startPosition, this.clonePosition())\n                },\n                err: null\n              };\n            } else {\n              return this.error(error_1.ErrorKind.UNCLOSED_TAG, createLocation(startPosition, this.clonePosition()));\n            }\n          } else {\n            return this.error(error_1.ErrorKind.INVALID_TAG, createLocation(startPosition, this.clonePosition()));\n          }\n        };\n        Parser2.prototype.parseTagName = function() {\n          var startOffset = this.offset();\n          this.bump();\n          while (!this.isEOF() && _isPotentialElementNameChar(this.char())) {\n            this.bump();\n          }\n          return this.message.slice(startOffset, this.offset());\n        };\n        Parser2.prototype.parseLiteral = function(nestingLevel, parentArgType) {\n          var start = this.clonePosition();\n          var value = \"\";\n          while (true) {\n            var parseQuoteResult = this.tryParseQuote(parentArgType);\n            if (parseQuoteResult) {\n              value += parseQuoteResult;\n              continue;\n            }\n            var parseUnquotedResult = this.tryParseUnquoted(nestingLevel, parentArgType);\n            if (parseUnquotedResult) {\n              value += parseUnquotedResult;\n              continue;\n            }\n            var parseLeftAngleResult = this.tryParseLeftAngleBracket();\n            if (parseLeftAngleResult) {\n              value += parseLeftAngleResult;\n              continue;\n            }\n            break;\n          }\n          var location = createLocation(start, this.clonePosition());\n          return {\n            val: { type: types_1.TYPE.literal, value, location },\n            err: null\n          };\n        };\n        Parser2.prototype.tryParseLeftAngleBracket = function() {\n          if (!this.isEOF() && this.char() === 60 && (this.ignoreTag || // If at the opening tag or closing tag position, bail.\n          !_isAlphaOrSlash(this.peek() || 0))) {\n            this.bump();\n            return \"<\";\n          }\n          return null;\n        };\n        Parser2.prototype.tryParseQuote = function(parentArgType) {\n          if (this.isEOF() || this.char() !== 39) {\n            return null;\n          }\n          switch (this.peek()) {\n            case 39:\n              this.bump();\n              this.bump();\n              return \"'\";\n            // '{', '<', '>', '}'\n            case 123:\n            case 60:\n            case 62:\n            case 125:\n              break;\n            case 35:\n              if (parentArgType === \"plural\" || parentArgType === \"selectordinal\") {\n                break;\n              }\n              return null;\n            default:\n              return null;\n          }\n          this.bump();\n          var codePoints = [this.char()];\n          this.bump();\n          while (!this.isEOF()) {\n            var ch = this.char();\n            if (ch === 39) {\n              if (this.peek() === 39) {\n                codePoints.push(39);\n                this.bump();\n              } else {\n                this.bump();\n                break;\n              }\n            } else {\n              codePoints.push(ch);\n            }\n            this.bump();\n          }\n          return fromCodePoint.apply(void 0, codePoints);\n        };\n        Parser2.prototype.tryParseUnquoted = function(nestingLevel, parentArgType) {\n          if (this.isEOF()) {\n            return null;\n          }\n          var ch = this.char();\n          if (ch === 60 || ch === 123 || ch === 35 && (parentArgType === \"plural\" || parentArgType === \"selectordinal\") || ch === 125 && nestingLevel > 0) {\n            return null;\n          } else {\n            this.bump();\n            return fromCodePoint(ch);\n          }\n        };\n        Parser2.prototype.parseArgument = function(nestingLevel, expectingCloseTag) {\n          var openingBracePosition = this.clonePosition();\n          this.bump();\n          this.bumpSpace();\n          if (this.isEOF()) {\n            return this.error(error_1.ErrorKind.EXPECT_ARGUMENT_CLOSING_BRACE, createLocation(openingBracePosition, this.clonePosition()));\n          }\n          if (this.char() === 125) {\n            this.bump();\n            return this.error(error_1.ErrorKind.EMPTY_ARGUMENT, createLocation(openingBracePosition, this.clonePosition()));\n          }\n          var value = this.parseIdentifierIfPossible().value;\n          if (!value) {\n            return this.error(error_1.ErrorKind.MALFORMED_ARGUMENT, createLocation(openingBracePosition, this.clonePosition()));\n          }\n          this.bumpSpace();\n          if (this.isEOF()) {\n            return this.error(error_1.ErrorKind.EXPECT_ARGUMENT_CLOSING_BRACE, createLocation(openingBracePosition, this.clonePosition()));\n          }\n          switch (this.char()) {\n            // Simple argument: `{name}`\n            case 125: {\n              this.bump();\n              return {\n                val: {\n                  type: types_1.TYPE.argument,\n                  // value does not include the opening and closing braces.\n                  value,\n                  location: createLocation(openingBracePosition, this.clonePosition())\n                },\n                err: null\n              };\n            }\n            // Argument with options: `{name, format, ...}`\n            case 44: {\n              this.bump();\n              this.bumpSpace();\n              if (this.isEOF()) {\n                return this.error(error_1.ErrorKind.EXPECT_ARGUMENT_CLOSING_BRACE, createLocation(openingBracePosition, this.clonePosition()));\n              }\n              return this.parseArgumentOptions(nestingLevel, expectingCloseTag, value, openingBracePosition);\n            }\n            default:\n              return this.error(error_1.ErrorKind.MALFORMED_ARGUMENT, createLocation(openingBracePosition, this.clonePosition()));\n          }\n        };\n        Parser2.prototype.parseIdentifierIfPossible = function() {\n          var startingPosition = this.clonePosition();\n          var startOffset = this.offset();\n          var value = matchIdentifierAtIndex(this.message, startOffset);\n          var endOffset = startOffset + value.length;\n          this.bumpTo(endOffset);\n          var endPosition = this.clonePosition();\n          var location = createLocation(startingPosition, endPosition);\n          return { value, location };\n        };\n        Parser2.prototype.parseArgumentOptions = function(nestingLevel, expectingCloseTag, value, openingBracePosition) {\n          var _a4;\n          var typeStartPosition = this.clonePosition();\n          var argType = this.parseIdentifierIfPossible().value;\n          var typeEndPosition = this.clonePosition();\n          switch (argType) {\n            case \"\":\n              return this.error(error_1.ErrorKind.EXPECT_ARGUMENT_TYPE, createLocation(typeStartPosition, typeEndPosition));\n            case \"number\":\n            case \"date\":\n            case \"time\": {\n              this.bumpSpace();\n              var styleAndLocation = null;\n              if (this.bumpIf(\",\")) {\n                this.bumpSpace();\n                var styleStartPosition = this.clonePosition();\n                var result = this.parseSimpleArgStyleIfPossible();\n                if (result.err) {\n                  return result;\n                }\n                var style = trimEnd(result.val);\n                if (style.length === 0) {\n                  return this.error(error_1.ErrorKind.EXPECT_ARGUMENT_STYLE, createLocation(this.clonePosition(), this.clonePosition()));\n                }\n                var styleLocation = createLocation(styleStartPosition, this.clonePosition());\n                styleAndLocation = { style, styleLocation };\n              }\n              var argCloseResult = this.tryParseArgumentClose(openingBracePosition);\n              if (argCloseResult.err) {\n                return argCloseResult;\n              }\n              var location_1 = createLocation(openingBracePosition, this.clonePosition());\n              if (styleAndLocation && startsWith(styleAndLocation === null || styleAndLocation === void 0 ? void 0 : styleAndLocation.style, \"::\", 0)) {\n                var skeleton = trimStart(styleAndLocation.style.slice(2));\n                if (argType === \"number\") {\n                  var result = this.parseNumberSkeletonFromString(skeleton, styleAndLocation.styleLocation);\n                  if (result.err) {\n                    return result;\n                  }\n                  return {\n                    val: { type: types_1.TYPE.number, value, location: location_1, style: result.val },\n                    err: null\n                  };\n                } else {\n                  if (skeleton.length === 0) {\n                    return this.error(error_1.ErrorKind.EXPECT_DATE_TIME_SKELETON, location_1);\n                  }\n                  var dateTimePattern = skeleton;\n                  if (this.locale) {\n                    dateTimePattern = (0, date_time_pattern_generator_1.getBestPattern)(skeleton, this.locale);\n                  }\n                  var style = {\n                    type: types_1.SKELETON_TYPE.dateTime,\n                    pattern: dateTimePattern,\n                    location: styleAndLocation.styleLocation,\n                    parsedOptions: this.shouldParseSkeletons ? (0, icu_skeleton_parser_1.parseDateTimeSkeleton)(dateTimePattern) : {}\n                  };\n                  var type = argType === \"date\" ? types_1.TYPE.date : types_1.TYPE.time;\n                  return {\n                    val: { type, value, location: location_1, style },\n                    err: null\n                  };\n                }\n              }\n              return {\n                val: {\n                  type: argType === \"number\" ? types_1.TYPE.number : argType === \"date\" ? types_1.TYPE.date : types_1.TYPE.time,\n                  value,\n                  location: location_1,\n                  style: (_a4 = styleAndLocation === null || styleAndLocation === void 0 ? void 0 : styleAndLocation.style) !== null && _a4 !== void 0 ? _a4 : null\n                },\n                err: null\n              };\n            }\n            case \"plural\":\n            case \"selectordinal\":\n            case \"select\": {\n              var typeEndPosition_1 = this.clonePosition();\n              this.bumpSpace();\n              if (!this.bumpIf(\",\")) {\n                return this.error(error_1.ErrorKind.EXPECT_SELECT_ARGUMENT_OPTIONS, createLocation(typeEndPosition_1, tslib_1.__assign({}, typeEndPosition_1)));\n              }\n              this.bumpSpace();\n              var identifierAndLocation = this.parseIdentifierIfPossible();\n              var pluralOffset = 0;\n              if (argType !== \"select\" && identifierAndLocation.value === \"offset\") {\n                if (!this.bumpIf(\":\")) {\n                  return this.error(error_1.ErrorKind.EXPECT_PLURAL_ARGUMENT_OFFSET_VALUE, createLocation(this.clonePosition(), this.clonePosition()));\n                }\n                this.bumpSpace();\n                var result = this.tryParseDecimalInteger(error_1.ErrorKind.EXPECT_PLURAL_ARGUMENT_OFFSET_VALUE, error_1.ErrorKind.INVALID_PLURAL_ARGUMENT_OFFSET_VALUE);\n                if (result.err) {\n                  return result;\n                }\n                this.bumpSpace();\n                identifierAndLocation = this.parseIdentifierIfPossible();\n                pluralOffset = result.val;\n              }\n              var optionsResult = this.tryParsePluralOrSelectOptions(nestingLevel, argType, expectingCloseTag, identifierAndLocation);\n              if (optionsResult.err) {\n                return optionsResult;\n              }\n              var argCloseResult = this.tryParseArgumentClose(openingBracePosition);\n              if (argCloseResult.err) {\n                return argCloseResult;\n              }\n              var location_2 = createLocation(openingBracePosition, this.clonePosition());\n              if (argType === \"select\") {\n                return {\n                  val: {\n                    type: types_1.TYPE.select,\n                    value,\n                    options: fromEntries(optionsResult.val),\n                    location: location_2\n                  },\n                  err: null\n                };\n              } else {\n                return {\n                  val: {\n                    type: types_1.TYPE.plural,\n                    value,\n                    options: fromEntries(optionsResult.val),\n                    offset: pluralOffset,\n                    pluralType: argType === \"plural\" ? \"cardinal\" : \"ordinal\",\n                    location: location_2\n                  },\n                  err: null\n                };\n              }\n            }\n            default:\n              return this.error(error_1.ErrorKind.INVALID_ARGUMENT_TYPE, createLocation(typeStartPosition, typeEndPosition));\n          }\n        };\n        Parser2.prototype.tryParseArgumentClose = function(openingBracePosition) {\n          if (this.isEOF() || this.char() !== 125) {\n            return this.error(error_1.ErrorKind.EXPECT_ARGUMENT_CLOSING_BRACE, createLocation(openingBracePosition, this.clonePosition()));\n          }\n          this.bump();\n          return { val: true, err: null };\n        };\n        Parser2.prototype.parseSimpleArgStyleIfPossible = function() {\n          var nestedBraces = 0;\n          var startPosition = this.clonePosition();\n          while (!this.isEOF()) {\n            var ch = this.char();\n            switch (ch) {\n              case 39: {\n                this.bump();\n                var apostrophePosition = this.clonePosition();\n                if (!this.bumpUntil(\"'\")) {\n                  return this.error(error_1.ErrorKind.UNCLOSED_QUOTE_IN_ARGUMENT_STYLE, createLocation(apostrophePosition, this.clonePosition()));\n                }\n                this.bump();\n                break;\n              }\n              case 123: {\n                nestedBraces += 1;\n                this.bump();\n                break;\n              }\n              case 125: {\n                if (nestedBraces > 0) {\n                  nestedBraces -= 1;\n                } else {\n                  return {\n                    val: this.message.slice(startPosition.offset, this.offset()),\n                    err: null\n                  };\n                }\n                break;\n              }\n              default:\n                this.bump();\n                break;\n            }\n          }\n          return {\n            val: this.message.slice(startPosition.offset, this.offset()),\n            err: null\n          };\n        };\n        Parser2.prototype.parseNumberSkeletonFromString = function(skeleton, location) {\n          var tokens = [];\n          try {\n            tokens = (0, icu_skeleton_parser_1.parseNumberSkeletonFromString)(skeleton);\n          } catch (e) {\n            return this.error(error_1.ErrorKind.INVALID_NUMBER_SKELETON, location);\n          }\n          return {\n            val: {\n              type: types_1.SKELETON_TYPE.number,\n              tokens,\n              location,\n              parsedOptions: this.shouldParseSkeletons ? (0, icu_skeleton_parser_1.parseNumberSkeleton)(tokens) : {}\n            },\n            err: null\n          };\n        };\n        Parser2.prototype.tryParsePluralOrSelectOptions = function(nestingLevel, parentArgType, expectCloseTag, parsedFirstIdentifier) {\n          var _a4;\n          var hasOtherClause = false;\n          var options = [];\n          var parsedSelectors = /* @__PURE__ */ new Set();\n          var selector = parsedFirstIdentifier.value, selectorLocation = parsedFirstIdentifier.location;\n          while (true) {\n            if (selector.length === 0) {\n              var startPosition = this.clonePosition();\n              if (parentArgType !== \"select\" && this.bumpIf(\"=\")) {\n                var result = this.tryParseDecimalInteger(error_1.ErrorKind.EXPECT_PLURAL_ARGUMENT_SELECTOR, error_1.ErrorKind.INVALID_PLURAL_ARGUMENT_SELECTOR);\n                if (result.err) {\n                  return result;\n                }\n                selectorLocation = createLocation(startPosition, this.clonePosition());\n                selector = this.message.slice(startPosition.offset, this.offset());\n              } else {\n                break;\n              }\n            }\n            if (parsedSelectors.has(selector)) {\n              return this.error(parentArgType === \"select\" ? error_1.ErrorKind.DUPLICATE_SELECT_ARGUMENT_SELECTOR : error_1.ErrorKind.DUPLICATE_PLURAL_ARGUMENT_SELECTOR, selectorLocation);\n            }\n            if (selector === \"other\") {\n              hasOtherClause = true;\n            }\n            this.bumpSpace();\n            var openingBracePosition = this.clonePosition();\n            if (!this.bumpIf(\"{\")) {\n              return this.error(parentArgType === \"select\" ? error_1.ErrorKind.EXPECT_SELECT_ARGUMENT_SELECTOR_FRAGMENT : error_1.ErrorKind.EXPECT_PLURAL_ARGUMENT_SELECTOR_FRAGMENT, createLocation(this.clonePosition(), this.clonePosition()));\n            }\n            var fragmentResult = this.parseMessage(nestingLevel + 1, parentArgType, expectCloseTag);\n            if (fragmentResult.err) {\n              return fragmentResult;\n            }\n            var argCloseResult = this.tryParseArgumentClose(openingBracePosition);\n            if (argCloseResult.err) {\n              return argCloseResult;\n            }\n            options.push([\n              selector,\n              {\n                value: fragmentResult.val,\n                location: createLocation(openingBracePosition, this.clonePosition())\n              }\n            ]);\n            parsedSelectors.add(selector);\n            this.bumpSpace();\n            _a4 = this.parseIdentifierIfPossible(), selector = _a4.value, selectorLocation = _a4.location;\n          }\n          if (options.length === 0) {\n            return this.error(parentArgType === \"select\" ? error_1.ErrorKind.EXPECT_SELECT_ARGUMENT_SELECTOR : error_1.ErrorKind.EXPECT_PLURAL_ARGUMENT_SELECTOR, createLocation(this.clonePosition(), this.clonePosition()));\n          }\n          if (this.requiresOtherClause && !hasOtherClause) {\n            return this.error(error_1.ErrorKind.MISSING_OTHER_CLAUSE, createLocation(this.clonePosition(), this.clonePosition()));\n          }\n          return { val: options, err: null };\n        };\n        Parser2.prototype.tryParseDecimalInteger = function(expectNumberError, invalidNumberError) {\n          var sign = 1;\n          var startingPosition = this.clonePosition();\n          if (this.bumpIf(\"+\")) {\n          } else if (this.bumpIf(\"-\")) {\n            sign = -1;\n          }\n          var hasDigits = false;\n          var decimal = 0;\n          while (!this.isEOF()) {\n            var ch = this.char();\n            if (ch >= 48 && ch <= 57) {\n              hasDigits = true;\n              decimal = decimal * 10 + (ch - 48);\n              this.bump();\n            } else {\n              break;\n            }\n          }\n          var location = createLocation(startingPosition, this.clonePosition());\n          if (!hasDigits) {\n            return this.error(expectNumberError, location);\n          }\n          decimal *= sign;\n          if (!isSafeInteger(decimal)) {\n            return this.error(invalidNumberError, location);\n          }\n          return { val: decimal, err: null };\n        };\n        Parser2.prototype.offset = function() {\n          return this.position.offset;\n        };\n        Parser2.prototype.isEOF = function() {\n          return this.offset() === this.message.length;\n        };\n        Parser2.prototype.clonePosition = function() {\n          return {\n            offset: this.position.offset,\n            line: this.position.line,\n            column: this.position.column\n          };\n        };\n        Parser2.prototype.char = function() {\n          var offset = this.position.offset;\n          if (offset >= this.message.length) {\n            throw Error(\"out of bound\");\n          }\n          var code = codePointAt(this.message, offset);\n          if (code === void 0) {\n            throw Error(\"Offset \".concat(offset, \" is at invalid UTF-16 code unit boundary\"));\n          }\n          return code;\n        };\n        Parser2.prototype.error = function(kind, location) {\n          return {\n            val: null,\n            err: {\n              kind,\n              message: this.message,\n              location\n            }\n          };\n        };\n        Parser2.prototype.bump = function() {\n          if (this.isEOF()) {\n            return;\n          }\n          var code = this.char();\n          if (code === 10) {\n            this.position.line += 1;\n            this.position.column = 1;\n            this.position.offset += 1;\n          } else {\n            this.position.column += 1;\n            this.position.offset += code < 65536 ? 1 : 2;\n          }\n        };\n        Parser2.prototype.bumpIf = function(prefix) {\n          if (startsWith(this.message, prefix, this.offset())) {\n            for (var i = 0; i < prefix.length; i++) {\n              this.bump();\n            }\n            return true;\n          }\n          return false;\n        };\n        Parser2.prototype.bumpUntil = function(pattern) {\n          var currentOffset = this.offset();\n          var index = this.message.indexOf(pattern, currentOffset);\n          if (index >= 0) {\n            this.bumpTo(index);\n            return true;\n          } else {\n            this.bumpTo(this.message.length);\n            return false;\n          }\n        };\n        Parser2.prototype.bumpTo = function(targetOffset) {\n          if (this.offset() > targetOffset) {\n            throw Error(\"targetOffset \".concat(targetOffset, \" must be greater than or equal to the current offset \").concat(this.offset()));\n          }\n          targetOffset = Math.min(targetOffset, this.message.length);\n          while (true) {\n            var offset = this.offset();\n            if (offset === targetOffset) {\n              break;\n            }\n            if (offset > targetOffset) {\n              throw Error(\"targetOffset \".concat(targetOffset, \" is at invalid UTF-16 code unit boundary\"));\n            }\n            this.bump();\n            if (this.isEOF()) {\n              break;\n            }\n          }\n        };\n        Parser2.prototype.bumpSpace = function() {\n          while (!this.isEOF() && _isWhiteSpace(this.char())) {\n            this.bump();\n          }\n        };\n        Parser2.prototype.peek = function() {\n          if (this.isEOF()) {\n            return null;\n          }\n          var code = this.char();\n          var offset = this.offset();\n          var nextCode = this.message.charCodeAt(offset + (code >= 65536 ? 2 : 1));\n          return nextCode !== null && nextCode !== void 0 ? nextCode : null;\n        };\n        return Parser2;\n      })()\n    );\n    exports2.Parser = Parser;\n    function _isAlpha(codepoint) {\n      return codepoint >= 97 && codepoint <= 122 || codepoint >= 65 && codepoint <= 90;\n    }\n    __name(_isAlpha, \"_isAlpha\");\n    function _isAlphaOrSlash(codepoint) {\n      return _isAlpha(codepoint) || codepoint === 47;\n    }\n    __name(_isAlphaOrSlash, \"_isAlphaOrSlash\");\n    function _isPotentialElementNameChar(c) {\n      return c === 45 || c === 46 || c >= 48 && c <= 57 || c === 95 || c >= 97 && c <= 122 || c >= 65 && c <= 90 || c == 183 || c >= 192 && c <= 214 || c >= 216 && c <= 246 || c >= 248 && c <= 893 || c >= 895 && c <= 8191 || c >= 8204 && c <= 8205 || c >= 8255 && c <= 8256 || c >= 8304 && c <= 8591 || c >= 11264 && c <= 12271 || c >= 12289 && c <= 55295 || c >= 63744 && c <= 64975 || c >= 65008 && c <= 65533 || c >= 65536 && c <= 983039;\n    }\n    __name(_isPotentialElementNameChar, \"_isPotentialElementNameChar\");\n    function _isWhiteSpace(c) {\n      return c >= 9 && c <= 13 || c === 32 || c === 133 || c >= 8206 && c <= 8207 || c === 8232 || c === 8233;\n    }\n    __name(_isWhiteSpace, \"_isWhiteSpace\");\n    function _isPatternSyntax(c) {\n      return c >= 33 && c <= 35 || c === 36 || c >= 37 && c <= 39 || c === 40 || c === 41 || c === 42 || c === 43 || c === 44 || c === 45 || c >= 46 && c <= 47 || c >= 58 && c <= 59 || c >= 60 && c <= 62 || c >= 63 && c <= 64 || c === 91 || c === 92 || c === 93 || c === 94 || c === 96 || c === 123 || c === 124 || c === 125 || c === 126 || c === 161 || c >= 162 && c <= 165 || c === 166 || c === 167 || c === 169 || c === 171 || c === 172 || c === 174 || c === 176 || c === 177 || c === 182 || c === 187 || c === 191 || c === 215 || c === 247 || c >= 8208 && c <= 8213 || c >= 8214 && c <= 8215 || c === 8216 || c === 8217 || c === 8218 || c >= 8219 && c <= 8220 || c === 8221 || c === 8222 || c === 8223 || c >= 8224 && c <= 8231 || c >= 8240 && c <= 8248 || c === 8249 || c === 8250 || c >= 8251 && c <= 8254 || c >= 8257 && c <= 8259 || c === 8260 || c === 8261 || c === 8262 || c >= 8263 && c <= 8273 || c === 8274 || c === 8275 || c >= 8277 && c <= 8286 || c >= 8592 && c <= 8596 || c >= 8597 &&\n      c <= 8601 || c >= 8602 && c <= 8603 || c >= 8604 && c <= 8607 || c === 8608 || c >= 8609 && c <= 8610 || c === 8611 || c >= 8612 && c <= 8613 || c === 8614 || c >= 8615 && c <= 8621 || c === 8622 || c >= 8623 && c <= 8653 || c >= 8654 && c <= 8655 || c >= 8656 && c <= 8657 || c === 8658 || c === 8659 || c === 8660 || c >= 8661 && c <= 8691 || c >= 8692 && c <= 8959 || c >= 8960 && c <= 8967 || c === 8968 || c === 8969 || c === 8970 || c === 8971 || c >= 8972 && c <= 8991 || c >= 8992 && c <= 8993 || c >= 8994 && c <= 9e3 || c === 9001 || c === 9002 || c >= 9003 && c <= 9083 || c === 9084 || c >= 9085 && c <= 9114 || c >= 9115 && c <= 9139 || c >= 9140 && c <= 9179 || c >= 9180 && c <= 9185 || c >= 9186 && c <= 9254 || c >= 9255 && c <= 9279 || c >= 9280 && c <= 9290 || c >= 9291 && c <= 9311 || c >= 9472 && c <= 9654 || c === 9655 || c >= 9656 && c <= 9664 || c === 9665 || c >= 9666 && c <= 9719 || c >= 9720 && c <= 9727 || c >= 9728 && c <= 9838 || c === 9839 || c >= 9840 && c <=\n      10087 || c === 10088 || c === 10089 || c === 10090 || c === 10091 || c === 10092 || c === 10093 || c === 10094 || c === 10095 || c === 10096 || c === 10097 || c === 10098 || c === 10099 || c === 10100 || c === 10101 || c >= 10132 && c <= 10175 || c >= 10176 && c <= 10180 || c === 10181 || c === 10182 || c >= 10183 && c <= 10213 || c === 10214 || c === 10215 || c === 10216 || c === 10217 || c === 10218 || c === 10219 || c === 10220 || c === 10221 || c === 10222 || c === 10223 || c >= 10224 && c <= 10239 || c >= 10240 && c <= 10495 || c >= 10496 && c <= 10626 || c === 10627 || c === 10628 || c === 10629 || c === 10630 || c === 10631 || c === 10632 || c === 10633 || c === 10634 || c === 10635 || c === 10636 || c === 10637 || c === 10638 || c === 10639 || c === 10640 || c === 10641 || c === 10642 || c === 10643 || c === 10644 || c === 10645 || c === 10646 || c === 10647 || c === 10648 || c >= 10649 && c <= 10711 || c === 10712 || c === 10713 || c === 10714 || c === 10715 || c >= 10716 &&\n      c <= 10747 || c === 10748 || c === 10749 || c >= 10750 && c <= 11007 || c >= 11008 && c <= 11055 || c >= 11056 && c <= 11076 || c >= 11077 && c <= 11078 || c >= 11079 && c <= 11084 || c >= 11085 && c <= 11123 || c >= 11124 && c <= 11125 || c >= 11126 && c <= 11157 || c === 11158 || c >= 11159 && c <= 11263 || c >= 11776 && c <= 11777 || c === 11778 || c === 11779 || c === 11780 || c === 11781 || c >= 11782 && c <= 11784 || c === 11785 || c === 11786 || c === 11787 || c === 11788 || c === 11789 || c >= 11790 && c <= 11798 || c === 11799 || c >= 11800 && c <= 11801 || c === 11802 || c === 11803 || c === 11804 || c === 11805 || c >= 11806 && c <= 11807 || c === 11808 || c === 11809 || c === 11810 || c === 11811 || c === 11812 || c === 11813 || c === 11814 || c === 11815 || c === 11816 || c === 11817 || c >= 11818 && c <= 11822 || c === 11823 || c >= 11824 && c <= 11833 || c >= 11834 && c <= 11835 || c >= 11836 && c <= 11839 || c === 11840 || c === 11841 || c === 11842 || c >= 11843 &&\n      c <= 11855 || c >= 11856 && c <= 11857 || c === 11858 || c >= 11859 && c <= 11903 || c >= 12289 && c <= 12291 || c === 12296 || c === 12297 || c === 12298 || c === 12299 || c === 12300 || c === 12301 || c === 12302 || c === 12303 || c === 12304 || c === 12305 || c >= 12306 && c <= 12307 || c === 12308 || c === 12309 || c === 12310 || c === 12311 || c === 12312 || c === 12313 || c === 12314 || c === 12315 || c === 12316 || c === 12317 || c >= 12318 && c <= 12319 || c === 12320 || c === 12336 || c === 64830 || c === 64831 || c >= 65093 && c <= 65094;\n    }\n    __name(_isPatternSyntax, \"_isPatternSyntax\");\n  }\n});\n\n// node_modules/@formatjs/icu-messageformat-parser/index.js\nvar require_icu_messageformat_parser = __commonJS({\n  \"node_modules/@formatjs/icu-messageformat-parser/index.js\"(exports2) {\n    \"use strict\";\n    init_process_global();\n    Object.defineProperty(exports2, \"__esModule\", { value: true });\n    exports2._Parser = exports2.parse = void 0;\n    var tslib_1 = (init_tslib_es62(), __toCommonJS(tslib_es6_exports2));\n    var error_1 = require_error();\n    var parser_1 = require_parser();\n    var types_1 = require_types();\n    function pruneLocation(els) {\n      els.forEach(function(el) {\n        delete el.location;\n        if ((0, types_1.isSelectElement)(el) || (0, types_1.isPluralElement)(el)) {\n          for (var k in el.options) {\n            delete el.options[k].location;\n            pruneLocation(el.options[k].value);\n          }\n        } else if ((0, types_1.isNumberElement)(el) && (0, types_1.isNumberSkeleton)(el.style)) {\n          delete el.style.location;\n        } else if (((0, types_1.isDateElement)(el) || (0, types_1.isTimeElement)(el)) && (0, types_1.isDateTimeSkeleton)(el.style)) {\n          delete el.style.location;\n        } else if ((0, types_1.isTagElement)(el)) {\n          pruneLocation(el.children);\n        }\n      });\n    }\n    __name(pruneLocation, \"pruneLocation\");\n    function parse(message, opts) {\n      if (opts === void 0) {\n        opts = {};\n      }\n      opts = tslib_1.__assign({ shouldParseSkeletons: true, requiresOtherClause: true }, opts);\n      var result = new parser_1.Parser(message, opts).parse();\n      if (result.err) {\n        var error = SyntaxError(error_1.ErrorKind[result.err.kind]);\n        error.location = result.err.location;\n        error.originalMessage = result.err.message;\n        throw error;\n      }\n      if (!(opts === null || opts === void 0 ? void 0 : opts.captureLocation)) {\n        pruneLocation(result.val);\n      }\n      return result.val;\n    }\n    __name(parse, \"parse\");\n    exports2.parse = parse;\n    tslib_1.__exportStar(require_types(), exports2);\n    exports2._Parser = parser_1.Parser;\n  }\n});\n\n// node_modules/@formatjs/fast-memoize/index.js\nvar require_fast_memoize = __commonJS({\n  \"node_modules/@formatjs/fast-memoize/index.js\"(exports2) {\n    \"use strict\";\n    init_process_global();\n    Object.defineProperty(exports2, \"__esModule\", { value: true });\n    exports2.strategies = exports2.memoize = void 0;\n    function memoize(fn, options) {\n      var cache = options && options.cache ? options.cache : cacheDefault;\n      var serializer = options && options.serializer ? options.serializer : serializerDefault;\n      var strategy = options && options.strategy ? options.strategy : strategyDefault;\n      return strategy(fn, {\n        cache,\n        serializer\n      });\n    }\n    __name(memoize, \"memoize\");\n    exports2.memoize = memoize;\n    function isPrimitive(value) {\n      return value == null || typeof value === \"number\" || typeof value === \"boolean\";\n    }\n    __name(isPrimitive, \"isPrimitive\");\n    function monadic(fn, cache, serializer, arg) {\n      var cacheKey = isPrimitive(arg) ? arg : serializer(arg);\n      var computedValue = cache.get(cacheKey);\n      if (typeof computedValue === \"undefined\") {\n        computedValue = fn.call(this, arg);\n        cache.set(cacheKey, computedValue);\n      }\n      return computedValue;\n    }\n    __name(monadic, \"monadic\");\n    function variadic(fn, cache, serializer) {\n      var args = Array.prototype.slice.call(arguments, 3);\n      var cacheKey = serializer(args);\n      var computedValue = cache.get(cacheKey);\n      if (typeof computedValue === \"undefined\") {\n        computedValue = fn.apply(this, args);\n        cache.set(cacheKey, computedValue);\n      }\n      return computedValue;\n    }\n    __name(variadic, \"variadic\");\n    function assemble(fn, context, strategy, cache, serialize) {\n      return strategy.bind(context, fn, cache, serialize);\n    }\n    __name(assemble, \"assemble\");\n    function strategyDefault(fn, options) {\n      var strategy = fn.length === 1 ? monadic : variadic;\n      return assemble(fn, this, strategy, options.cache.create(), options.serializer);\n    }\n    __name(strategyDefault, \"strategyDefault\");\n    function strategyVariadic(fn, options) {\n      return assemble(fn, this, variadic, options.cache.create(), options.serializer);\n    }\n    __name(strategyVariadic, \"strategyVariadic\");\n    function strategyMonadic(fn, options) {\n      return assemble(fn, this, monadic, options.cache.create(), options.serializer);\n    }\n    __name(strategyMonadic, \"strategyMonadic\");\n    var serializerDefault = /* @__PURE__ */ __name(function() {\n      return JSON.stringify(arguments);\n    }, \"serializerDefault\");\n    function ObjectWithoutPrototypeCache() {\n      this.cache = /* @__PURE__ */ Object.create(null);\n    }\n    __name(ObjectWithoutPrototypeCache, \"ObjectWithoutPrototypeCache\");\n    ObjectWithoutPrototypeCache.prototype.get = function(key) {\n      return this.cache[key];\n    };\n    ObjectWithoutPrototypeCache.prototype.set = function(key, value) {\n      this.cache[key] = value;\n    };\n    var cacheDefault = {\n      create: /* @__PURE__ */ __name(function create() {\n        return new ObjectWithoutPrototypeCache();\n      }, \"create\")\n    };\n    exports2.strategies = {\n      variadic: strategyVariadic,\n      monadic: strategyMonadic\n    };\n  }\n});\n\n// node_modules/intl-messageformat/src/error.js\nvar require_error2 = __commonJS({\n  \"node_modules/intl-messageformat/src/error.js\"(exports2) {\n    \"use strict\";\n    init_process_global();\n    Object.defineProperty(exports2, \"__esModule\", { value: true });\n    exports2.MissingValueError = exports2.InvalidValueTypeError = exports2.InvalidValueError = exports2.FormatError = exports2.ErrorCode = void 0;\n    var tslib_1 = (init_tslib_es6(), __toCommonJS(tslib_es6_exports));\n    var ErrorCode;\n    (function(ErrorCode2) {\n      ErrorCode2[\"MISSING_VALUE\"] = \"MISSING_VALUE\";\n      ErrorCode2[\"INVALID_VALUE\"] = \"INVALID_VALUE\";\n      ErrorCode2[\"MISSING_INTL_API\"] = \"MISSING_INTL_API\";\n    })(ErrorCode = exports2.ErrorCode || (exports2.ErrorCode = {}));\n    var FormatError = (\n      /** @class */\n      (function(_super) {\n        tslib_1.__extends(FormatError2, _super);\n        function FormatError2(msg, code, originalMessage) {\n          var _this = _super.call(this, msg) || this;\n          _this.code = code;\n          _this.originalMessage = originalMessage;\n          return _this;\n        }\n        __name(FormatError2, \"FormatError\");\n        FormatError2.prototype.toString = function() {\n          return \"[formatjs Error: \".concat(this.code, \"] \").concat(this.message);\n        };\n        return FormatError2;\n      })(Error)\n    );\n    exports2.FormatError = FormatError;\n    var InvalidValueError = (\n      /** @class */\n      (function(_super) {\n        tslib_1.__extends(InvalidValueError2, _super);\n        function InvalidValueError2(variableId, value, options, originalMessage) {\n          return _super.call(this, 'Invalid values for \"'.concat(variableId, '\": \"').concat(value, '\". Options are \"').concat(Object.keys(options).join('\", \"'), '\"'), ErrorCode.INVALID_VALUE, originalMessage) || this;\n        }\n        __name(InvalidValueError2, \"InvalidValueError\");\n        return InvalidValueError2;\n      })(FormatError)\n    );\n    exports2.InvalidValueError = InvalidValueError;\n    var InvalidValueTypeError = (\n      /** @class */\n      (function(_super) {\n        tslib_1.__extends(InvalidValueTypeError2, _super);\n        function InvalidValueTypeError2(value, type, originalMessage) {\n          return _super.call(this, 'Value for \"'.concat(value, '\" must be of type ').concat(type), ErrorCode.INVALID_VALUE, originalMessage) || this;\n        }\n        __name(InvalidValueTypeError2, \"InvalidValueTypeError\");\n        return InvalidValueTypeError2;\n      })(FormatError)\n    );\n    exports2.InvalidValueTypeError = InvalidValueTypeError;\n    var MissingValueError = (\n      /** @class */\n      (function(_super) {\n        tslib_1.__extends(MissingValueError2, _super);\n        function MissingValueError2(variableId, originalMessage) {\n          return _super.call(this, 'The intl string context variable \"'.concat(variableId, '\" was not provided to the string \"').concat(originalMessage, '\"'), ErrorCode.MISSING_VALUE, originalMessage) || this;\n        }\n        __name(MissingValueError2, \"MissingValueError\");\n        return MissingValueError2;\n      })(FormatError)\n    );\n    exports2.MissingValueError = MissingValueError;\n  }\n});\n\n// node_modules/intl-messageformat/src/formatters.js\nvar require_formatters = __commonJS({\n  \"node_modules/intl-messageformat/src/formatters.js\"(exports2) {\n    \"use strict\";\n    init_process_global();\n    Object.defineProperty(exports2, \"__esModule\", { value: true });\n    exports2.formatToParts = exports2.isFormatXMLElementFn = exports2.PART_TYPE = void 0;\n    var icu_messageformat_parser_1 = require_icu_messageformat_parser();\n    var error_1 = require_error2();\n    var PART_TYPE;\n    (function(PART_TYPE2) {\n      PART_TYPE2[PART_TYPE2[\"literal\"] = 0] = \"literal\";\n      PART_TYPE2[PART_TYPE2[\"object\"] = 1] = \"object\";\n    })(PART_TYPE = exports2.PART_TYPE || (exports2.PART_TYPE = {}));\n    function mergeLiteral(parts) {\n      if (parts.length < 2) {\n        return parts;\n      }\n      return parts.reduce(function(all, part) {\n        var lastPart = all[all.length - 1];\n        if (!lastPart || lastPart.type !== PART_TYPE.literal || part.type !== PART_TYPE.literal) {\n          all.push(part);\n        } else {\n          lastPart.value += part.value;\n        }\n        return all;\n      }, []);\n    }\n    __name(mergeLiteral, \"mergeLiteral\");\n    function isFormatXMLElementFn(el) {\n      return typeof el === \"function\";\n    }\n    __name(isFormatXMLElementFn, \"isFormatXMLElementFn\");\n    exports2.isFormatXMLElementFn = isFormatXMLElementFn;\n    function formatToParts(els, locales2, formatters, formats2, values, currentPluralValue, originalMessage) {\n      if (els.length === 1 && (0, icu_messageformat_parser_1.isLiteralElement)(els[0])) {\n        return [\n          {\n            type: PART_TYPE.literal,\n            value: els[0].value\n          }\n        ];\n      }\n      var result = [];\n      for (var _i = 0, els_1 = els; _i < els_1.length; _i++) {\n        var el = els_1[_i];\n        if ((0, icu_messageformat_parser_1.isLiteralElement)(el)) {\n          result.push({\n            type: PART_TYPE.literal,\n            value: el.value\n          });\n          continue;\n        }\n        if ((0, icu_messageformat_parser_1.isPoundElement)(el)) {\n          if (typeof currentPluralValue === \"number\") {\n            result.push({\n              type: PART_TYPE.literal,\n              value: formatters.getNumberFormat(locales2).format(currentPluralValue)\n            });\n          }\n          continue;\n        }\n        var varName = el.value;\n        if (!(values && varName in values)) {\n          throw new error_1.MissingValueError(varName, originalMessage);\n        }\n        var value = values[varName];\n        if ((0, icu_messageformat_parser_1.isArgumentElement)(el)) {\n          if (!value || typeof value === \"string\" || typeof value === \"number\") {\n            value = typeof value === \"string\" || typeof value === \"number\" ? String(value) : \"\";\n          }\n          result.push({\n            type: typeof value === \"string\" ? PART_TYPE.literal : PART_TYPE.object,\n            value\n          });\n          continue;\n        }\n        if ((0, icu_messageformat_parser_1.isDateElement)(el)) {\n          var style = typeof el.style === \"string\" ? formats2.date[el.style] : (0, icu_messageformat_parser_1.isDateTimeSkeleton)(el.style) ? el.style.parsedOptions : void 0;\n          result.push({\n            type: PART_TYPE.literal,\n            value: formatters.getDateTimeFormat(locales2, style).format(value)\n          });\n          continue;\n        }\n        if ((0, icu_messageformat_parser_1.isTimeElement)(el)) {\n          var style = typeof el.style === \"string\" ? formats2.time[el.style] : (0, icu_messageformat_parser_1.isDateTimeSkeleton)(el.style) ? el.style.parsedOptions : formats2.time.medium;\n          result.push({\n            type: PART_TYPE.literal,\n            value: formatters.getDateTimeFormat(locales2, style).format(value)\n          });\n          continue;\n        }\n        if ((0, icu_messageformat_parser_1.isNumberElement)(el)) {\n          var style = typeof el.style === \"string\" ? formats2.number[el.style] : (0, icu_messageformat_parser_1.isNumberSkeleton)(el.style) ? el.style.parsedOptions : void 0;\n          if (style && style.scale) {\n            value = value * (style.scale || 1);\n          }\n          result.push({\n            type: PART_TYPE.literal,\n            value: formatters.getNumberFormat(locales2, style).format(value)\n          });\n          continue;\n        }\n        if ((0, icu_messageformat_parser_1.isTagElement)(el)) {\n          var children = el.children, value_1 = el.value;\n          var formatFn = values[value_1];\n          if (!isFormatXMLElementFn(formatFn)) {\n            throw new error_1.InvalidValueTypeError(value_1, \"function\", originalMessage);\n          }\n          var parts = formatToParts(children, locales2, formatters, formats2, values, currentPluralValue);\n          var chunks = formatFn(parts.map(function(p) {\n            return p.value;\n          }));\n          if (!Array.isArray(chunks)) {\n            chunks = [chunks];\n          }\n          result.push.apply(result, chunks.map(function(c) {\n            return {\n              type: typeof c === \"string\" ? PART_TYPE.literal : PART_TYPE.object,\n              value: c\n            };\n          }));\n        }\n        if ((0, icu_messageformat_parser_1.isSelectElement)(el)) {\n          var opt = el.options[value] || el.options.other;\n          if (!opt) {\n            throw new error_1.InvalidValueError(el.value, value, Object.keys(el.options), originalMessage);\n          }\n          result.push.apply(result, formatToParts(opt.value, locales2, formatters, formats2, values));\n          continue;\n        }\n        if ((0, icu_messageformat_parser_1.isPluralElement)(el)) {\n          var opt = el.options[\"=\".concat(value)];\n          if (!opt) {\n            if (!Intl.PluralRules) {\n              throw new error_1.FormatError('Intl.PluralRules is not available in this environment.\\nTry polyfilling it using \"@formatjs/intl-pluralrules\"\\n', error_1.ErrorCode.MISSING_INTL_API, originalMessage);\n            }\n            var rule = formatters.getPluralRules(locales2, { type: el.pluralType }).select(value - (el.offset || 0));\n            opt = el.options[rule] || el.options.other;\n          }\n          if (!opt) {\n            throw new error_1.InvalidValueError(el.value, value, Object.keys(el.options), originalMessage);\n          }\n          result.push.apply(result, formatToParts(opt.value, locales2, formatters, formats2, values, value - (el.offset || 0)));\n          continue;\n        }\n      }\n      return mergeLiteral(result);\n    }\n    __name(formatToParts, \"formatToParts\");\n    exports2.formatToParts = formatToParts;\n  }\n});\n\n// node_modules/intl-messageformat/src/core.js\nvar require_core = __commonJS({\n  \"node_modules/intl-messageformat/src/core.js\"(exports2) {\n    \"use strict\";\n    init_process_global();\n    Object.defineProperty(exports2, \"__esModule\", { value: true });\n    exports2.IntlMessageFormat = void 0;\n    var tslib_1 = (init_tslib_es6(), __toCommonJS(tslib_es6_exports));\n    var icu_messageformat_parser_1 = require_icu_messageformat_parser();\n    var fast_memoize_1 = require_fast_memoize();\n    var formatters_1 = require_formatters();\n    function mergeConfig(c1, c2) {\n      if (!c2) {\n        return c1;\n      }\n      return tslib_1.__assign(tslib_1.__assign(tslib_1.__assign({}, c1 || {}), c2 || {}), Object.keys(c1).reduce(function(all, k) {\n        all[k] = tslib_1.__assign(tslib_1.__assign({}, c1[k]), c2[k] || {});\n        return all;\n      }, {}));\n    }\n    __name(mergeConfig, \"mergeConfig\");\n    function mergeConfigs(defaultConfig2, configs) {\n      if (!configs) {\n        return defaultConfig2;\n      }\n      return Object.keys(defaultConfig2).reduce(function(all, k) {\n        all[k] = mergeConfig(defaultConfig2[k], configs[k]);\n        return all;\n      }, tslib_1.__assign({}, defaultConfig2));\n    }\n    __name(mergeConfigs, \"mergeConfigs\");\n    function createFastMemoizeCache(store) {\n      return {\n        create: /* @__PURE__ */ __name(function() {\n          return {\n            get: /* @__PURE__ */ __name(function(key) {\n              return store[key];\n            }, \"get\"),\n            set: /* @__PURE__ */ __name(function(key, value) {\n              store[key] = value;\n            }, \"set\")\n          };\n        }, \"create\")\n      };\n    }\n    __name(createFastMemoizeCache, \"createFastMemoizeCache\");\n    function createDefaultFormatters(cache) {\n      if (cache === void 0) {\n        cache = {\n          number: {},\n          dateTime: {},\n          pluralRules: {}\n        };\n      }\n      return {\n        getNumberFormat: (0, fast_memoize_1.memoize)(function() {\n          var _a3;\n          var args = [];\n          for (var _i = 0; _i < arguments.length; _i++) {\n            args[_i] = arguments[_i];\n          }\n          return new ((_a3 = Intl.NumberFormat).bind.apply(_a3, tslib_1.__spreadArray([void 0], args, false)))();\n        }, {\n          cache: createFastMemoizeCache(cache.number),\n          strategy: fast_memoize_1.strategies.variadic\n        }),\n        getDateTimeFormat: (0, fast_memoize_1.memoize)(function() {\n          var _a3;\n          var args = [];\n          for (var _i = 0; _i < arguments.length; _i++) {\n            args[_i] = arguments[_i];\n          }\n          return new ((_a3 = Intl.DateTimeFormat).bind.apply(_a3, tslib_1.__spreadArray([void 0], args, false)))();\n        }, {\n          cache: createFastMemoizeCache(cache.dateTime),\n          strategy: fast_memoize_1.strategies.variadic\n        }),\n        getPluralRules: (0, fast_memoize_1.memoize)(function() {\n          var _a3;\n          var args = [];\n          for (var _i = 0; _i < arguments.length; _i++) {\n            args[_i] = arguments[_i];\n          }\n          return new ((_a3 = Intl.PluralRules).bind.apply(_a3, tslib_1.__spreadArray([void 0], args, false)))();\n        }, {\n          cache: createFastMemoizeCache(cache.pluralRules),\n          strategy: fast_memoize_1.strategies.variadic\n        })\n      };\n    }\n    __name(createDefaultFormatters, \"createDefaultFormatters\");\n    var IntlMessageFormat2 = exports2.IntlMessageFormat = /** @class */\n    (function() {\n      function IntlMessageFormat3(message, locales2, overrideFormats, opts) {\n        if (locales2 === void 0) {\n          locales2 = IntlMessageFormat3.defaultLocale;\n        }\n        var _this = this;\n        this.formatterCache = {\n          number: {},\n          dateTime: {},\n          pluralRules: {}\n        };\n        this.format = function(values) {\n          var parts = _this.formatToParts(values);\n          if (parts.length === 1) {\n            return parts[0].value;\n          }\n          var result = parts.reduce(function(all, part) {\n            if (!all.length || part.type !== formatters_1.PART_TYPE.literal || typeof all[all.length - 1] !== \"string\") {\n              all.push(part.value);\n            } else {\n              all[all.length - 1] += part.value;\n            }\n            return all;\n          }, []);\n          if (result.length <= 1) {\n            return result[0] || \"\";\n          }\n          return result;\n        };\n        this.formatToParts = function(values) {\n          return (0, formatters_1.formatToParts)(_this.ast, _this.locales, _this.formatters, _this.formats, values, void 0, _this.message);\n        };\n        this.resolvedOptions = function() {\n          var _a4;\n          return {\n            locale: ((_a4 = _this.resolvedLocale) === null || _a4 === void 0 ? void 0 : _a4.toString()) || Intl.NumberFormat.supportedLocalesOf(_this.locales)[0]\n          };\n        };\n        this.getAst = function() {\n          return _this.ast;\n        };\n        this.locales = locales2;\n        this.resolvedLocale = IntlMessageFormat3.resolveLocale(locales2);\n        if (typeof message === \"string\") {\n          this.message = message;\n          if (!IntlMessageFormat3.__parse) {\n            throw new TypeError(\"IntlMessageFormat.__parse must be set to process `message` of type `string`\");\n          }\n          var _a3 = opts || {}, formatters = _a3.formatters, parseOpts = tslib_1.__rest(_a3, [\"formatters\"]);\n          this.ast = IntlMessageFormat3.__parse(message, tslib_1.__assign(tslib_1.__assign({}, parseOpts), { locale: this.resolvedLocale }));\n        } else {\n          this.ast = message;\n        }\n        if (!Array.isArray(this.ast)) {\n          throw new TypeError(\"A message must be provided as a String or AST.\");\n        }\n        this.formats = mergeConfigs(IntlMessageFormat3.formats, overrideFormats);\n        this.formatters = opts && opts.formatters || createDefaultFormatters(this.formatterCache);\n      }\n      __name(IntlMessageFormat3, \"IntlMessageFormat\");\n      Object.defineProperty(IntlMessageFormat3, \"defaultLocale\", {\n        get: /* @__PURE__ */ __name(function() {\n          if (!IntlMessageFormat3.memoizedDefaultLocale) {\n            IntlMessageFormat3.memoizedDefaultLocale = new Intl.NumberFormat().resolvedOptions().locale;\n          }\n          return IntlMessageFormat3.memoizedDefaultLocale;\n        }, \"get\"),\n        enumerable: false,\n        configurable: true\n      });\n      IntlMessageFormat3.memoizedDefaultLocale = null;\n      IntlMessageFormat3.resolveLocale = function(locales2) {\n        if (typeof Intl.Locale === \"undefined\") {\n          return;\n        }\n        var supportedLocales = Intl.NumberFormat.supportedLocalesOf(locales2);\n        if (supportedLocales.length > 0) {\n          return new Intl.Locale(supportedLocales[0]);\n        }\n        return new Intl.Locale(typeof locales2 === \"string\" ? locales2 : locales2[0]);\n      };\n      IntlMessageFormat3.__parse = icu_messageformat_parser_1.parse;\n      IntlMessageFormat3.formats = {\n        number: {\n          integer: {\n            maximumFractionDigits: 0\n          },\n          currency: {\n            style: \"currency\"\n          },\n          percent: {\n            style: \"percent\"\n          }\n        },\n        date: {\n          short: {\n            month: \"numeric\",\n            day: \"numeric\",\n            year: \"2-digit\"\n          },\n          medium: {\n            month: \"short\",\n            day: \"numeric\",\n            year: \"numeric\"\n          },\n          long: {\n            month: \"long\",\n            day: \"numeric\",\n            year: \"numeric\"\n          },\n          full: {\n            weekday: \"long\",\n            month: \"long\",\n            day: \"numeric\",\n            year: \"numeric\"\n          }\n        },\n        time: {\n          short: {\n            hour: \"numeric\",\n            minute: \"numeric\"\n          },\n          medium: {\n            hour: \"numeric\",\n            minute: \"numeric\",\n            second: \"numeric\"\n          },\n          long: {\n            hour: \"numeric\",\n            minute: \"numeric\",\n            second: \"numeric\",\n            timeZoneName: \"short\"\n          },\n          full: {\n            hour: \"numeric\",\n            minute: \"numeric\",\n            second: \"numeric\",\n            timeZoneName: \"short\"\n          }\n        }\n      };\n      return IntlMessageFormat3;\n    })();\n  }\n});\n\n// node_modules/intl-messageformat/index.js\nvar require_intl_messageformat = __commonJS({\n  \"node_modules/intl-messageformat/index.js\"(exports2) {\n    \"use strict\";\n    init_process_global();\n    Object.defineProperty(exports2, \"__esModule\", { value: true });\n    var tslib_1 = (init_tslib_es6(), __toCommonJS(tslib_es6_exports));\n    var core_1 = require_core();\n    tslib_1.__exportStar(require_formatters(), exports2);\n    tslib_1.__exportStar(require_core(), exports2);\n    tslib_1.__exportStar(require_error2(), exports2);\n    exports2.default = core_1.IntlMessageFormat;\n  }\n});\n\n// replace-modules:module\nvar createRequire;\nvar init_module = __esm({\n  \"replace-modules:module\"() {\n    init_process_global();\n    createRequire = /* @__PURE__ */ __name(() => ({\n      resolve() {\n        throw new Error(\"createRequire.resolve is not supported\");\n      }\n    }), \"createRequire\");\n  }\n});\n\n// replace-modules:url\nvar URL2, fileURLToPath, url_default;\nvar init_url = __esm({\n  \"replace-modules:url\"() {\n    init_process_global();\n    URL2 = globalThis.URL;\n    fileURLToPath = /* @__PURE__ */ __name((url) => url, \"fileURLToPath\");\n    url_default = { URL: URL2, fileURLToPath };\n  }\n});\n\n// shared/esm-utils.js\nfunction getModulePath(importMeta) {\n  return url_default.fileURLToPath(importMeta.url);\n}\nvar init_esm_utils = __esm({\n  \"shared/esm-utils.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_module();\n    init_url();\n    /**\n     * @license\n     * Copyright 2021 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    __name(getModulePath, \"getModulePath\");\n  }\n});\n\n// shared/type-verifiers.js\nfunction isObjectOfUnknownValues(val) {\n  return typeof val === \"object\" && val !== null && !Array.isArray(val);\n}\nfunction isObjectOrArrayOfUnknownValues(val) {\n  return typeof val === \"object\" && val !== null;\n}\nvar init_type_verifiers = __esm({\n  \"shared/type-verifiers.js\"() {\n    \"use strict\";\n    init_process_global();\n    /**\n     * @license\n     * Copyright 2020 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    __name(isObjectOfUnknownValues, \"isObjectOfUnknownValues\");\n    __name(isObjectOrArrayOfUnknownValues, \"isObjectOrArrayOfUnknownValues\");\n  }\n});\n\n// replace-modules:/Users/alexrudenko/src/lighthouse/shared/localization/locales.js\nvar locales;\nvar init_locales = __esm({\n  \"replace-modules:/Users/alexrudenko/src/lighthouse/shared/localization/locales.js\"() {\n    init_process_global();\n    locales = {};\n  }\n});\n\n// shared/localization/format.js\nfunction collectAllCustomElementsFromICU(icuElements, customElements = /* @__PURE__ */ new Map()) {\n  for (const el of icuElements) {\n    if (el.type === TYPE.literal || el.type === TYPE.pound) continue;\n    customElements.set(el.value, el);\n    if (el.type === TYPE.plural) {\n      for (const option of Object.values(el.options)) {\n        collectAllCustomElementsFromICU(option.value, customElements);\n      }\n    }\n  }\n  return customElements;\n}\nfunction _preformatValues(messageFormatter, values = {}, lhlMessage) {\n  const customElements = collectAllCustomElementsFromICU(messageFormatter.getAst());\n  const formattedValues = {};\n  for (const [id, element] of customElements) {\n    if (!(id in values)) {\n      throw new Error(`ICU Message \"${lhlMessage}\" contains a value reference (\"${id}\") that wasn't provided`);\n    }\n    const value = values[id];\n    if (element.type !== TYPE.number) {\n      formattedValues[id] = value;\n      continue;\n    }\n    if (typeof value !== \"number\") {\n      throw new Error(`ICU Message \"${lhlMessage}\" contains a numeric reference (\"${id}\") but provided value was not a number`);\n    }\n    if (element.style === \"milliseconds\") {\n      formattedValues[id] = Math.round(value / 10) * 10;\n    } else if (element.style === \"seconds\" && id === \"timeInMs\") {\n      formattedValues[id] = Math.round(value / 100) / 10;\n    } else if (element.style === \"bytes\") {\n      formattedValues[id] = value / 1024;\n    } else {\n      formattedValues[id] = value;\n    }\n  }\n  for (const valueId of Object.keys(values)) {\n    if (valueId in formattedValues) continue;\n    if (valueId === \"errorCode\") {\n      formattedValues.errorCode = values.errorCode;\n      continue;\n    }\n    throw new Error(`Provided value \"${valueId}\" does not match any placeholder in ICU message \"${lhlMessage}\"`);\n  }\n  return formattedValues;\n}\nfunction escapeIcuMessage(message) {\n  return message.replace(/'/g, `''`).replace(/\\\\{/g, `'{`).replace(/\\\\}/g, `'}`);\n}\nfunction formatMessage(message, values, locale) {\n  message = escapeIcuMessage(message);\n  const localeForMessageFormat = locale === \"en-XA\" || locale === \"en-XL\" ? \"de-DE\" : locale;\n  const IntlMessageFormatCtor = import_intl_messageformat.default.IntlMessageFormat || import_intl_messageformat.default;\n  const formatter = new IntlMessageFormatCtor(message, localeForMessageFormat, formats, {\n    ignoreTag: true\n  });\n  const valuesForMessageFormat = _preformatValues(formatter, values, message);\n  const formattedResult = formatter.format(valuesForMessageFormat);\n  if (typeof formattedResult !== \"string\") {\n    throw new Error(\"unexpected formatted result\");\n  }\n  return formattedResult;\n}\nfunction _localizeIcuMessage(icuMessage, locale) {\n  const localeMessages = _getLocaleMessages(locale);\n  const localeMessage = localeMessages[icuMessage.i18nId];\n  if (!localeMessage) {\n    return icuMessage.formattedDefault;\n  }\n  return formatMessage(localeMessage.message, icuMessage.values, locale);\n}\nfunction getRendererFormattedStrings(locale) {\n  const localeMessages = _getLocaleMessages(locale);\n  const icuMessageIds = Object.keys(localeMessages).filter((f) => f.startsWith(\"report/renderer/report-utils.js\"));\n  const strings = {};\n  for (const icuMessageId of icuMessageIds) {\n    const { filename, key } = getIcuMessageIdParts(icuMessageId);\n    if (!filename.endsWith(\"report-utils.js\")) {\n      throw new Error(`Unexpected message: ${icuMessageId}`);\n    }\n    strings[key] = localeMessages[icuMessageId].message;\n  }\n  return strings;\n}\nfunction isIcuMessage(icuMessageOrNot) {\n  if (!isObjectOfUnknownValues(icuMessageOrNot)) {\n    return false;\n  }\n  const { i18nId, values, formattedDefault } = icuMessageOrNot;\n  if (typeof i18nId !== \"string\") {\n    return false;\n  }\n  if (typeof formattedDefault !== \"string\") {\n    return false;\n  }\n  if (values !== void 0) {\n    if (!isObjectOfUnknownValues(values)) {\n      return false;\n    }\n    for (const value of Object.values(values)) {\n      if (typeof value !== \"string\" && typeof value !== \"number\") {\n        return false;\n      }\n    }\n  }\n  return MESSAGE_I18N_ID_REGEX.test(i18nId);\n}\nfunction getFormatted(icuMessageOrRawString, locale) {\n  if (isIcuMessage(icuMessageOrRawString)) {\n    return _localizeIcuMessage(icuMessageOrRawString, locale);\n  }\n  if (typeof icuMessageOrRawString === \"string\") {\n    return icuMessageOrRawString;\n  }\n  throw new Error(\"Attempted to format invalid icuMessage type\");\n}\nfunction _formatPathAsString(pathInLHR) {\n  let pathAsString = \"\";\n  for (const property of pathInLHR) {\n    if (/^[a-z]+$/i.test(property)) {\n      if (pathAsString.length) pathAsString += \".\";\n      pathAsString += property;\n    } else {\n      if (/]|\"|'|\\s/.test(property)) throw new Error(`Cannot handle \"${property}\" in i18n`);\n      pathAsString += `[${property}]`;\n    }\n  }\n  return pathAsString;\n}\nfunction replaceIcuMessages(inputObject, locale) {\n  function replaceInObject(subObject, icuMessagePaths2, pathInLHR = []) {\n    if (!isObjectOrArrayOfUnknownValues(subObject)) return;\n    for (const [property, possibleIcuMessage] of Object.entries(subObject)) {\n      const currentPathInLHR = pathInLHR.concat([property]);\n      if (isIcuMessage(possibleIcuMessage)) {\n        const formattedString = getFormatted(possibleIcuMessage, locale);\n        const messageInstancesInLHR = icuMessagePaths2[possibleIcuMessage.i18nId] || [];\n        const currentPathAsString = _formatPathAsString(currentPathInLHR);\n        messageInstancesInLHR.push(\n          possibleIcuMessage.values ? { values: possibleIcuMessage.values, path: currentPathAsString } : currentPathAsString\n        );\n        subObject[property] = formattedString;\n        icuMessagePaths2[possibleIcuMessage.i18nId] = messageInstancesInLHR;\n      } else {\n        replaceInObject(possibleIcuMessage, icuMessagePaths2, currentPathInLHR);\n      }\n    }\n  }\n  __name(replaceInObject, \"replaceInObject\");\n  const icuMessagePaths = {};\n  replaceInObject(inputObject, icuMessagePaths);\n  return icuMessagePaths;\n}\nfunction _getLocaleMessages(locale) {\n  const localeMessages = LOCALE_MESSAGES[locale];\n  if (!localeMessages) {\n    if (locale === DEFAULT_LOCALE) {\n      return {};\n    }\n    throw new Error(`Unsupported locale '${locale}'`);\n  }\n  return localeMessages;\n}\nfunction getAvailableLocales() {\n  const localesWithMessages = /* @__PURE__ */ new Set([...Object.keys(LOCALE_MESSAGES), DEFAULT_LOCALE]);\n  return (\n    /** @type {Array<LH.Locale>} */\n    [...localesWithMessages].sort()\n  );\n}\nfunction getIcuMessageIdParts(i18nMessageId) {\n  if (!MESSAGE_I18N_ID_REGEX.test(i18nMessageId)) {\n    throw Error(`\"${i18nMessageId}\" does not appear to be a valid ICU message id`);\n  }\n  const [filename, key] = i18nMessageId.split(\" | \");\n  return { filename, key };\n}\nvar import_intl_messageformat, TYPE, LOCALE_MESSAGES, DEFAULT_LOCALE, CANONICAL_LOCALES, MESSAGE_I18N_ID_REGEX, formats;\nvar init_format = __esm({\n  \"shared/localization/format.js\"() {\n    \"use strict\";\n    init_process_global();\n    import_intl_messageformat = __toESM(require_intl_messageformat(), 1);\n    init_esm_utils();\n    init_type_verifiers();\n    init_locales();\n    /**\n     * @license\n     * Copyright 2021 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    TYPE = /** @type {const} */\n    {\n      literal: 0,\n      argument: 1,\n      number: 2,\n      date: 3,\n      time: 4,\n      select: 5,\n      plural: 6,\n      pound: 7,\n      tag: 8\n    };\n    LOCALE_MESSAGES = locales;\n    DEFAULT_LOCALE = \"en-US\";\n    CANONICAL_LOCALES = [\"ar-XB.json\", \"ar.json\", \"bg.json\", \"ca.json\", \"cs.json\", \"da.json\", \"de.json\", \"el.json\", \"en-GB.json\", \"en-US.json\", \"en-XA.json\", \"en-XL.json\", \"es-419.json\", \"es.json\", \"fi.json\", \"fil.json\", \"fr.json\", \"he.json\", \"hi.json\", \"hr.json\", \"hu.json\", \"id.json\", \"it.json\", \"ja.json\", \"ko.json\", \"lt.json\", \"lv.json\", \"nl.json\", \"no.json\", \"pl.json\", \"pt-PT.json\", \"pt.json\", \"ro.json\", \"ru.json\", \"sk.json\", \"sl.json\", \"sr-Latn.json\", \"sr.json\", \"sv.json\", \"ta.json\", \"te.json\", \"th.json\", \"tr.json\", \"uk.json\", \"vi.json\", \"zh-HK.json\", \"zh-TW.json\", \"zh.json\"].filter((basename) => basename.endsWith(\".json\") && !basename.endsWith(\".ctc.json\")).map((locale) => locale.replace(\".json\", \"\")).sort();\n    MESSAGE_I18N_ID_REGEX = / | [^\\s]+$/;\n    formats = {\n      number: {\n        bytes: {\n          maximumFractionDigits: 0\n        },\n        milliseconds: {\n          maximumFractionDigits: 0\n        },\n        seconds: {\n          // Force the seconds to the tenths place for limited output and ease of scanning\n          minimumFractionDigits: 1,\n          maximumFractionDigits: 1\n        },\n        extendedPercent: {\n          // Force allow up to two digits after decimal place in percentages. (Intl.NumberFormat options)\n          maximumFractionDigits: 2,\n          style: \"percent\"\n        }\n      }\n    };\n    __name(collectAllCustomElementsFromICU, \"collectAllCustomElementsFromICU\");\n    __name(_preformatValues, \"_preformatValues\");\n    __name(escapeIcuMessage, \"escapeIcuMessage\");\n    __name(formatMessage, \"formatMessage\");\n    __name(_localizeIcuMessage, \"_localizeIcuMessage\");\n    __name(getRendererFormattedStrings, \"getRendererFormattedStrings\");\n    __name(isIcuMessage, \"isIcuMessage\");\n    __name(getFormatted, \"getFormatted\");\n    __name(_formatPathAsString, \"_formatPathAsString\");\n    __name(replaceIcuMessages, \"replaceIcuMessages\");\n    __name(_getLocaleMessages, \"_getLocaleMessages\");\n    __name(getAvailableLocales, \"getAvailableLocales\");\n    __name(getIcuMessageIdParts, \"getIcuMessageIdParts\");\n  }\n});\n\n// node_modules/lighthouse-stack-packs/packs/amp.js\nvar require_amp = __commonJS({\n  \"node_modules/lighthouse-stack-packs/packs/amp.js\"(exports2, module2) {\n    init_process_global();\n    var icon = `data:image/svg+xml,<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 256 256\"><path fill=\"%230379c4\" fill-rule=\"evenodd\" d=\"m171.887 116.28-53.696 89.36h-9.728l9.617-58.227-30.2.047a4.852 4.852 0 0 1-4.855-4.855c0-1.152 1.07-3.102 1.07-3.102l53.52-89.254 9.9.043-9.86 58.317 30.413-.043a4.852 4.852 0 0 1 4.855 4.855c0 1.088-.427 2.044-1.033 2.854l.004.004zM128 0C57.306 0 0 57.3 0 128s57.306 128 128 128 128-57.306 128-128S198.7 0 128 0z\"/></svg>`;\n    var UIStrings125 = {\n      /** Additional description of a Lighthouse audit that tells the user how they can improve image loading by using WebP in the context of AMP. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */\n      \"modern-image-formats\": \"Consider displaying all [`amp-img`](https://amp.dev/documentation/components/amp-img/?format=websites) components in WebP formats while specifying an appropriate fallback for other browsers. [Learn more](https://amp.dev/documentation/components/amp-img/#example:-specifying-a-fallback-image).\",\n      /** Additional description of a Lighthouse audit that tells the user how images are automatically lazy loaded for the AMP framewok. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */\n      \"offscreen-images\": \"Ensure that you are using [`amp-img`](https://amp.dev/documentation/components/amp-img/?format=websites) for images to automatically lazy-load. [Learn more](https://amp.dev/documentation/guides-and-tutorials/develop/media_iframes_3p/?format=websites#images).\",\n      /** Additional description of a Lighthouse audit that tells the user how they can improve performance by reducing the amount of render blocking resources present on their page in the context of the AMP framework. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */\n      \"render-blocking-resources\": \"Use tools such as [AMP Optimizer](https://github.com/ampproject/amp-toolbox/tree/master/packages/optimizer) to [server-side render AMP layouts](https://amp.dev/documentation/guides-and-tutorials/optimize-and-measure/server-side-rendering/).\",\n      /** Additional description of a Lighthouse audit that tells the user how they can improve performance by ensuring all the CSS written is supported by the AMP framework. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */\n      \"unminified-css\": \"Refer to the [AMP documentation](https://amp.dev/documentation/guides-and-tutorials/develop/style_and_layout/style_pages/) to ensure all styles are supported.\",\n      /** Additional description of a Lighthouse audit that tells the user how they can improve performance by using a runtime-managed animated image in the context of the AMP framework. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */\n      \"efficient-animated-content\": \"For animated content, use [`amp-anim`](https://amp.dev/documentation/components/amp-anim/) to minimize CPU usage when the content is offscreen.\",\n      /** Additional description of a Lighthouse audit that tells the user how they can improve performance by using responsive images in the context of the AMP framework. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */\n      \"uses-responsive-images\": \"The [`amp-img`](https://amp.dev/documentation/components/amp-img/?format=websites) component supports the [`srcset`](https://web.dev/use-srcset-to-automatically-choose-the-right-image/) attribute to specify which image assets to use based on the screen size. [Learn more](https://amp.dev/documentation/guides-and-tutorials/develop/style_and_layout/art_direction/).\"\n    };\n    module2.exports = {\n      id: \"amp\",\n      title: \"AMP\",\n      icon,\n      UIStrings: UIStrings125\n    };\n  }\n});\n\n// node_modules/lighthouse-stack-packs/packs/angular.js\nvar require_angular = __commonJS({\n  \"node_modules/lighthouse-stack-packs/packs/angular.js\"(exports2, module2) {\n    init_process_global();\n    var icon = `data:image/svg+xml,<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 250 250\"><path fill=\"%23dd0031\" d=\"M125 30 31.9 63.2l14.2 123.1L125 230l78.9-43.7 14.2-123.1z\"/><path fill=\"%23c3002f\" d=\"M125 30v22.2-.1V230l78.9-43.7 14.2-123.1L125 30z\"/><path fill=\"%23fff\" d=\"M125 52.1 66.8 182.6h21.7l11.7-29.2h49.4l11.7 29.2H183L125 52.1zm17 83.3h-34l17-40.9 17 40.9z\"/></svg>`;\n    var UIStrings125 = {\n      /** Additional description of a Lighthouse audit that tells the user how they can improve site loading performance by reducing the total bytes delivered by their page in the context of the Angular framework. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */\n      \"total-byte-weight\": \"Apply [route-level code splitting](https://web.dev/route-level-code-splitting-in-angular/) to minimize the size of your JavaScript bundles. Also, consider precaching assets with the [Angular service worker](https://web.dev/precaching-with-the-angular-service-worker/).\",\n      /** Additional description of a Lighthouse audit that tells the user how they can improve performance by minifying their CSS and JS files in the context of the Angular framework. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */\n      \"unminified-warning\": \"If you are using Angular CLI, ensure that builds are generated in production mode. [Learn more](https://angular.io/guide/deployment#enable-runtime-production-mode).\",\n      /** Additional description of a Lighthouse audit that tells the user how they can improve performance by removing unused Javascript files in the context of the Angular framework. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */\n      \"unused-javascript\": \"If you are using Angular CLI, include source maps in your production build to inspect your bundles. [Learn more](https://angular.io/guide/deployment#inspect-the-bundles).\",\n      /** Additional description of a Lighthouse audit that tells the user how they can use responsive images in the context of the Angular framework. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */\n      \"uses-responsive-images\": \"Consider using the `BreakpointObserver` utility in the Component Dev Kit (CDK) to manage image breakpoints. [Learn more](https://material.angular.io/cdk/layout/overview).\",\n      /** Additional description of a Lighthouse audit that tells the user how they can use preload to improve performance in the context of the Angular framework. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */\n      \"uses-rel-preload\": \"Preload routes ahead of time to speed up navigation. [Learn more](https://web.dev/route-preloading-in-angular/).\",\n      /** Additional description of a Lighthouse audit that tells the user and *how* they should reduce the size of the web page's DOM in the context of the Angular framework. 'Learn More' becomes link text to additional documentation. */\n      \"dom-size\": \"Consider virtual scrolling with the Component Dev Kit (CDK) if very large lists are being rendered. [Learn more](https://web.dev/virtualize-lists-with-angular-cdk/).\"\n    };\n    module2.exports = {\n      id: \"angular\",\n      title: \"Angular\",\n      icon,\n      UIStrings: UIStrings125\n    };\n  }\n});\n\n// node_modules/lighthouse-stack-packs/packs/drupal.js\nvar require_drupal = __commonJS({\n  \"node_modules/lighthouse-stack-packs/packs/drupal.js\"(exports2, module2) {\n    init_process_global();\n    var icon = `data:image/svg+xml,<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 186.525 243.713\"><path fill=\"%23009cde\" d=\"M131.64 51.91C114.491 34.769 98.13 18.429 93.26 0c-4.87 18.429-21.234 34.769-38.38 51.91C29.16 77.613 0 106.743 0 150.434a93.263 93.263 0 1 0 186.525 0c0-43.688-29.158-72.821-54.885-98.524m-92 120.256c-5.719-.194-26.824-36.571 12.329-75.303l25.909 28.3a2.215 2.215 0 0 1-.173 3.306c-6.183 6.34-32.534 32.765-35.81 41.902-.675 1.886-1.663 1.815-2.256 1.795m53.624 47.943a32.075 32.075 0 0 1-32.076-32.075 33.423 33.423 0 0 1 7.995-21.187c5.784-7.072 24.077-26.963 24.077-26.963s18.012 20.183 24.033 26.896a31.368 31.368 0 0 1 8.046 21.254 32.076 32.076 0 0 1-32.075 32.075m61.392-52.015c-.691 1.512-2.26 4.036-4.376 4.113-3.773.138-4.176-1.796-6.965-5.923-6.122-9.06-59.551-64.9-69.545-75.699-8.79-9.498-1.238-16.195 2.266-19.704 4.395-4.403 17.224-17.225 17.224-17.225s38.255 36.296 54.19 61.096 10.444 46.26 7.206 53.342\"/></svg>`;\n    var UIStrings125 = {\n      /** Additional description of a Lighthouse audit that tells the user how they can improve performance by removing unused CSS, in the context of the `Drupal` CMS platform. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */\n      \"unused-css-rules\": \"Consider removing unused CSS rules and only attach the needed `Drupal` libraries to the relevant page or component in a page. See the [`Drupal` documentation](https://www.drupal.org/docs/develop/theming-drupal/adding-assets-css-js-to-a-drupal-theme-via-librariesyml#define) for details. To identify attached libraries that are adding extraneous CSS, try running [code coverage](https://developer.chrome.com/docs/devtools/coverage) in Chrome DevTools. You can identify the theme/module responsible from the URL of the stylesheet when CSS aggregation is disabled in your `Drupal` site. Look out for themes/modules that have many stylesheets in the list which have a lot of red in code coverage. A theme/module should only attach a stylesheet library if it is actually used on the page.\",\n      /** Additional description of a Lighthouse audit that tells the user how they can improve image loading by using webp in the context of the `Drupal` CMS platform. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */\n      \"modern-image-formats\": \"Consider configuring [WebP image formats with a Convert image style](https://www.drupal.org/docs/core-modules-and-themes/core-modules/image-module/working-with-images#styles) on your site.\",\n      /** Additional description of a Lighthouse audit that tells the user how they can improve performance by lazy loading images that are initially offscreen in the context of the `Drupal` CMS platform. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */\n      \"offscreen-images\": \"Consider configuring lazy load images in `Drupal`. The field formatters for images support `lazy` or `eager`.\",\n      /** Additional description of a Lighthouse audit that tells the user how they can improve site loading performance by reducing the total bytes delivered by their page in the context of the `Drupal` CMS platform. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */\n      \"total-byte-weight\": \"Consider using [Responsive Image Styles](https://www.drupal.org/documentation/modules/responsive_image) to reduce the size of images loaded on your page. If you are using `Views` to show multiple content items on a page, consider implementing pagination to limit the number of content items shown on a given page.\",\n      /** Additional description of a Lighthouse audit that tells the user how they can improve performance by reducing the amount of render blocking resources present on their page, in the context of the `Drupal` CMS platform. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */\n      \"render-blocking-resources\": \"Consider using [a module](https://www.drupal.org/project/critical_css) to inline critical CSS and JavaScript, and use the defer attribute for non-critical CSS or JavaScript.\",\n      /** Additional description of a Lighthouse audit that tells the user how they can improve performance by minifying their CSS files in the context of the `Drupal` CMS platform. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */\n      \"unminified-css\": 'Ensure you have enabled \"Aggregate CSS files\" in the \"Administration » Configuration » Development\" page.',\n      /** Additional description of a Lighthouse audit that tells the user how they can improve performance by minifying their Javascript files in the context of the `Drupal` CMS platform. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */\n      \"unminified-javascript\": 'Ensure you have enabled \"Aggregate JavaScript files\" in the \"Administration » Configuration » Development\" page.',\n      /** Additional description of a Lighthouse audit that tells the user how they can improve performance by encoding animated images as video, in the context of the `Drupal` CMS platform. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */\n      \"efficient-animated-content\": \"Consider uploading your `GIF` to a service which will make it available to embed as an HTML5 video.\",\n      /** Additional description of a Lighthouse audit that tells the user how they can improve performance by removing unused Javascript files in the context of the `Drupal` CMS platform. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */\n      \"unused-javascript\": \"Consider removing unused JavaScript assets and only attach the needed `Drupal` libraries to the relevant page or component in a page. See the [Drupal documentation](https://www.drupal.org/docs/develop/theming-drupal/adding-assets-css-js-to-a-drupal-theme-via-librariesyml#define) for details. To identify attached libraries that are adding extraneous JavaScript, try running [code coverage](https://developer.chrome.com/docs/devtools/coverage) in Chrome DevTools. You can identify the theme/module responsible from the URL of the script when JavaScript aggregation is disabled in your `Drupal` site. Look out for themes/modules that have many scripts in the list which have a lot of red in code coverage. A theme/module should only attach a script library if it is actually used on the page.\",\n      /** Additional description of a Lighthouse audit that tells the user how they can improve their site by enabling long caching in the context of the `Drupal` CMS platform. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */\n      \"uses-long-cache-ttl\": 'Set the \"Browser and proxy cache maximum age\" in the \"Administration » Configuration » Development\" page. Read about [`Drupal` cache and optimizing for performance](https://www.drupal.org/docs/8/api/cache-api/cache-api).',\n      /** Additional description of a Lighthouse audit that tells the user how they can improve site performance by optimizing images, in the context of the `Drupal` CMS platform. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */\n      \"uses-optimized-images\": \"Consider using [a module](https://www.drupal.org/project/project_module?f%5B0%5D=&f%5B1%5D=&f%5B2%5D=im_vid_3%3A123&f%5B3%5D=&f%5B4%5D=sm_field_project_type%3Afull&f%5B5%5D=&f%5B6%5D=&text=image&solrsort=iss_project_release_usage+desc&op=Search) that automatically optimizes and reduces the size of images uploaded through the site while retaining quality. Also, ensure you are using the native [Responsive Image Styles](https://www.drupal.org/documentation/modules/responsive_image) provided from `Drupal` for all images rendered on the site.\",\n      /** Additional description of a Lighthouse audit for a third-party framework called `Drupal`. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */\n      \"uses-text-compression\": \"Text-based resources should be served with compression (gzip, deflate or brotli) to minimize total network bytes. Consider using a CDN that natively supports this, or configure the web server to perform this operation. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/text-compression).\",\n      /** Additional description of a Lighthouse audit that tells the user how they can improve performance by using responsive images in the context of the `Drupal` CMS platform. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */\n      \"uses-responsive-images\": \"Ensure that you are using the native [Responsive Image Styles](https://www.drupal.org/documentation/modules/responsive_image) provided from `Drupal`. Use the Responsive Image Styles when rendering image fields through view modes, views, or images uploaded through the WYSIWYG editor.\",\n      /** Additional description of a Lighthouse audit for a third-party framework called `Drupal`. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */\n      \"prioritize-lcp-image\": \"If the LCP element is dynamically added to the page, you should optimize the image in order to improve LCP. [Learn more](https://www.smashingmagazine.com/2023/08/methods-improving-drupal-largest-contentful-paint-core-web-vital/).\",\n      /** Additional description of a Lighthouse audit that tells the user how they can improve the time to first byte speed metric, in the context of the `Drupal` CMS platform. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */\n      \"server-response-time\": \"Offload traffic with one or more `Drupal` caching modules such as `Internal Page Cache`, `Internal Dynamic Page Cache`, and `BigPipe`. Couple these with a CDN to further improve response time. Your hosting servers should make use of PHP OPcache. Consider using memory-caching such as Redis or Memcached to reduce database query times. Lastly use performant themes, modules, and faster servers to lower server response time.\",\n      /** Additional description of a Lighthouse audit for a third-party framework called `Drupal`. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */\n      \"redirects\": \"Redirects introduce additional delays before the page can be loaded. If the [Redirect](https://www.drupal.org/project/redirect) module is installed, review if unnecessary redirects can be removed. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/redirects).\",\n      /** Additional description of a Lighthouse audit that tells the user how they can add preconnect or dns-prefetch resource hints, in the context of the `Drupal` CMS platform. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */\n      \"uses-rel-preconnect\": \"`Preconnect` or `dns-prefetch` resource hints can be added by installing and configuring [a module](https://www.drupal.org/project/project_module?f%5B0%5D=&f%5B1%5D=&f%5B2%5D=&f%5B3%5D=&f%5B4%5D=sm_field_project_type%3Afull&f%5B5%5D=&f%5B6%5D=&text=Preconnect&solrsort=score+desc&op=Search) that provides facilities for user agent resource hints.\"\n    };\n    module2.exports = {\n      id: \"drupal\",\n      title: \"Drupal\",\n      icon,\n      UIStrings: UIStrings125\n    };\n  }\n});\n\n// node_modules/lighthouse-stack-packs/packs/ezoic.js\nvar require_ezoic = __commonJS({\n  \"node_modules/lighthouse-stack-packs/packs/ezoic.js\"(exports2, module2) {\n    init_process_global();\n    var icon = `data:image/svg+xml,<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 82 82\"><path fill=\"%235FA624\" fill-rule=\"evenodd\" d=\"M81.37 48.117C85.301 25.821 70.413 4.56 48.117.63 25.821-3.3 4.56 11.586.63 33.883-3.3 56.178 11.586 77.44 33.883 81.37 56.18 85.301 77.44 70.412 81.37 48.117Zm-8.935-14.17c2.77 12.357-1.942 25.721-12.96 33.436-14.57 10.203-34.656 6.662-44.859-7.909a32.434 32.434 0 0 1-2.869-4.98l28.7-20.097a6.53 6.53 0 1 0-3.744-5.347L9.564 48.054c-2.768-12.359 1.943-25.724 12.96-33.439 14.572-10.203 34.656-6.662 44.86 7.91a32.349 32.349 0 0 1 2.868 4.98L41.554 47.6a6.53 6.53 0 1 0 3.746 5.35l27.136-19.003Z\"/></svg>`;\n    var UIStrings125 = {\n      /** Additional description of a Lighthouse audit for a third-party framework called `Ezoic`. This is displayed after a user expands the section to see more. No character length limits. Ezoic Leap is Ezoic's site speed improvement toolset. Remove Unused CSS is a setting name. */\n      \"unused-css-rules\": \"Use [Ezoic Leap](https://pubdash.ezoic.com/leap) and enable `Remove Unused CSS` to help with this issue. It will identify the CSS classes that are actually used on each page of your site, and remove any others to keep the file size small.\",\n      /** Additional description of a Lighthouse audit for a third-party framework called `Ezoic`. This is displayed after a user expands the section to see more. No character length limits. Ezoic Leap is Ezoic's site speed improvement toolset. Next-Gen Formats is a setting name.*/\n      \"modern-image-formats\": \"Use [Ezoic Leap](https://pubdash.ezoic.com/leap) and enable `Next-Gen Formats` to convert images to WebP.\",\n      /** Additional description of a Lighthouse audit for a third-party framework called `Ezoic`. This is displayed after a user expands the section to see more. No character length limits. Ezoic Leap is Ezoic's site speed improvement toolset. Lazy Load Images is a setting name.*/\n      \"offscreen-images\": \"Use [Ezoic Leap](https://pubdash.ezoic.com/leap) and enable `Lazy Load Images` to defer loading off-screen images until they are needed.\",\n      /** Additional description of a Lighthouse audit for a third-party framework called `Ezoic`. This is displayed after a user expands the section to see more. No character length limits. Ezoic Leap is Ezoic's site speed improvement toolset. Script Delay is a setting name.*/\n      \"render-blocking-resources\": \"Use [Ezoic Leap](https://pubdash.ezoic.com/leap) and enable `Script Delay` to defer non-critical JS.\",\n      /** Additional description of a Lighthouse audit for a third-party framework called `Ezoic`. This is displayed after a user expands the section to see more. No character length limits. Ezoic Leap is Ezoic's site speed improvement toolset. Minify CSS is a setting name.*/\n      \"unminified-css\": \"Use [Ezoic Leap](https://pubdash.ezoic.com/leap) and enable `Minify CSS` to automatically minify your CSS to reduce network payload sizes.\",\n      /** Additional description of a Lighthouse audit for a third-party framework called `Ezoic`. This is displayed after a user expands the section to see more. No character length limits. Ezoic Leap is Ezoic's site speed improvement toolset. Minify Javascript is a setting name.*/\n      \"unminified-javascript\": \"Use [Ezoic Leap](https://pubdash.ezoic.com/leap) and enable `Minify Javascript` to automatically minify your JS to reduce network payload sizes.\",\n      /** Additional description of a Lighthouse audit for a third-party framework called `Ezoic`. This is displayed after a user expands the section to see more. No character length limits. Ezoic Leap is Ezoic's site speed improvement toolset. Efficient Static Cache Policy is a setting name.*/\n      \"uses-long-cache-ttl\": \"Use [Ezoic Leap](https://pubdash.ezoic.com/leap) and enable `Efficient Static Cache Policy` to set recommended values in the caching header for static assests.\",\n      /** Additional description of a Lighthouse audit for a third-party framework called `Ezoic`. This is displayed after a user expands the section to see more. No character length limits. Ezoic Leap is Ezoic's site speed improvement toolset. Next-Gen Formats is a setting name.*/\n      \"uses-optimized-images\": \"Use [Ezoic Leap](https://pubdash.ezoic.com/leap) and enable `Next-Gen Formats` to convert images to WebP.\",\n      /** Additional description of a Lighthouse audit for a third-party framework called `Ezoic`. This is displayed after a user expands the section to see more. No character length limits. Ezoic Leap is Ezoic's site speed improvement toolset. Resize Images is a setting name.*/\n      \"uses-responsive-images\": \"Use [Ezoic Leap](https://pubdash.ezoic.com/leap) and enable `Resize Images` to resize images to a device appropriate size, reducing network payload sizes.\",\n      /** Additional description of a Lighthouse audit for a third-party framework called `Ezoic`. This is displayed after a user expands the section to see more. No character length limits. Ezoic Cloud Caching is Ezoic's CDN.*/\n      \"server-response-time\": \"Use [Ezoic Cloud Caching](https://pubdash.ezoic.com/leap/caching) to cache your content across our world wide network, improving time to first byte.\",\n      /** Additional description of a Lighthouse audit for a third-party framework called `Ezoic`. This is displayed after a user expands the section to see more. No character length limits. Ezoic Leap is Ezoic's site speed improvement toolset. Pre-Connect Origins is a setting name.*/\n      \"uses-rel-preconnect\": \"Use [Ezoic Leap](https://pubdash.ezoic.com/leap) and enable `Pre-Connect Origins` to automatically add `preconnect` resource hints to establish early connections to important third-party origins.\",\n      /** Additional description of a Lighthouse audit for a third-party framework called `Ezoic`. This is displayed after a user expands the section to see more. No character length limits. Ezoic Leap is Ezoic's site speed improvement toolset. Preload Fonts and Preload Background Images are setting names.*/\n      \"uses-rel-preload\": \"Use [Ezoic Leap](https://pubdash.ezoic.com/leap) and enable `Preload Fonts` and `Preload Background Images` to add `preload` links to prioritize fetching resources that are currently requested later in page load.\",\n      /** Additional description of a Lighthouse audit for a third-party framework called `Ezoic`. This is displayed after a user expands the section to see more. No character length limits. Ezoic Leap is Ezoic's site speed improvement toolset. Optimize Fonts is a setting name.*/\n      \"font-display\": \"Use [Ezoic Leap](https://pubdash.ezoic.com/leap) and enable `Optimize Fonts` to automatically leverage the `font-display` CSS feature to ensure text is user-visible while webfonts are loading.\"\n    };\n    module2.exports = {\n      id: \"ezoic\",\n      title: \"Ezoic\",\n      icon,\n      UIStrings: UIStrings125\n    };\n  }\n});\n\n// node_modules/lighthouse-stack-packs/packs/gatsby.js\nvar require_gatsby = __commonJS({\n  \"node_modules/lighthouse-stack-packs/packs/gatsby.js\"(exports2, module2) {\n    init_process_global();\n    var icon = `data:image/svg+xml,<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 28 28\"><circle cx=\"14\" cy=\"14\" r=\"14\" fill=\"%23639\"/><path fill=\"%23fff\" d=\"M6.2 21.8C4.1 19.7 3 16.9 3 14.2L13.9 25c-2.8-.1-5.6-1.1-7.7-3.2zm10.2 2.9L3.3 11.6C4.4 6.7 8.8 3 14 3c3.7 0 6.9 1.8 8.9 4.5l-1.5 1.3C19.7 6.5 17 5 14 5c-3.9 0-7.2 2.5-8.5 6L17 22.5c2.9-1 5.1-3.5 5.8-6.5H18v-2h7c0 5.2-3.7 9.6-8.6 10.7z\"/></svg>`;\n    var UIStrings125 = {\n      /** Additional description of a Lighthouse audit that tells the user how they can remove unused CSS rules by configuring the Gatsby plugin `gatsby-plugin-purgecss` which sets up PurgeCSS */\n      \"unused-css-rules\": \"Use the `PurgeCSS` `Gatsby` plugin to remove unused rules from stylesheets. [Learn more](https://purgecss.com/plugins/gatsby.html).\",\n      /** Additional description of a Lighthouse audit that tells the user to use the gatsby-plugin-image component to automatically optimize image format */\n      \"modern-image-formats\": \"Use the `gatsby-plugin-image` component instead of `<img>` to automatically optimize image format. [Learn more](https://www.gatsbyjs.com/docs/how-to/images-and-media/using-gatsby-plugin-image).\",\n      /** Additional description of a Lighthouse audit that tells the user to defer loading images which are not shown on screen using the gatsby-plugin-image component */\n      \"offscreen-images\": \"Use the `gatsby-plugin-image` component instead of `<img>` to automatically lazy-load images. [Learn more](https://www.gatsbyjs.com/docs/how-to/images-and-media/using-gatsby-plugin-image).\",\n      /** Additional description of a Lighthouse audit that tells the user to use gatsby-script to defer loading of non-critical third-party libraries */\n      \"render-blocking-resources\": \"Use the `Gatsby Script API` to defer loading of non-critical third-party scripts. [Learn more](https://www.gatsbyjs.com/docs/reference/built-in-components/gatsby-script/).\",\n      /** Additional description of a Lighthouse audit that tells the user to use Webpack Bundle Analyzer to discover JavaScript code that is not used */\n      \"unused-javascript\": \"Use `Webpack Bundle Analyzer` to detect unused JavaScript code. [Learn more](https://www.gatsbyjs.com/plugins/gatsby-plugin-webpack-bundle-analyser-v2/)\",\n      /** Additional description of a Lighthouse audit that tells the user to enable caching for assets (e.g. images) and artifacts that don't change between deployments */\n      \"uses-long-cache-ttl\": \"Configure caching for immutable assets. [Learn more](https://www.gatsbyjs.com/docs/how-to/previews-deploys-hosting/caching/).\",\n      /** Additional description of a Lighthouse audit that tells the user to use the gatsby-plugin-image component to adjust image quality */\n      \"uses-optimized-images\": \"Use the `gatsby-plugin-image` component instead of `<img>` to adjust image quality. [Learn more](https://www.gatsbyjs.com/docs/how-to/images-and-media/using-gatsby-plugin-image).\",\n      /** Additional description of a Lighthouse audit that tells the user to serve responsive images using the gatsby-plugin-image component with appropriate `sizes` set */\n      \"uses-responsive-images\": \"Use the `gatsby-plugin-image` component to set appropriate `sizes`. [Learn more](https://www.gatsbyjs.com/docs/how-to/images-and-media/using-gatsby-plugin-image).\",\n      /** Additional description of a Lighthouse audit that tells the user to use the gatsby-plugin-image component to automatically preload LCP images. \"prop\" is short for \"property\" */\n      \"prioritize-lcp-image\": \"Use the `gatsby-plugin-image` component and set the `loading` prop to `eager`. [Learn more](https://www.gatsbyjs.com/docs/reference/built-in-components/gatsby-plugin-image#shared-props).\"\n    };\n    module2.exports = {\n      id: \"gatsby\",\n      title: \"Gatsby\",\n      icon,\n      UIStrings: UIStrings125\n    };\n  }\n});\n\n// node_modules/lighthouse-stack-packs/packs/joomla.js\nvar require_joomla = __commonJS({\n  \"node_modules/lighthouse-stack-packs/packs/joomla.js\"(exports2, module2) {\n    \"use strict\";\n    init_process_global();\n    /**\n     * @license Copyright 2020 The Lighthouse Authors. All Rights Reserved.\n     * Licensed under the Apache License, Version 2.0 (the 'License'); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0\n     * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.\n     */\n    var icon = `data:image/svg+xml,<svg xmlns=\"http://www.w3.org/2000/svg\" preserveAspectRatio=\"xMidYMid\" viewBox=\"0 0 256 258\"><path fill=\"%23F9AE41\" d=\"M255.7 35.6a33.7 33.7 0 0 0-67-4.8l-.4-.2c-27.6-12.4-50.8 9.6-50.8 9.6l-61.4 61.7 24.3 23.4 49.4-48.6c23-23 35.6-7.4 35.6-7.4 17.4 14.6.6 32 .6 32l24.9 24c20.3-22 21.5-41.1 15.3-56.3a33.7 33.7 0 0 0 29.5-33.4\"/><path fill=\"%23EE4035\" d=\"m226.5 190.5.2-.3c12.4-27.6-9.6-50.8-9.6-50.8L155.4 78l-23.3 24.3 48.5 49.4c23 23 7.5 35.6 7.5 35.6-14.7 17.4-32 .6-32 .6l-24 24.9c21.9 20.3 41 21.5 56.2 15.3a33.7 33.7 0 1 0 38.2-37.6\"/><path fill=\"%234F91CD\" d=\"m156 133-49.5 48.6c-23 23-35.6 7.4-35.6 7.4-17.4-14.6-.6-32-.6-32l-24.9-24c-20.3 22-21.4 41.1-15.3 56.3a33.7 33.7 0 1 0 37.6 38.2l.3.2c27.6 12.4 50.8-9.6 50.8-9.6l61.4-61.7-24.3-23.4\"/><path fill=\"%237AC043\" d=\"M75.7 106.6c-23-23-7.4-35.6-7.4-35.6 14.6-17.4 32-.6 32-.6l24-24.9c-22-20.3-41-21.5-56.3-15.3a33.7 33.7 0 1 0-38.2 37.6l-.2.3C17.2 95.7 39.2 119 39.2 119l61.7 61.4 23.4-24.3-48.6-49.4\"/\\\n></svg>`;\n    var UIStrings125 = {\n      /** Additional description of a Lighthouse audit that tells the user how they can improve performance by removing unused CSS, in the context of the Joomla CMS platform. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */\n      \"unused-css-rules\": \"Consider reducing, or switching, the number of [Joomla extensions](https://extensions.joomla.org/) loading unused CSS in your page. To identify extensions that are adding extraneous CSS, try running [code coverage](https://developers.google.com/web/updates/2017/04/devtools-release-notes#coverage) in Chrome DevTools. You can identify the theme/plugin responsible from the URL of the stylesheet. Look out for plugins that have many stylesheets in the list which have a lot of red in code coverage. A plugin should only enqueue a stylesheet if it is actually used on the page.\",\n      /** Additional description of a Lighthouse audit that tells the user how they can improve image loading by using webp in the context of the Joomla CMS platform. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */\n      \"modern-image-formats\": \"Consider using a [plugin](https://extensions.joomla.org/instant-search/?jed_live%5Bquery%5D=webp) or service that will automatically convert your uploaded images to the optimal formats.\",\n      /** Additional description of a Lighthouse audit that tells the user how they can improve performance by lazy loading images that are initially offscreen in the context of the Joomla CMS platform. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */\n      \"offscreen-images\": \"Install a [lazy-load Joomla plugin](https://extensions.joomla.org/instant-search/?jed_live%5Bquery%5D=lazy%20loading) that provides the ability to defer any offscreen images, or switch to a template that provides that functionality. Starting with Joomla 4.0, all new images will [automatically](https://github.com/joomla/joomla-cms/pull/30748) get the `loading` attribute from the core.\",\n      /** Additional description of a Lighthouse audit that tells the user how they can improve site loading performance by reducing the total bytes delivered by their page in the context of the Joomla CMS platform. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */\n      \"total-byte-weight\": \"Consider showing excerpts in your article categories (e.g. via the read more link), reducing the number of articles shown on a given page, breaking your long posts into multiple pages, or using a plugin to lazy-load comments.\",\n      /** Additional description of a Lighthouse audit that tells the user how they can improve performance by reducing the amount of render blocking resources present on their page, in the context of the Joomla CMS platform. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */\n      \"render-blocking-resources\": \"There are a number of Joomla plugins that can help you [inline critical assets](https://extensions.joomla.org/instant-search/?jed_live%5Bquery%5D=performance) or [defer less important resources](https://extensions.joomla.org/instant-search/?jed_live%5Bquery%5D=performance). Beware that optimizations provided by these plugins may break features of your templates or plugins, so you will need to test these thoroughly.\",\n      /** Additional description of a Lighthouse audit that tells the user how they can improve performance by minifying their CSS files in the context of the Joomla CMS platform. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */\n      \"unminified-css\": \"A number of [Joomla extensions](https://extensions.joomla.org/instant-search/?jed_live%5Bquery%5D=performance) can speed up your site by concatenating, minifying, and compressing your css styles. There are also templates that provide this functionality.\",\n      /** Additional description of a Lighthouse audit that tells the user how they can improve performance by minifying their Javascript files in the context of the Joomla CMS platform. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */\n      \"unminified-javascript\": \"A number of [Joomla extensions](https://extensions.joomla.org/instant-search/?jed_live%5Bquery%5D=performance) can speed up your site by concatenating, minifying, and compressing your scripts. There are also templates that provide this functionality.\",\n      /** Additional description of a Lighthouse audit that tells the user how they can improve performance by encoding animated images as video, in the context of the Joomla CMS platform. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */\n      \"efficient-animated-content\": \"Consider uploading your GIF to a service which will make it available to embed as an HTML5 video.\",\n      /** Additional description of a Lighthouse audit that tells the user how they can improve performance by removing unused Javascript files in the context of the Joomla CMS platform. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */\n      \"unused-javascript\": \"Consider reducing, or switching, the number of [Joomla extensions](https://extensions.joomla.org/) loading unused JavaScript in your page. To identify plugins that are adding extraneous JS, try running [code coverage](https://developers.google.com/web/updates/2017/04/devtools-release-notes#coverage) in Chrome DevTools. You can identify the extension responsible from the URL of the script. Look out for extensions that have many scripts in the list which have a lot of red in code coverage. An extension should only enqueue a script if it is actually used on the page.\",\n      /** Additional description of a Lighthouse audit that tells the user how they can improve their site by enabling long caching in the context of the Joomla CMS platform. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */\n      \"uses-long-cache-ttl\": \"Read about [Browser Caching in Joomla](https://docs.joomla.org/Cache).\",\n      /** Additional description of a Lighthouse audit that tells the user how they can improve site performance by optimizing images, in the context of the Joomla CMS platform. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */\n      \"uses-optimized-images\": \"Consider using an [image optimization plugin](https://extensions.joomla.org/instant-search/?jed_live%5Bquery%5D=performance) that compresses your images while retaining quality.\",\n      /** Additional description of a Lighthouse audit that tells the user how they can improve performance via enabling text compression in the context of the Joomla CMS platform. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */\n      \"uses-text-compression\": \"You can enable text compression by enabling Gzip Page Compression in Joomla (System > Global configuration > Server).\",\n      /** Additional description of a Lighthouse audit that tells the user how they can improve performance by using responsive images in the context of the Joomla CMS platform. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */\n      \"uses-responsive-images\": \"Consider using a [responsive images plugin](https://extensions.joomla.org/instant-search/?jed_live%5Bquery%5D=responsive%20images) to use responsive images in your content.\",\n      /** Additional description of a Lighthouse audit that tells the user how they can improve the server-response-time speed metric, in the context of the Joomla CMS platform. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */\n      \"server-response-time\": \"Templates, extensions, and server specifications all contribute to server response time. Consider finding a more optimized template, carefully selecting an optimization extension, and/or upgrading your server.\"\n    };\n    module2.exports = {\n      id: \"joomla\",\n      title: \"Joomla\",\n      icon,\n      UIStrings: UIStrings125\n    };\n  }\n});\n\n// node_modules/lighthouse-stack-packs/packs/magento.js\nvar require_magento = __commonJS({\n  \"node_modules/lighthouse-stack-packs/packs/magento.js\"(exports2, module2) {\n    init_process_global();\n    var icon = `data:image/svg+xml,<svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"%23f26322\" viewBox=\"0 0 1000 1000\"><path d=\"M916.9 267.4v465.3l-111.3 67.4V331.4l-1.5-.9-303.9-189-304.6 189.2-1.2.8V799L83.1 732.6V267.4l.7-.4L500.3 10l416 257 .6.4zM560.7 468.5v383.3L500.3 890l-61-38.2V306.7l-136 84.3v476.6l197 122.5 196.4-122.5V391l-136-84.3v161.8z\"/></svg>`;\n    var UIStrings125 = {\n      /** Additional description of a Lighthouse audit that tells the user how they can improve image loading by using webp in the context of the Magento platform. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */\n      \"modern-image-formats\": \"Consider searching the [Magento Marketplace](https://marketplace.magento.com/catalogsearch/result/?q=webp) for a variety of third-party extensions to leverage newer image formats.\",\n      /** Additional description of a Lighthouse audit that tells the user how they can improve performance by lazy loading images that are initially offscreen in the context of the Magento platform. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */\n      \"offscreen-images\": \"Consider modifying your product and catalog templates to make use of the web platform's [lazy loading](https://web.dev/native-lazy-loading) feature.\",\n      /** Additional description of a Lighthouse audit that tells the user how they can improve site loading performance by disabling JS bundling in the context of the Magento platform. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */\n      \"disable-bundling\": \"Disable Magento's built-in [JavaScript bundling and minification](https://devdocs.magento.com/guides/v2.3/frontend-dev-guide/themes/js-bundling.html), and consider using [baler](https://github.com/magento/baler/) instead.\",\n      /** Additional description of a Lighthouse audit that tells the user how they can improve performance by minifying their CSS files in the context of the Magento platform. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */\n      \"unminified-css\": `Enable the \"Minify CSS Files\" option in your store's Developer settings. [Learn more](https://devdocs.magento.com/guides/v2.3/performance-best-practices/configuration.html?itm_source=devdocs&itm_medium=search_page&itm_campaign=federated_search&itm_term=minify%20css%20files).`,\n      /** Additional description of a Lighthouse audit that tells the user how they can improve performance by minifying their Javascript files in the context of the Magento platform. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */\n      \"unminified-javascript\": \"Use [Terser](https://www.npmjs.com/package/terser) to minify all JavaScript assets from static content deployment, and disable the built-in minification feature.\",\n      /** Additional description of a Lighthouse audit that tells the user how they can improve performance by removing unused Javascript files in the context of the Magento platform. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */\n      \"unused-javascript\": \"Disable Magento's built-in [JavaScript bundling](https://devdocs.magento.com/guides/v2.3/frontend-dev-guide/themes/js-bundling.html).\",\n      /** Additional description of a Lighthouse audit that tells the user how they can improve site performance by optimizing images, in the context of the Magento platform. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */\n      \"uses-optimized-images\": \"Consider searching the [Magento Marketplace](https://marketplace.magento.com/catalogsearch/result/?q=optimize%20image) for a variety of third party extensions to optimize images.\",\n      /** Additional description of a Lighthouse audit that tells the user how they can improve the time to first byte speed metric, in the context of the Magento platform. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */\n      \"server-response-time\": \"Use Magento's [Varnish integration](https://devdocs.magento.com/guides/v2.3/config-guide/varnish/config-varnish.html).\",\n      /** Additional description of a Lighthouse audit that tells the user how they can add preconnect or dns-prefetch resource hints, in the context of the Magento platform. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */\n      \"uses-rel-preconnect\": \"Preconnect or dns-prefetch resource hints can be added by [modifying a themes's layout](https://devdocs.magento.com/guides/v2.3/frontend-dev-guide/layouts/xml-manage.html).\",\n      /** Additional description of a Lighthouse audit that tells the user how they can add preload tags, in the context of the Magento platform. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */\n      \"uses-rel-preload\": \"`<link rel=preload>` tags can be added by [modifying a themes's layout](https://devdocs.magento.com/guides/v2.3/frontend-dev-guide/layouts/xml-manage.html).\",\n      /** Additional description of a Lighthouse audit that tells the user how they can minimize critical request chains, in the context of the Magento platform. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */\n      \"critical-request-chains\": \"If you are not bundling your JavaScript assets, consider using [baler](https://github.com/magento/baler).\",\n      /** Additional description of a Lighthouse audit that tells the user how they can specify font-display, in the context of the Magento platform. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */\n      \"font-display\": \"Specify `@font-display` when [defining custom fonts](https://devdocs.magento.com/guides/v2.3/frontend-dev-guide/css-topics/using-fonts.html).\"\n    };\n    module2.exports = {\n      id: \"magento\",\n      title: \"Magento\",\n      icon,\n      UIStrings: UIStrings125\n    };\n  }\n});\n\n// node_modules/lighthouse-stack-packs/packs/next.js\nvar require_next = __commonJS({\n  \"node_modules/lighthouse-stack-packs/packs/next.js\"(exports2, module2) {\n    init_process_global();\n    var icon = `data:image/svg+xml,<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 207 124\"><path fill=\"%23000\" d=\"M48.942 32.632h38.96v3.082h-35.39v23.193H85.79v3.082H52.513v25.464h35.794v3.081H48.942V32.632Zm42.45 0h4.139l18.343 25.464 18.749-25.464L158.124.287l-41.896 60.485 21.59 29.762h-4.302l-19.642-27.086L94.15 90.534h-4.22l21.751-29.762-20.29-28.14Zm47.967 3.082v-3.082h44.397v3.082h-20.453v54.82h-3.571v-54.82h-20.373ZM.203 32.632h4.464l61.557 91.671-25.439-33.769L3.936 37.011l-.162 53.523H.203zm183.194 53.891c.738 0 1.276-.563 1.276-1.29 0-.727-.538-1.29-1.276-1.29-.73 0-1.277.563-1.277 1.29 0 .727.547 1.29 1.277 1.29Zm3.509-3.393c0 2.146 1.555 3.549 3.822 3.549 2.414 0 3.874-1.446 3.874-3.956v-8.837h-1.946v8.828c0 1.394-.704 2.138-1.946 2.138-1.112 0-1.867-.692-1.893-1.722h-1.911Zm10.24-.113c.14 2.233 2.007 3.662 4.787 3.662 2.97 0 4.83-1.498 4.83-3.887 0-1.878-1.06-2.917-3.632-3.514l-1.38-.338c-1.634-.38-2.294-.891-2.294-1.783 0-1.125 1.025-1.86 2.563-1.86 1.459 0 2.466.\\\n718 2.649 1.869h1.893c-.113-2.103-1.971-3.583-4.516-3.583-2.737 0-4.56 1.48-4.56 3.704 0 1.835 1.033 2.926 3.3 3.454l1.616.39c1.659.389 2.388.96 2.388 1.912 0 1.108-1.146 1.913-2.71 1.913-1.676 0-2.84-.753-3.005-1.939h-1.928Z\"/></svg>`;\n    var UIStrings125 = {\n      /** Additional description of a Lighthouse audit that tells the user how they can remove unusused CSS rules by configuring a plugin named PurgeCSS. */\n      \"unused-css-rules\": \"Consider setting up `PurgeCSS` in `Next.js` configuration to remove unused rules from stylesheets. [Learn more](https://purgecss.com/guides/next.html).\",\n      /** Additional description of a Lighthouse audit that tells the user to use the next/image component to automatically optimize image format. */\n      \"modern-image-formats\": \"Use the `next/image` component instead of `<img>` to automatically optimize image format. [Learn more](https://nextjs.org/docs/app/getting-started/images).\",\n      /** Additional description of a Lighthouse audit that tells the user to defer loading images which are not shown on screen using the next/image component. */\n      \"offscreen-images\": \"Use the `next/image` component instead of `<img>` to automatically lazy-load images. [Learn more](https://nextjs.org/docs/app/getting-started/images).\",\n      /** Additional description of a Lighthouse audit that tells the user to use next/script to defer loading of non-critical third-party libraries. */\n      \"render-blocking-resources\": \"Use the `next/script` component to defer loading of non-critical third-party scripts. [Learn more](https://nextjs.org/docs/app/guides/scripts).\",\n      /** Additional description of a Lighthouse audit that tells the user to use Webpack Bundle Analyzer to discover JavaScript code that is not used. */\n      \"unused-javascript\": \"Use `Webpack Bundle Analyzer` to detect unused JavaScript code. [Learn more](https://github.com/vercel/next.js/tree/canary/packages/next-bundle-analyzer)\",\n      /** Additional description of a Lighthouse audit that tells the user to enable caching for assets (e.g. images) and server-side rendered (SSR) pages that don't change between deployments. */\n      \"uses-long-cache-ttl\": \"Configure caching for immutable assets and `Server-side Rendered` (SSR) pages. [Learn more](https://nextjs.org/docs/13/pages/building-your-application/deploying/production-checklist#caching).\",\n      /** Additional description of a Lighthouse audit that tells the user to use the next/image component to adjust image quality. */\n      \"uses-optimized-images\": \"Use the `next/image` component instead of `<img>` to adjust image quality. [Learn more](https://nextjs.org/docs/app/getting-started/images).\",\n      /** Additional description of a Lighthouse audit that tells the user to enable compression (gzip, brotli) on their servers. */\n      \"uses-text-compression\": \"Enable compression on your Next.js server. [Learn more](https://nextjs.org/docs/api-reference/next.config.js/compression).\",\n      /** Additional description of a Lighthouse audit that tells the user to serve responsive images using the next/image component with appropriate `sizes` set. */\n      \"uses-responsive-images\": \"Use the `next/image` component to set the appropriate `sizes`. [Learn more](https://nextjs.org/docs/api-reference/next/image#sizes).\",\n      /** Additional description of a Lighthouse audit that tells the user to analyze the performance of their applications using Next.js Analytics. */\n      \"user-timings\": \"Consider using `Next.js Analytics` to measure your app's real-world performance. [Learn more](https://nextjs.org/docs/pages/guides/analytics).\",\n      /** Additional description of a Lighthouse audit that tells the user to use the next/image component to automatically preload LCP images. */\n      \"prioritize-lcp-image\": 'Use the `next/image` component and set \"priority\" to true to preload LCP image. [Learn more](https://nextjs.org/docs/api-reference/next/image#priority).',\n      /** Additional description of a Lighthouse audit that tells the user to use the next/image component to make sure `width` and `height` of image elements are always specified. */\n      \"unsized-images\": \"Use the `next/image` component to make sure images are always sized appropriately. [Learn more](https://nextjs.org/docs/api-reference/next/image#width).\"\n    };\n    module2.exports = {\n      id: \"next.js\",\n      title: \"Next.js\",\n      icon,\n      UIStrings: UIStrings125\n    };\n  }\n});\n\n// node_modules/lighthouse-stack-packs/packs/nitropack.js\nvar require_nitropack = __commonJS({\n  \"node_modules/lighthouse-stack-packs/packs/nitropack.js\"(exports2, module2) {\n    init_process_global();\n    var icon = `data:image/svg+xml,<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"142\" height=\"54\"><g fill=\"none\" fill-rule=\"evenodd\"><g fill=\"%231B004E\"><path d=\"M19.486 53.24h-3.891L4.682 39.247v13.936H0V32.946h5.444l9.475 12.398V32.946h4.567zM21.346 32.94h4.647v3.57h-4.647v-3.57Zm0 5.477h4.647V53.18h-4.647V38.417ZM40.569 53.183H36c-3.408 0-4.991-1.625-4.991-4.697v-6.22h-3.777V38.42h3.777v-5.474h4.598v5.474h4.958v3.846h-4.958v4.588c0 1.597.477 2.252 2.197 2.252h2.764v4.077ZM46.688 53.183h-4.57V38.42h4.57v2.308c.31-.686 1.351-2.336 4.425-2.336h3.13v4.56h-4.004c-2.593 0-3.55.967-3.55 3.019v7.212ZM70.612 45.802c0 4.56-3.409 7.75-8.01 7.75s-8.006-3.19-8.006-7.75c0-4.56 3.408-7.755 8.006-7.755 4.598 0 8.01 3.195 8.01 7.755Zm-4.599 0c0-2.14-1.35-3.733-3.408-3.733-2.057 0-3.44 1.594-3.44 3.733 0 2.139 1.41 3.733 3.44 3.733 2.03 0 3.408-1.598 3.408-3.733ZM72.47 32.946h11.7c4.543 0 7.192 2.28 7.192 6.526 0 4.247-2.649 6.577-7.191 6.577h-6.935v7.125h-4.765V32.946Zm4.766 4.218v4.676h6.485c1.832\\\n 0 2.736-.883 2.736-2.34 0-1.565-.904-2.336-2.736-2.336h-6.485ZM102.662 51.016c-.254.485-1.636 2.48-4.71 2.48-3.665 0-6.627-2.906-6.627-7.694 0-4.789 2.962-7.667 6.656-7.667 2.962 0 4.372 1.851 4.626 2.336v-2.05h4.567v14.762h-4.512v-2.167Zm-3.327-8.932c-2.03 0-3.384 1.594-3.384 3.733 0 2.14 1.354 3.733 3.384 3.733s3.327-1.597 3.327-3.733-1.298-3.733-3.327-3.733ZM119.184 43.578a2.98 2.98 0 0 0-2.749-1.494c-1.918 0-3.13 1.594-3.13 3.733 0 2.14 1.24 3.758 3.158 3.758 1.807 0 2.625-1.168 2.764-1.51h4.4c-.143 2.052-2.116 5.5-7.275 5.5-4.286 0-7.641-3.078-7.641-7.75 0-4.673 3.328-7.755 7.585-7.755 5.159 0 7.105 3.392 7.33 5.53l-4.442-.012ZM129.712 46.6v6.577h-4.567V32.194h4.567v11.998l5.838-5.784h5.751l-6.994 6.811 7.362 7.952h-5.921z\"/></g><g fill=\"%2325F5CE\"><path d=\"M49.159 4.65c12.832 0 23.235 10.41 23.235 23.251h4.648C77.042 12.491 64.558 0 49.159 0c-15.4 0-27.883 12.492-27.883 27.901h4.647c0-12.841 10.403-23.25 23.236-23.25Z\"/><path d=\"M44.852 25.793a3.632 3.632 0 0 1 2.6-5.097L63.8 16\\\n.951 50.426 27.09a3.626 3.626 0 0 1-5.574-1.296Z\"/></g></g></svg>`;\n    var UIStrings125 = {\n      /** Additional description of a Lighthouse audit for a third-party framework called `NitroPack`. This is displayed after a user expands the section to see more. No character length limits. `Reduce Unused CSS` is the name of a feature and becomes link text to additional documentation.*/\n      \"unused-css-rules\": \"Enable [`Reduce Unused CSS`](https://support.nitropack.io/hc/en-us/articles/360020418457-Reduce-Unused-CSS) to remove CSS rules that are not applicable to this page.\",\n      /** Additional description of a Lighthouse audit for a third-party framework called `NitroPack`. This is displayed after a user expands the section to see more. No character length limits. `Image Optimization` is the name of a feature and becomes link text to additional documentation. `WebP` is the name of a standardized image format for the web.*/\n      \"modern-image-formats\": \"Use [`Image Optimization`](https://support.nitropack.io/hc/en-us/articles/16547237162513) to automatically convert your images to WebP.\",\n      /** Additional description of a Lighthouse audit for a third-party framework called `NitroPack`. This is displayed after a user expands the section to see more. No character length limits. `Automatic Image Lazy Loading` is the name of a feature and becomes link text to additional documentation.*/\n      \"offscreen-images\": \"Defer offscreen images by enabling [`Automatic Image Lazy Loading`](https://support.nitropack.io/hc/en-us/articles/12457493524369-NitroPack-Lazy-Loading-Feature-for-Images).\",\n      /** Additional description of a Lighthouse audit for a third-party framework called `NitroPack`. This is displayed after a user expands the section to see more. No character length limits. `Remove render-blocking resources` is the name of a feature and becomes link text to additional documentation.*/\n      \"render-blocking-resources\": \"Enable [`Remove render-blocking resources`](https://support.nitropack.io/hc/en-us/articles/13820893500049-How-to-Deal-with-Render-Blocking-Resources-in-NitroPack) in NitroPack for faster initial load times.\",\n      /** Additional description of a Lighthouse audit for a third-party framework called `NitroPack`. This is displayed after a user expands the section to see more. No character length limits. `Minify resources` is the name of a feature and becomes link text to additional documentation.*/\n      \"unminified-css\": \"Enable [`Minify resources`](https://support.nitropack.io/hc/en-us/articles/360061059394-Minify-Resources) in your Caching settings to reduce the size of your CSS, HTML, and JavaScript files for faster load times.\",\n      /** Additional description of a Lighthouse audit for a third-party framework called `NitroPack`. This is displayed after a user expands the section to see more. No character length limits. `Minify resources` is the name of a feature and becomes link text to additional documentation.*/\n      \"unminified-javascript\": \"Enable [`Minify resources`](https://support.nitropack.io/hc/en-us/articles/360061059394-Minify-Resources) in your Caching settings to reduce the size of your JS, HTML, and CSS files for faster load times.\",\n      /** Additional description of a Lighthouse audit for a third-party framework called `NitroPack`. This is displayed after a user expands the section to see more. No character length limits. `Delayed Scripts` is the name of a feature and becomes link text to additional documentation.*/\n      \"unused-javascript\": \"Configure [`Delayed Scripts`](https://support.nitropack.io/hc/en-us/articles/1500002600942-Delayed-Scripts) in NitroPack to delay loading of scripts until they are needed.\",\n      /** Additional description of a Lighthouse audit for a third-party framework called `NitroPack`. This is displayed after a user expands the section to see more. No character length limits. `Improve Server Response Time` is the name of a feature and becomes link text to additional documentation.*/\n      \"uses-long-cache-ttl\": \"Go to the [`Improve Server Response Time`](https://support.nitropack.io/hc/en-us/articles/1500002321821-Improve-Server-Response-Time) feature in the `Caching` menu and adjust your page cache expiration time to improve loading times and user experience.\",\n      /** Additional description of a Lighthouse audit for a third-party framework called `NitroPack`. This is displayed after a user expands the section to see more. No character length limits. `Image Optimization` is the name of a feature and becomes link text to additional documentation.*/\n      \"uses-optimized-images\": \"Automatically compress, optimize, and convert your images into WebP by enabling the [`Image Optimization`](https://support.nitropack.io/hc/en-us/articles/14177271695121-How-to-serve-images-in-next-gen-formats-using-NitroPack) setting.\",\n      /** Additional description of a Lighthouse audit for a third-party framework called `NitroPack`. This is displayed after a user expands the section to see more. No character length limits. `Adaptive Image Sizing` is the name of a feature and becomes link text to additional documentation.*/\n      \"uses-responsive-images\": \"Enable [`Adaptive Image Sizing`](https://support.nitropack.io/hc/en-us/articles/10123833029905-How-to-Enable-Adaptive-Image-Sizing-For-Your-Site) to preemptively optimize your images and make them match the dimensions of the containers they’re displayed in across all devices.\",\n      /** Additional description of a Lighthouse audit for a third-party framework called `NitroPack`. This is displayed after a user expands the section to see more. No character length limits. `HTML Lazy Load` is the name of a feature.*/\n      \"dom-size\": \"Contact your account manager to enable [`HTML Lazy Load`](https://support.nitropack.io/hc/en-us/articles/17144942904337). Configuring it will prioritize and optimize your page rendering performance.\",\n      /** Additional description of a Lighthouse audit for a third-party framework called `NitroPack`. This is displayed after a user expands the section to see more. No character length limits. `Override Font Rendering Behavior` is the name of a feature and becomes link text to additional documentation.*/\n      \"font-display\": \"Use the [`Override Font Rendering Behavior`](https://support.nitropack.io/hc/en-us/articles/16547358865041) option in NitroPack to set a desired value for the CSS font-display rule.\"\n    };\n    module2.exports = {\n      id: \"nitropack\",\n      title: \"NitroPack\",\n      icon,\n      UIStrings: UIStrings125\n    };\n  }\n});\n\n// node_modules/lighthouse-stack-packs/packs/nuxt.js\nvar require_nuxt = __commonJS({\n  \"node_modules/lighthouse-stack-packs/packs/nuxt.js\"(exports2, module2) {\n    init_process_global();\n    var icon = `data:image/svg+xml,<svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 512 512\"><path fill=\"%2300DC82\" d=\"M281.44 397.667h156.88c5.006 0 9.798-1.759 14.133-4.244.336-2.481 8.805-5.596 11.307-9.894 2.502-4.297 4.242-9.173 4.24-14.134-.002-4.962-1.734-9.836-4.24-14.131l-106-182.321c-2.502-4.297-5.559-7.413-9.893-9.894-4.335-2.48-10.542-4.24-15.547-4.24-5.005 0-9.799 1.76-14.133 4.24-4.335 2.481-7.392 5.597-9.894 9.894l-26.853 46.64-53.707-90.457c-2.504-4.296-5.557-8.823-9.893-11.303-4.336-2.481-9.127-2.827-14.133-2.827-5.006 0-9.798.346-14.134 2.827-4.335 2.48-8.802 7.007-11.306 11.303L46.827 355.268c-2.506 4.295-2.8259.169-2.827 14.131-.002 4.961.325 9.836 2.827 14.134 2.502 4.297 6.97 7.413 11.306 9.894 4.336 2.481 9.127 4.24 14.134 4.24H171.2c39.201 0 67.734-17.585 87.627-50.88L306.88 263.4l25.44-43.813 77.733 132.853H306.88l-25.44 45.227ZM169.787 352.44h-69.254l103.174-178.08L256 263.4l-34.639 60.384c-13.21 21.603-28.272 28.656-51.574 28.656Z\"/></svg>`;\n    var UIStrings125 = {\n      /** Additional description of a Lighthouse audit that tells the user to use the nuxt/image component to serve modern formats like WebP. */\n      \"modern-image-formats\": 'Use the `nuxt/image` component and set `format=\"webp\"`. [Learn more](https://image.nuxt.com/usage/nuxt-img#format).',\n      /** Additional description of a Lighthouse audit that tells the user to use the nuxt/image component to defer loading images which are not shown on screen. */\n      \"offscreen-images\": 'Use the `nuxt/image` component and set `loading=\"lazy\"` for offscreen images. [Learn more](https://image.nuxt.com/usage/nuxt-img#loading).',\n      /** Additional description of a Lighthouse audit that tells the user to use the nuxt/image component to automatically compress their images. */\n      \"uses-optimized-images\": \"Use the `nuxt/image` component and set the appropriate `quality`. [Learn more](https://image.nuxt.com/usage/nuxt-img#quality).\",\n      /** Additional description of a Lighthouse audit that tells the user to use the nuxt/image component to serve appropriately sized images to different devices. */\n      \"uses-responsive-images\": \"Use the `nuxt/image` component and set the appropriate `sizes`. [Learn more](https://image.nuxt.com/usage/nuxt-img#sizes).\",\n      /** Additional description of a Lighthouse audit that tells the user to use the nuxt/image component to prioritize the loading of the image that is part of the Largest Contentful Paint (LCP). */\n      \"prioritize-lcp-image\": \"Use the `nuxt/image` component and specify `preload` for LCP image. [Learn more](https://image.nuxt.com/usage/nuxt-img#preload).\",\n      /** Additional description of a Lighthouse audit that tells the user to use the nuxt/image component to provide explicit `width` and `height` for images to prevent layout shift. */\n      \"unsized-images\": \"Use the `nuxt/image` component and specify explicit `width` and `height`. [Learn more](https://image.nuxt.com/usage/nuxt-img#width-height).\"\n    };\n    module2.exports = {\n      id: \"nuxt\",\n      title: \"Nuxt\",\n      icon,\n      UIStrings: UIStrings125\n    };\n  }\n});\n\n// node_modules/lighthouse-stack-packs/packs/octobercms.js\nvar require_octobercms = __commonJS({\n  \"node_modules/lighthouse-stack-packs/packs/octobercms.js\"(exports2, module2) {\n    init_process_global();\n    var icon = `data:image/svg+xml,<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 310 310\"><path fill=\"none\" d=\"M-1-1h802v602H-1z\"/><path fill=\"%23de6c26\" d=\"M135 6.9c-14.2 4.4-34.9 21.8-49.9 42C55.8 88.5 39.6 135.8 41.4 177c.8 20.2 4.9 35.5 14.4 54.5 13.6 27.4 40.8 55.1 65.5 66.9 14.1 6.7 13.4 6.9 14.1-2.8.3-4.4 1-32.4 1.6-62.1 2.7-137.3 4.4-176 8.2-191.3.6-2.3 1.4-4.2 1.9-4.2 1.2 0 3.6 9.1 4.9 18.3.5 4.3 1 17.7 1 29.8 0 12 .3 21.9.7 21.9.3 0 5.7-5 11.9-11 6.9-6.8 12-11 13.3-11 1.8 0 1.9.3 1 2.7-1.2 3.1-7.9 13.2-19.1 28.5L153 128l.1 31.2c.1 17.2.4 37.4.8 44.9l.6 13.7 11-12.6c14-16 35.1-37.1 39.5-39.6l3.3-1.9-.6 3.2c-2 9.8-9.5 20.7-37.4 54.3L154 240.8v31.1c0 18.3.4 31.1.9 31.1 2.8 0 19.3-6.4 26.8-10.5 13.8-7.3 23.8-15 38.3-29.5 15.7-15.7 24.4-27.4 33.4-45.2 20.5-40 21-80.3 1.6-119-17.8-35.6-54.6-72.1-87.8-86.9-11.7-5.3-24.6-7.3-32.2-5z\"/></svg>`;\n    var UIStrings125 = {\n      /** Additional description of a Lighthouse audit that tells the user how they can improve performance by removing unused CSS, in the context of the October CMS platform. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */\n      \"unused-css-rules\": \"Consider reviewing the [plugins](https://octobercms.com/plugins) loading unused CSS on the website. To identify plugins that add unnecessary CSS, run [code coverage](https://developers.google.com/web/updates/2017/04/devtools-release-notes#coverage) in Chrome DevTools. Identify the theme/plugin responsible from the stylesheet URL. Look for plugins with many stylesheets with lots of red in code coverage. A plugin should only add a stylesheet if it is actually used on the web page.\",\n      /** Additional description of a Lighthouse audit that tells the user how they can improve image loading by using webp in the context of the October CMS platform. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */\n      \"modern-image-formats\": \"Consider using a [plugin](https://octobercms.com/plugins?search=image) or service that will automatically convert the uploaded images to the optimal formats. [WebP lossless images](https://developers.google.com/speed/webp) are 26% smaller in size compared to PNGs and 25-34% smaller than comparable JPEG images at the equivalent SSIM quality index. Another next-gen image format to consider is [AVIF](https://jakearchibald.com/2020/avif-has-landed/).\",\n      /** Additional description of a Lighthouse audit that tells the user how they can improve performance by lazy loading images that are initially offscreen in the context of the October CMS platform. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */\n      \"offscreen-images\": \"Consider installing an [image lazy loading plugin](https://octobercms.com/plugins?search=lazy) that provides the ability to defer any offscreen images, or switch to a theme that provides that functionality. Also consider using [the AMP plugin](https://octobercms.com/plugins?search=Accelerated+Mobile+Pages).\",\n      /** Additional description of a Lighthouse audit that tells the user how they can improve site loading performance by reducing the total bytes delivered by their page in the context of the October CMS platform. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */\n      \"total-byte-weight\": \"Consider showing excerpts in the post lists (e.g. using a `show more` button), reducing the number of posts shown on a given web page, breaking long posts into multiple web pages, or using a plugin to lazy-load comments.\",\n      /** Additional description of a Lighthouse audit that tells the user how they can improve performance by reducing the amount of render blocking resources present on their page, in the context of the October CMS platform. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */\n      \"render-blocking-resources\": \"There are many plugins that help [inline critical assets](https://octobercms.com/plugins?search=css). These plugins may break other plugins, so you should test thoroughly.\",\n      /** Additional description of a Lighthouse audit that tells the user how they can improve performance by minifying their CSS files in the context of the October CMS platform. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */\n      \"unminified-css\": \"There are many [plugins](https://octobercms.com/plugins?search=css) that can speed up a website by concatenating, minifying and compressing the styles. Using a build process to do this minification up-front can speed up development.\",\n      /** Additional description of a Lighthouse audit that tells the user how they can improve performance by minifying their Javascript files in the context of the October CMS platform. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */\n      \"unminified-javascript\": \"There are many [plugins](https://octobercms.com/plugins?search=javascript) that can speed up a website by concatenating, minifying and compressing the scripts. Using a build process to do this minification up-front can speed up development.\",\n      /** Additional description of a Lighthouse audit that tells the user how they can improve performance by encoding animated images as video, in the context of the October CMS platform. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */\n      \"efficient-animated-content\": \"[Replace animated GIFs with video](https://web.dev/replace-gifs-with-videos/) for faster web page loads and consider using modern file formats such as [WebM](https://web.dev/replace-gifs-with-videos/#create-webm-videos) or [AV1](https://developers.google.com/web/updates/2018/09/chrome-70-media-updates#av1-decoder) to improve compression efficiency by greater than 30% over the current state-of-the-art video codec, VP9.\",\n      /** Additional description of a Lighthouse audit that tells the user how they can improve performance by removing unused Javascript files in the context of the October CMS platform. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */\n      \"unused-javascript\": \"Consider reviewing the [plugins](https://octobercms.com/plugins?search=javascript) that load unused JavaScript in the web page. To identify plugins that add unnecessary JavaScript, run [code coverage](https://developers.google.com/web/updates/2017/04/devtools-release-notes#coverage) in Chrome DevTools. Identify the theme/plugin responsible from the URL of the script. Look for plugins with many scripts with lots of red in code coverage. A plugin should only add a script if it is actually used on the web page.\",\n      /** Additional description of a Lighthouse audit that tells the user how they can improve their site by enabling long caching in the context of the October CMS platform. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */\n      \"uses-long-cache-ttl\": \"Read about [preventing unnecessary network requests with the HTTP Cache](https://web.dev/http-cache/#caching-checklist). There are many [plugins](https://octobercms.com/plugins?search=Caching) that can be used to speed up caching.\",\n      /** Additional description of a Lighthouse audit that tells the user how they can improve site performance by optimizing images, in the context of the October CMS platform. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */\n      \"uses-optimized-images\": \"Consider using an [image optimization plugin](https://octobercms.com/plugins?search=image) to compresses images while retaining the quality.\",\n      /** Additional description of a Lighthouse audit that tells the user how they can improve performance via enabling text compression in the context of the October CMS platform. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */\n      \"uses-text-compression\": \"Enable text compression in the web server configuration.\",\n      /** Additional description of a Lighthouse audit that tells the user how they can improve performance by using responsive images in the context of the October CMS platform. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */\n      \"uses-responsive-images\": \"Upload images directly in the media manager to ensure the required image sizes are available. Consider using the [resize filter](https://octobercms.com/docs/markup/filter-resize) or an [image resizing plugin](https://octobercms.com/plugins?search=image) to ensure the optimal image sizes are used.\",\n      /** Additional description of a Lighthouse audit that tells the user how they can improve the time to first byte speed metric, in the context of the October CMS platform. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */\n      \"server-response-time\": \"Themes, plugins and server specifications all contribute to the server response time. Consider finding a more optimized theme, carefully selecting an optimization plugin and/or upgrade the server. October CMS also allows developers to use [`Queues`](https://octobercms.com/docs/services/queues) to defer the processing of a time consuming task, such as sending an e-mail. This drastically speeds up web requests.\"\n    };\n    module2.exports = {\n      id: \"octobercms\",\n      title: \"October CMS\",\n      icon,\n      UIStrings: UIStrings125\n    };\n  }\n});\n\n// node_modules/lighthouse-stack-packs/packs/react.js\nvar require_react = __commonJS({\n  \"node_modules/lighthouse-stack-packs/packs/react.js\"(exports2, module2) {\n    init_process_global();\n    var icon = `data:image/svg+xml,<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 841.9 595.3\"><g fill=\"%2361DAFB\"><path d=\"M666.3 296.5c0-32.5-40.7-63.3-103.1-82.4 14.4-63.6 8-114.2-20.2-130.4-6.5-3.8-14.1-5.6-22.4-5.6v22.3c4.6 0 8.3.9 11.4 2.6 13.6 7.8 19.5 37.5 14.9 75.7-1.1 9.4-2.9 19.3-5.1 29.4-19.6-4.8-41-8.5-63.5-10.9-13.5-18.5-27.5-35.3-41.6-50 32.6-30.3 63.2-46.9 84-46.9V78c-27.5 0-63.5 19.6-99.9 53.6-36.4-33.8-72.4-53.2-99.9-53.2v22.3c20.7 0 51.4 16.5 84 46.6-14 14.7-28 31.4-41.3 49.9-22.6 2.4-44 6.1-63.6 11-2.3-10-4-19.7-5.2-29-4.7-38.2 1.1-67.9 14.6-75.8 3-1.8 6.9-2.6 11.5-2.6V78.5c-8.4 0-16 1.8-22.6 5.6-28.1 16.2-34.4 66.7-19.9 130.1-62.2 19.2-102.7 49.9-102.7 82.3 0 32.5 40.7 63.3 103.1 82.4-14.4 63.6-8 114.2 20.2 130.4 6.5 3.8 14.1 5.6 22.5 5.6 27.5 0 63.5-19.6 99.9-53.6 36.4 33.8 72.4 53.2 99.9 53.2 8.4 0 16-1.8 22.6-5.6 28.1-16.2 34.4-66.7 19.9-130.1 62-19.1 102.5-49.9 102.5-82.3zm-130.2-66.7c-3.7 12.9-8.3 26.2-13.5 39.5-4.1-8-8.4-16-13.1-24-4.6-8-9.5-15.8-14.4-2\\\n3.4 14.2 2.1 27.9 4.7 41 7.9zm-45.8 106.5c-7.8 13.5-15.8 26.3-24.1 38.2-14.9 1.3-30 2-45.2 2-15.1 0-30.2-.7-45-1.9-8.3-11.9-16.4-24.6-24.2-38-7.6-13.1-14.5-26.4-20.8-39.8 6.2-13.4 13.2-26.8 20.7-39.9 7.8-13.5 15.8-26.3 24.1-38.2 14.9-1.3 30-2 45.2-2 15.1 0 30.2.7 45 1.9 8.3 11.9 16.4 24.6 24.2 38 7.6 13.1 14.5 26.4 20.8 39.8-6.3 13.4-13.2 26.8-20.7 39.9zm32.3-13c5.4 13.4 10 26.8 13.8 39.8-13.1 3.2-26.9 5.9-41.2 8 4.9-7.7 9.8-15.6 14.4-23.7 4.6-8 8.9-16.1 13-24.1zM421.2 430c-9.3-9.6-18.6-20.3-27.8-32 9 .4 18.2.7 27.5.7 9.4 0 18.7-.2 27.8-.7-9 11.7-18.3 22.4-27.5 32zm-74.4-58.9c-14.2-2.1-27.9-4.7-41-7.9 3.7-12.9 8.3-26.2 13.5-39.5 4.1 8 8.4 16 13.1 24 4.7 8 9.5 15.8 14.4 23.4zM420.7 163c9.3 9.6 18.6 20.3 27.8 32-9-.4-18.2-.7-27.5-.7-9.4 0-18.7.2-27.8.7 9-11.7 18.3-22.4 27.5-32zm-74 58.9c-4.9 7.7-9.8 15.6-14.4 23.7-4.6 8-8.9 16-13 24-5.4-13.4-10-26.8-13.8-39.8 13.1-3.1 26.9-5.8 41.2-7.9zm-90.5 125.2c-35.4-15.1-58.3-34.9-58.3-50.6 0-15.7 22.9-35.6 58.3-50.6 8.6-3.7 18-7 27.7-10.1 5.7 19.6 \\\n13.2 40 22.5 60.9-9.2 20.8-16.6 41.1-22.2 60.6-9.9-3.1-19.3-6.5-28-10.2zM310 490c-13.6-7.8-19.5-37.5-14.9-75.7 1.1-9.4 2.9-19.3 5.1-29.4 19.6 4.8 41 8.5 63.5 10.9 13.5 18.5 27.5 35.3 41.6 50-32.6 30.3-63.2 46.9-84 46.9-4.5-.1-8.3-1-11.3-2.7zm237.2-76.2c4.7 38.2-1.1 67.9-14.6 75.8-3 1.8-6.9 2.6-11.5 2.6-20.7 0-51.4-16.5-84-46.6 14-14.7 28-31.4 41.3-49.9 22.6-2.4 44-6.1 63.6-11 2.3 10.1 4.1 19.8 5.2 29.1zm38.5-66.7c-8.6 3.7-18 7-27.7 10.1-5.7-19.6-13.2-40-22.5-60.9 9.2-20.8 16.6-41.1 22.2-60.6 9.9 3.1 19.3 6.5 28.1 10.2 35.4 15.1 58.3 34.9 58.3 50.6-.1 15.7-23 35.6-58.4 50.6zM320.8 78.4z\"/><circle cx=\"420.9\" cy=\"296.5\" r=\"45.7\"/><path d=\"M520.5 78.1z\"/></g></svg>`;\n    var UIStrings125 = {\n      /** Additional description of a Lighthouse audit that tells the user how they can improve performance by minifying their CSS files in the context of the React library. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */\n      \"unminified-css\": \"If your build system minifies CSS files automatically, ensure that you are deploying the production build of your application. You can check this with the React Developer Tools extension. [Learn more](https://reactjs.org/docs/optimizing-performance.html#use-the-production-build).\",\n      /** Additional description of a Lighthouse audit that tells the user how they can improve performance by minifying their Javascript files in the context of the React library. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */\n      \"unminified-javascript\": \"If your build system minifies JS files automatically, ensure that you are deploying the production build of your application. You can check this with the React Developer Tools extension. [Learn more](https://reactjs.org/docs/optimizing-performance.html#use-the-production-build).\",\n      /** Additional description of a Lighthouse audit that tells the user how they can improve performance by removing unused Javascript files in the context of the React library. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */\n      \"unused-javascript\": \"If you are not server-side rendering, [split your JavaScript bundles](https://web.dev/code-splitting-suspense/) with `React.lazy()`. Otherwise, code-split using a third-party library such as [loadable-components](https://loadable-components.com/).\",\n      /** Additional description of a Lighthouse audit that tells the user how they can improve the time to first byte speed metric, in the context of the React library. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */\n      \"server-response-time\": \"If you are server-side rendering any React components, consider using `renderToPipeableStream()` or `renderToStaticNodeStream()` to allow the client to receive and hydrate different parts of the markup instead of all at once. [Learn more](https://reactjs.org/docs/react-dom-server.html#renderToPipeableStream).\",\n      /** Additional description of a Lighthouse audit that tells the user how they can minimize redirects, in the context of the React library. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */\n      \"redirects\": \"If you are using React Router, minimize usage of the `<Redirect>` component for [route navigations](https://reacttraining.com/react-router/web/api/Redirect).\",\n      /** Additional description of a Lighthouse audit that tells the user how they can use the Profiler to help measure performance. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */\n      \"user-timings\": \"Use the React DevTools Profiler, which makes use of the Profiler API, to measure the rendering performance of your components. [Learn more.](https://reactjs.org/blog/2018/09/10/introducing-the-react-profiler.html)\",\n      /** Additional description of a Lighthouse audit that tells the user *why* and *how* they should reduce the size of the web page\"s DOM, in the context of the React library, as well as how to maximize component performance when many DOM nodes are present. 'Learn More' becomes link text to additional documentation. */\n      \"dom-size\": 'Consider using a \"windowing\" library like `react-window` to minimize the number of DOM nodes created if you are rendering many repeated elements on the page. [Learn more](https://web.dev/virtualize-long-lists-react-window/). Also, minimize unnecessary re-renders using [`shouldComponentUpdate`](https://reactjs.org/docs/optimizing-performance.html#shouldcomponentupdate-in-action), [`PureComponent`](https://reactjs.org/docs/react-api.html#reactpurecomponent), or [`React.memo`](https://reactjs.org/docs/react-api.html#reactmemo) and [skip effects](https://reactjs.org/docs/hooks-effect.html#tip-optimizing-performance-by-skipping-effects) only until certain dependencies have changed if you are using the `Effect` hook to improve runtime performance.'\n    };\n    module2.exports = {\n      id: \"react\",\n      title: \"React\",\n      icon,\n      UIStrings: UIStrings125\n    };\n  }\n});\n\n// node_modules/lighthouse-stack-packs/packs/wix.js\nvar require_wix = __commonJS({\n  \"node_modules/lighthouse-stack-packs/packs/wix.js\"(exports2, module2) {\n    init_process_global();\n    var icon = `data:image/svg+xml,<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 71 28\"><path fill-rule=\"evenodd\" d=\"M0 .032s2.796-.356 4.66 1.31C5.81 2.37 6.145 4.008 6.145 4.008L9.952 18.96l3.165-12.239c.309-1.301.864-2.909 1.743-3.997 1.121-1.385 3.398-1.472 3.641-1.472.242 0 2.519.087 3.639 1.472.88 1.088 1.435 2.696 1.744 3.997l3.165 12.239 3.806-14.953s.336-1.638 1.486-2.666C34.205-.324 37 .032 37 .032l-7.289 27.945s-2.404.176-3.607-.446c-1.58-.816-2.332-1.447-3.289-5.249l-.099-.395c-.349-1.399-.883-3.59-1.424-5.813l-.162-.667-.162-.664c-.779-3.198-1.497-6.143-1.612-6.517-.108-.351-.236-1.187-.855-1.187-.607 0-.746.837-.857 1.187-.13.412-.99 3.955-1.856 7.514l-.162.667c-.512 2.107-1.01 4.151-1.341 5.48l-.1.395c-.956 3.802-1.708 4.433-3.288 5.249-1.204.622-3.608.446-3.608.446zM43.998 5v.995L44 5.994v16.628c-.014 3.413-.373 4.17-1.933 4.956-1.213.61-3.067.379-3.067.379V9.332c0-.935.315-1.548 1.477-2.098.693-.329 1.34-.58 2.012-.953C43.54 5.703 43.998 5 43.998 5zM46 .125s3.87\\\n7-.673 5.797 1.107c1.228 1.14 2.602 3.19 2.602 3.19l3.38 4.965c.164.258.378.54.72.54.343 0 .558-.282.722-.54l3.38-4.965s1.374-2.05 2.602-3.19C67.123-.548 71 .125 71 .125l-9.186 13.923 9.161 13.881-.032.004c-.38.045-4.036.423-5.855-1.266-1.229-1.138-2.487-2.992-2.487-2.992l-3.38-4.964c-.164-.26-.379-.54-.721-.54-.343 0-.557.28-.721.54l-3.38 4.964s-1.19 1.854-2.418 2.992c-1.92 1.783-5.957 1.262-5.957 1.262l9.161-13.88zM43.96 0H44c0 1.91-.186 3.042-1.387 3.923-.384.28-1.048.71-1.826.992C39.719 5.304 39 6 39 6c0-3.476.53-4.734 1.95-5.48.865-.452 2.272-.514 2.82-.52z\"></path></svg>`;\n    var UIStrings125 = {\n      /** Additional description of a Lighthouse audit that tells the user to optimize image formats, in the context of the Wix CMS platform. */\n      \"modern-image-formats\": \"Upload images using `Wix Media Manager` to ensure they are automatically served as WebP. Find [more ways to optimize](https://support.wix.com/en/article/site-performance-optimizing-your-media) your site's media.\",\n      /** Additional description of a Lighthouse audit that tells the user to defer loading of non-critical third-party libraries, in the context of the Wix CMS platform. */\n      \"render-blocking-resources\": \"When [adding third-party code](https://support.wix.com/en/article/site-performance-using-third-party-code-on-your-site) in the `Custom Code` tab of your site's dashboard, make sure it's deferred or loaded at the end of the code body. Where possible, use Wix’s [integrations](https://support.wix.com/en/article/about-marketing-integrations) to embed marketing tools on your site. \",\n      /** Additional description of a Lighthouse audit that tells the user how they can improve performance by avoiding animated images and using videos where possible, in the context of the Wix CMS platform. */\n      \"efficient-animated-content\": \"Place videos inside `VideoBoxes`, customize them using `Video Masks` or add `Transparent Videos`. [Learn more](https://support.wix.com/en/article/wix-video-about-wix-video).\",\n      /** Additional description of a Lighthouse audit that tells the user to be aware of JavaScript code that is not used, particularly from third-parties, in the context of the Wix CMS platform. */\n      \"unused-javascript\": \"Review any third-party code you've added to your site in the `Custom Code` tab of your site's dashboard and only keep the services that are necessary to your site. [Find out more](https://support.wix.com/en/article/site-performance-removing-unused-javascript).\",\n      /** Additional description of a Lighthouse audit that tells the user how they can improve the server response time, in the context of the Wix CMS platform. */\n      \"server-response-time\": \"Wix utilizes CDNs and caching to serve responses as fast as possible for most visitors. Consider [manually enabling caching](https://support.wix.com/en/article/site-performance-caching-pages-to-optimize-loading-speed) for your site, especially if using `Velo`.\"\n    };\n    module2.exports = {\n      id: \"wix\",\n      title: \"Wix\",\n      icon,\n      UIStrings: UIStrings125\n    };\n  }\n});\n\n// node_modules/lighthouse-stack-packs/packs/wordpress.js\nvar require_wordpress = __commonJS({\n  \"node_modules/lighthouse-stack-packs/packs/wordpress.js\"(exports2, module2) {\n    init_process_global();\n    var icon = `data:image/svg+xml,<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 122.5 122.5\"><g fill=\"%232f3439\"><path d=\"M8.7 61.3c0 20.8 12.1 38.7 29.6 47.3l-25-68.7c-3 6.5-4.6 13.7-4.6 21.4zm88-2.7c0-6.5-2.3-11-4.3-14.5-2.7-4.3-5.2-8-5.2-12.3 0-4.8 3.7-9.3 8.9-9.3h.7a52.4 52.4 0 0 0-79.4 9.9h3.3c5.5 0 14-.6 14-.6 2.9-.2 3.2 4 .4 4.3 0 0-2.9.4-6 .5l19.1 57L59.7 59l-8.2-22.5c-2.8-.1-5.5-.5-5.5-.5-2.8-.1-2.5-4.5.3-4.3 0 0 8.7.7 13.9.7 5.5 0 14-.7 14-.7 2.8-.2 3.2 4 .3 4.3 0 0-2.8.4-6 .5l19 56.5 5.2-17.5c2.3-7.3 4-12.5 4-17z\"/><path d=\"m62.2 65.9-15.8 45.8a52.6 52.6 0 0 0 32.3-.9l-.4-.7zM107.4 36a49.6 49.6 0 0 1-3.6 24.2l-16.1 46.5A52.5 52.5 0 0 0 107.4 36z\"/><path d=\"M61.3 0a61.3 61.3 0 1 0 .1 122.7A61.3 61.3 0 0 0 61.3 0zm0 119.7a58.5 58.5 0 1 1 .1-117 58.5 58.5 0 0 1-.1 117z\"/></g></svg>`;\n    var UIStrings125 = {\n      /** Additional description of a Lighthouse audit that tells the user how they can improve performance by removing unused CSS, in the context of the Wordpress CMS platform. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */\n      \"unused-css-rules\": \"Consider reducing, or switching, the number of [WordPress plugins](https://wordpress.org/plugins/) loading unused CSS in your page. To identify plugins that are adding extraneous CSS, try running [code coverage](https://developer.chrome.com/docs/devtools/coverage/) in Chrome DevTools. You can identify the theme/plugin responsible from the URL of the stylesheet. Look out for plugins that have many stylesheets in the list which have a lot of red in code coverage. A plugin should only enqueue a stylesheet if it is actually used on the page.\",\n      /** Additional description of a Lighthouse audit that tells the user how they can improve image loading by using webp in the context of the Wordpress CMS platform. This is displayed after a user expands the section to see more. No character length limits. */\n      \"modern-image-formats\": \"Consider using the [Performance Lab](https://wordpress.org/plugins/performance-lab/) plugin to automatically convert your uploaded JPEG images into WebP, wherever supported.\",\n      /** Additional description of a Lighthouse audit that tells the user how they can improve performance by lazy loading images that are initially offscreen in the context of the Wordpress CMS platform. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */\n      \"offscreen-images\": \"Install a [lazy-load WordPress plugin](https://wordpress.org/plugins/search/lazy+load/) that provides the ability to defer any offscreen images, or switch to a theme that provides that functionality. Also consider using [the AMP plugin](https://wordpress.org/plugins/amp/).\",\n      /** Additional description of a Lighthouse audit that tells the user how they can improve site loading performance by reducing the total bytes delivered by their page in the context of the Wordpress CMS platform. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */\n      \"total-byte-weight\": \"Consider showing excerpts in your post lists (e.g. via the more tag), reducing the number of posts shown on a given page, breaking your long posts into multiple pages, or using a plugin to lazy-load comments.\",\n      /** Additional description of a Lighthouse audit that tells the user how they can improve performance by reducing the amount of render blocking resources present on their page, in the context of the Wordpress CMS platform. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */\n      \"render-blocking-resources\": \"There are a number of WordPress plugins that can help you [inline critical assets](https://wordpress.org/plugins/search/critical+css/) or [defer less important resources](https://wordpress.org/plugins/search/defer+css+javascript/). Beware that optimizations provided by these plugins may break features of your theme or plugins, so you will likely need to make code changes.\",\n      /** Additional description of a Lighthouse audit that tells the user how they can improve performance by minifying their CSS files in the context of the Wordpress CMS platform. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */\n      \"unminified-css\": \"A number of [WordPress plugins](https://wordpress.org/plugins/search/minify+css/) can speed up your site by concatenating, minifying, and compressing your styles. You may also want to use a build process to do this minification up-front if possible.\",\n      /** Additional description of a Lighthouse audit that tells the user how they can improve performance by minifying their Javascript files in the context of the Wordpress CMS platform. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */\n      \"unminified-javascript\": \"A number of [WordPress plugins](https://wordpress.org/plugins/search/minify+javascript/) can speed up your site by concatenating, minifying, and compressing your scripts. You may also want to use a build process to do this minification up front if possible.\",\n      /** Additional description of a Lighthouse audit that tells the user how they can improve performance by encoding animated images as video, in the context of the Wordpress CMS platform. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */\n      \"efficient-animated-content\": \"Consider uploading your GIF to a service which will make it available to embed as an HTML5 video.\",\n      /** Additional description of a Lighthouse audit that tells the user how they can improve performance by removing unused Javascript files in the context of the Wordpress CMS platform. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */\n      \"unused-javascript\": \"Consider reducing, or switching, the number of [WordPress plugins](https://wordpress.org/plugins/) loading unused JavaScript in your page. To identify plugins that are adding extraneous JS, try running [code coverage](https://developer.chrome.com/docs/devtools/coverage/) in Chrome DevTools. You can identify the theme/plugin responsible from the URL of the script. Look out for plugins that have many scripts in the list which have a lot of red in code coverage. A plugin should only enqueue a script if it is actually used on the page.\",\n      /** Additional description of a Lighthouse audit that tells the user how they can improve their site by enabling long caching in the context of the Wordpress CMS platform. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */\n      \"uses-long-cache-ttl\": \"Read about [Browser Caching in WordPress](https://wordpress.org/support/article/optimization/#browser-caching).\",\n      /** Additional description of a Lighthouse audit that tells the user how they can improve site performance by optimizing images, in the context of the Wordpress CMS platform. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */\n      \"uses-optimized-images\": \"Consider using an [image optimization WordPress plugin](https://wordpress.org/plugins/search/optimize+images/) that compresses your images while retaining quality.\",\n      /** Additional description of a Lighthouse audit that tells the user how they can improve performance via enabling text compression in the context of the Wordpress CMS platform. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */\n      \"uses-text-compression\": \"You can enable text compression in your web server configuration.\",\n      /** Additional description of a Lighthouse audit that tells the user how they can improve performance by using responsive images in the context of the Wordpress CMS platform. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */\n      \"uses-responsive-images\": \"Upload images directly through the [media library](https://wordpress.org/support/article/media-library-screen/) to ensure that the required image sizes are available, and then insert them from the media library or use the image widget to ensure the optimal image sizes are used (including those for the responsive breakpoints). Avoid using `Full Size` images unless the dimensions are adequate for their usage. [Learn More](https://wordpress.org/support/article/inserting-images-into-posts-and-pages/).\",\n      /** Additional description of a Lighthouse audit that tells the user how they can improve the time to first byte speed metric, in the context of the Wordpress CMS platform. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */\n      \"server-response-time\": \"Choose a lightweight theme (ideally a block theme) and implement full-page caching or a static site solution. Disable unnecessary plugins to minimize server overhead. Consider upgrading your hosting to managed or dedicated service.\"\n    };\n    module2.exports = {\n      id: \"wordpress\",\n      title: \"WordPress\",\n      icon,\n      UIStrings: UIStrings125\n    };\n  }\n});\n\n// node_modules/lighthouse-stack-packs/packs/wp-rocket.js\nvar require_wp_rocket = __commonJS({\n  \"node_modules/lighthouse-stack-packs/packs/wp-rocket.js\"(exports2, module2) {\n    init_process_global();\n    var icon = `data:image/svg+xml,<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 294 524\"><defs><linearGradient id=\"a\" x1=\"36.742%\" x2=\"37.116%\" y1=\"100.518%\" y2=\"-.001%\"><stop offset=\"0%\" stop-color=\"%23DD5F29\"/><stop offset=\"26.042%\" stop-color=\"%23F26B32\"/><stop offset=\"100%\" stop-color=\"%23FAC932\"/></linearGradient><linearGradient id=\"b\" x1=\"28.046%\" x2=\"28.421%\" y1=\"100.518%\" y2=\"-.003%\"><stop offset=\"0%\" stop-color=\"%23DD5F29\"/><stop offset=\"26.042%\" stop-color=\"%23F26B32\"/><stop offset=\"100%\" stop-color=\"%23FAC932\"/></linearGradient><linearGradient id=\"c\" x1=\"38.215%\" x2=\"38.589%\" y1=\"100.518%\" y2=\"0%\"><stop offset=\"0%\" stop-color=\"%23DD5F29\"/><stop offset=\"26.042%\" stop-color=\"%23F26B32\"/><stop offset=\"100%\" stop-color=\"%23FAC932\"/></linearGradient></defs><g fill=\"none\" fill-rule=\"evenodd\"><path fill=\"url(%23a)\" d=\"M218.617 270.615c-9.752 0-18.896-5.689-23.366-14.63l-7.72-17.27h-76.6l-7.722 17.27c-4.47 8.941-13.613 14.63-23.366 14.63H75.78l32.712 249.306c1.625 4.671 4.67\\\n3 4.671 6.502 0l32.51-79.648 28.242 79.442c1.625 4.676 4.673 4.676 6.501 0L220.04 270.82l-1.423-.204Z\" transform=\"translate(-1.58 -.2)\"/><path fill=\"url(%23b)\" d=\"M184.47 231.784h-70.3l-10.77 24.179c-3.657 7.314-10.768 12.597-18.489 14.02L109.7 423.791c1.625 2.844 4.673 2.844 6.501 0l31.697-48.155 29.055 47.951c1.829 2.845 4.673 2.845 6.502 0l28.039-154.012c-6.908-2.032-13.004-6.908-16.255-13.613l-10.768-24.18Z\" transform=\"translate(-1.58 -.2)\"/><path fill=\"url(%23c)\" d=\"m195.259 255.988-46.123-103.014-45.92 103.014c-1.625 3.048-3.656 5.69-6.095 7.925l19.1 102.2c1.015 1.423 3.657 1.83 5.485 0l25.601-33.931 25.602 33.728c1.625 2.032 4.47 1.626 5.485 0l21.131-103.42c-1.625-2.032-3.047-4.064-4.266-6.502Z\" transform=\"translate(-1.58 -.2)\"/><path fill=\"%23F56F46\" d=\"M.439 12.559c-1.422-4.877 1.422-8.33 6.299-8.33H47.17c2.845 0 5.486 2.437 6.299 4.876l29.665 116.83h1.422l53.437-121.3c1.016-2.032 3.048-3.86 5.892-3.86h6.299c3.047 0 5.08 1.625 5.892 3.86l53.437 121.3h1.423L240.6 9.105c.61-2.43\\\n9 3.454-4.877 6.299-4.877h40.433c4.877 0 7.518 3.454 6.299 8.33l-65.221 231.63c-.61 2.845-3.454 4.876-6.298 4.876h-5.487c-2.438 0-4.876-1.625-5.892-3.86l-63.19-141.009h-1.015L83.744 245.203c-1.016 2.032-3.454 3.86-5.892 3.86h-5.486c-2.845 0-5.486-2.031-6.299-4.876L.44 12.559Z\"/></g></svg>`;\n    var UIStrings125 = {\n      /** Additional description of a Lighthouse audit for a third-party framework called 'WP Rocket'. This is displayed after a user expands the section to see more. No character length limits. Remove Unused CSS is a name of the feature */\n      \"unused-css-rules\": `Enable [Remove Unused CSS](https://docs.wp-rocket.me/article/1529-remove-unused-css) in 'WP Rocket' to fix this issue. It reduces page size by removing all CSS and stylesheets that are not used while keeping only the used CSS for each page.`,\n      /** Additional description of a Lighthouse audit for a third-party framework called 'WP Rocket'. This is displayed after a user expands the section to see more. No character length limits. `Imagify` is an image optimization add-on */\n      \"modern-image-formats\": `Enable 'Imagify' from the Image Optimization tab in 'WP Rocket' to convert your images to WebP.`,\n      /** Additional description of a Lighthouse audit for a third-party framework called 'WP Rocket'. This is displayed after a user expands the section to see more. No character length limits. Delay JavaScript, LazyLoad for iframes and videos and Replace YouTube iframe with preview image are names of the features */\n      \"unused-javascript\": `Enable [Delay JavaScript execution](https://docs.wp-rocket.me/article/1349-delay-javascript-execution) in 'WP Rocket' to fix this problem. It will improve the loading of your page by delaying the execution of scripts until user interaction. If your site has iframes, you can use WP Rocket's [LazyLoad for iframes and videos](https://docs.wp-rocket.me/article/1674-lazyload-for-iframes-and-videos) and [Replace YouTube iframe with preview image](https://docs.wp-rocket.me/article/1488-replace-youtube-iframe-with-preview-image) as well.`,\n      /** Additional description of a Lighthouse audit for a third-party framework called 'WP Rocket'. This is displayed after a user expands the section to see more. No character length limits. Remove Unused CSS, Load JavaScript deferred are names of the features */\n      \"render-blocking-resources\": `Enable [Remove Unused CSS](https://docs.wp-rocket.me/article/1529-remove-unused-css) and [Load JavaScript deferred](https://docs.wp-rocket.me/article/1265-load-javascript-deferred) in 'WP Rocket' to address this recommendation. These features will respectively optimize the CSS and JavaScript files so that they don't block the rendering of your page.`,\n      /** Additional description of a Lighthouse audit for a third-party framework called 'WP Rocket'. This is displayed after a user expands the section to see more. No character length limits. Minify CSS Files is a name of the feature */\n      \"unminified-css\": `Enable [Minify CSS files](https://docs.wp-rocket.me/article/1350-css-minify-combine) in 'WP Rocket' to fix this issue. Any spaces and comments in your site's CSS files will be removed to make the file size smaller and faster to download.`,\n      /** Additional description of a Lighthouse audit for a third-party framework called 'WP Rocket'. This is displayed after a user expands the section to see more. No character length limits. Minify JavaScript Files is a name of the feature */\n      \"unminified-javascript\": `Enable [Minify JavaScript files](https://docs.wp-rocket.me/article/1351-javascript-minify-combine) in 'WP Rocket' to fix this issue. Empty spaces and comments will be removed from JavaScript files to make their size smaller and faster to download.`,\n      /** Additional description of a Lighthouse audit for a third-party framework called 'WP Rocket'. This is displayed after a user expands the section to see more. No character length limits. `Imagify` is an image optimization add-on */\n      \"uses-optimized-images\": `Enable 'Imagify' from the Image Optimization tab in 'WP Rocket' and run Bulk Optimization to compress your images.`,\n      /** Additional description of a Lighthouse audit for a third-party framework called 'WP Rocket'. This is displayed after a user expands the section to see more. No character length limits. Prefetch DNS Requests, Enable CDN are names of the features */\n      \"uses-rel-preconnect\": `Use [Prefetch DNS Requests](https://docs.wp-rocket.me/article/1302-prefetch-dns-requests) in 'WP Rocket' to add \"dns-prefetch\" and speed up the connection with external domains. Also, 'WP Rocket' automatically adds \"preconnect\" to [Google Fonts domain](https://docs.wp-rocket.me/article/1312-optimize-google-fonts) and any CNAME(S) added via the [Enable CDN](https://docs.wp-rocket.me/article/42-using-wp-rocket-with-a-cdn) feature.`,\n      /** Additional description of a Lighthouse audit for a third-party framework called 'WP Rocket'. This is displayed after a user expands the section to see more. No character length limits. Remove Unused CSS is a name of the feature*/\n      \"uses-rel-preload\": `To fix this issue for fonts, enable [Remove Unused CSS](https://docs.wp-rocket.me/article/1529-remove-unused-css) in 'WP Rocket'. Your site's critical fonts will be preloaded with priority.`,\n      /** Additional description of a Lighthouse audit for a third-party framework called 'WP Rocket'. This is displayed after a user expands the section to see more. No character length limits. LazyLoad for images is a name of the feature*/\n      \"offscreen-images\": `Enable [LazyLoad](https://docs.wp-rocket.me/article/1141-lazyload-for-images) in WP Rocket to fix this recommendation. This feature delays the loading of the images until the visitor scrolls down the page and actually needs to see them.`\n    };\n    module2.exports = {\n      id: \"wp-rocket\",\n      title: \"WP Rocket\",\n      icon,\n      UIStrings: UIStrings125\n    };\n  }\n});\n\n// node_modules/lighthouse-stack-packs/index.js\nvar require_lighthouse_stack_packs = __commonJS({\n  \"node_modules/lighthouse-stack-packs/index.js\"(exports2, module2) {\n    init_process_global();\n    var stackPacks2 = [\n      require_amp(),\n      require_angular(),\n      require_drupal(),\n      require_ezoic(),\n      require_gatsby(),\n      require_joomla(),\n      require_magento(),\n      require_next(),\n      require_nitropack(),\n      require_nuxt(),\n      require_octobercms(),\n      require_react(),\n      require_wix(),\n      require_wordpress(),\n      require_wp_rocket()\n    ];\n    module2.exports = stackPacks2;\n  }\n});\n\n// node_modules/lookup-closest-locale/index.js\nvar require_lookup_closest_locale = __commonJS({\n  \"node_modules/lookup-closest-locale/index.js\"(exports2, module2) {\n    init_process_global();\n    module2.exports = /* @__PURE__ */ __name(function lookupClosestLocale2(locale, available) {\n      if (typeof locale === \"string\" && available[locale]) return locale;\n      var locales2 = [].concat(locale || []);\n      for (var l = 0, ll = locales2.length; l < ll; ++l) {\n        var current = locales2[l].split(\"-\");\n        while (current.length) {\n          var candidate = current.join(\"-\");\n          if (available[candidate]) return candidate;\n          current.pop();\n        }\n      }\n    }, \"lookupClosestLocale\");\n  }\n});\n\n// shared/root.js\nimport path from \"path\";\nvar LH_ROOT, pkg, lighthouseVersion;\nvar init_root2 = __esm({\n  \"shared/root.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_esm_utils();\n    /**\n     * @license\n     * Copyright 2021 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    LH_ROOT = path.dirname(\"\");\n    pkg = JSON.parse(`{\n  \"name\": \"lighthouse\",\n  \"type\": \"module\",\n  \"version\": \"13.0.3\",\n  \"description\": \"Automated auditing, performance metrics, and best practices for the web.\",\n  \"main\": \"./core/index.js\",\n  \"bin\": {\n    \"lighthouse\": \"./cli/index.js\",\n    \"chrome-debug\": \"./core/scripts/manual-chrome-launcher.js\",\n    \"smokehouse\": \"./cli/test/smokehouse/frontends/smokehouse-bin.js\"\n  },\n  \"engines\": {\n    \"node\": \">=22.19\"\n  },\n  \"scripts\": {\n    \"prepack\": \"yarn build-report --standalone --flow --esm && yarn build-types\",\n    \"postpack\": \"yarn clean-types\",\n    \"build-all\": \"yarn build-report && yarn build-cdt-strings && yarn build-devtools && concurrently 'yarn build-extension' 'yarn build-lr' 'yarn build-viewer' 'yarn build-treemap' 'yarn build-smokehouse-bundle' 'yarn build-legacy-javascript' 'yarn build-devtools-mcp' && yarn build-pack\",\n    \"build-cdt-lib\": \"node ./build/build-cdt-lib.js\",\n    \"build-cdt-strings\": \"node ./build/build-cdt-strings.js\",\n    \"build-extension\": \"yarn build-extension-chrome && yarn build-extension-firefox\",\n    \"build-extension-chrome\": \"node ./build/build-extension.js chrome\",\n    \"build-extension-firefox\": \"node ./build/build-extension.js firefox\",\n    \"build-devtools\": \"yarn reset-link && node ./build/build-bundle.js clients/devtools/devtools-entry.js dist/lighthouse-dt-bundle.js && node ./build/build-dt-report-resources.js\",\n    \"build-legacy-javascript\": \"node ./build/build-legacy-javascript.js\",\n    \"build-devtools-mcp\": \"node ./build/build-bundle-mcp.js clients/devtools-mcp/devtools-mcp-entry.js dist/lighthouse-devtools-mcp-bundle.js\",\n    \"build-smokehouse-bundle\": \"node ./build/build-smokehouse-bundle.js\",\n    \"build-lr\": \"yarn reset-link && node --max-old-space-size=4096 ./build/build-lightrider-bundles.js\",\n    \"build-pack\": \"bash build/build-pack.sh\",\n    \"build-report\": \"node build/build-report-components.js && node build/build-report.js\",\n    \"build-sample-reports\": \"yarn build-report && node build/build-sample-reports.js\",\n    \"build-treemap\": \"node ./build/build-treemap.js\",\n    \"build-viewer\": \"node ./build/build-viewer.js\",\n    \"build-types\": \"yarn type-check && rsync -a .tmp/tsbuildinfo/ ./ --include='*.d.ts' --include='*.d.cts' --exclude='*.map' --exclude='*.tsbuildinfo'\",\n    \"reset-link\": \"(yarn unlink || true) && yarn link && yarn link lighthouse\",\n    \"c8\": \"bash core/scripts/c8.sh\",\n    \"clean\": \"rm -r dist proto/scripts/*.json proto/scripts/*_pb2.* proto/scripts/*_pb.* proto/scripts/__pycache__ proto/scripts/*.pyc *.report.html *.report.dom.html *.report.json *.devtoolslog.json *.trace.json shared/localization/locales/*.ctc.json || true\",\n    \"clean-types\": \"git clean -xfq '*.d.ts' '*.d.cts' -e 'node_modules/' -e 'dist/' -e '.tmp/' -e '**/types/'\",\n    \"lint\": \"[ \\\\\"$CI\\\\\" = true ] && eslint --quiet -f codeframe . || eslint .\",\n    \"smoke\": \"node -r source-map-support/register cli/test/smokehouse/frontends/smokehouse-bin.js\",\n    \"debug\": \"node --inspect-brk ./cli/index.js\",\n    \"start\": \"yarn build-report --standalone && node ./cli/index.js\",\n    \"mocha\": \"node core/test/scripts/run-mocha-tests.js\",\n    \"test\": \"yarn diff:sample-json && yarn lint --quiet && yarn unit && yarn type-check\",\n    \"test-bundle\": \"yarn smoke --runner bundle\",\n    \"test-clients\": \"yarn mocha --testMatch clients/**/*-test.js && yarn mocha --testMatch clients/**/*-test-pptr.js\",\n    \"test-viewer\": \"yarn unit-viewer && yarn mocha --testMatch viewer/**/*-test-pptr.js --timeout 35000\",\n    \"test-treemap\": \"yarn unit-treemap && yarn mocha --testMatch treemap/**/*-test-pptr.js --timeout 35000\",\n    \"test-lantern\": \"bash core/scripts/test-lantern.sh\",\n    \"test-legacy-javascript\": \"bash core/scripts/test-legacy-javascript.sh\",\n    \"test-docs\": \"yarn --cwd docs/recipes/ test\",\n    \"test-proto\": \"yarn compile-proto && yarn build-proto-roundtrip\",\n    \"unit-core\": \"yarn mocha core\",\n    \"unit-cli\": \"yarn mocha --testMatch cli/**/*-test.js\",\n    \"unit-lantern-trace\": \"INTERNAL_LANTERN_USE_TRACE=1 yarn mocha core/test/computed/metrics core/test/audits\",\n    \"unit-report\": \"yarn mocha --testMatch report/**/*-test.js\",\n    \"unit-treemap\": \"yarn mocha --testMatch treemap/**/*-test.js\",\n    \"unit-viewer\": \"yarn mocha --testMatch viewer/**/*-test.js\",\n    \"unit-flow\": \"bash flow-report/test/run-flow-report-tests.sh\",\n    \"unit\": \"yarn unit-flow && yarn mocha && yarn unit-lantern-trace\",\n    \"unit:ci\": \"NODE_OPTIONS=--max-old-space-size=8192 npm run unit\",\n    \"unit-lantern-trace:ci\": \"NODE_OPTIONS=--max-old-space-size=8192 npm run unit-lantern-trace\",\n    \"core-unit\": \"yarn unit-core\",\n    \"cli-unit\": \"yarn unit-cli\",\n    \"viewer-unit\": \"yarn unit-viewer\",\n    \"watch\": \"yarn unit-core --watch\",\n    \"unit:cicoverage\": \"yarn c8 --all yarn unit:ci && yarn c8 --all yarn unit-lantern-trace:ci\",\n    \"coverage\": \"yarn unit:cicoverage && c8 report --reporter html\",\n    \"coverage:smoke\": \"yarn c8 yarn smoke -j=1 && c8 report --reporter html\",\n    \"devtools\": \"bash core/scripts/roll-to-devtools.sh\",\n    \"chrome\": \"node core/scripts/manual-chrome-launcher.js\",\n    \"fast\": \"node ./cli/index.js --preset=desktop --throttlingMethod=provided\",\n    \"deploy-treemap\": \"yarn build-treemap --deploy\",\n    \"deploy-viewer\": \"yarn build-viewer --deploy\",\n    \"vercel-build\": \"yarn build-sample-reports && yarn build-viewer && yarn build-treemap\",\n    \"dogfood-lhci\": \"./core/scripts/dogfood-lhci.sh\",\n    \"timing-trace\": \"node core/scripts/generate-timing-trace.js\",\n    \"changelog\": \"conventional-changelog --config ./build/changelog-generator/index.cjs --infile changelog.md --same-file\",\n    \"type-check\": \"tsc --build ./tsconfig-all.json\",\n    \"i18n:checks\": \"./core/scripts/i18n/assert-strings-collected.sh\",\n    \"i18n:collect-strings\": \"node core/scripts/i18n/collect-strings.js\",\n    \"update:lantern-baseline\": \"node core/scripts/lantern/update-baseline-lantern-values.js\",\n    \"update:sample-artifacts\": \"node core/scripts/update-report-fixtures.js\",\n    \"update:sample-json\": \"yarn i18n:collect-strings && node ./cli -A=./core/test/results/artifacts --config-path=./core/test/results/sample-config.js --output=json --output-path=./core/test/results/sample_v2.json && node core/scripts/cleanup-LHR-for-diff.js ./core/test/results/sample_v2.json --only-remove-timing && node ./core/scripts/update-flow-fixtures.js\",\n    \"update:flow-sample-json\": \"yarn i18n:collect-strings && node ./core/scripts/update-flow-fixtures.js\",\n    \"test-devtools\": \"bash core/test/devtools-tests/test-locally.sh\",\n    \"open-devtools\": \"bash core/scripts/open-devtools.sh\",\n    \"run-devtools\": \"node core/scripts/pptr-run-devtools.js\",\n    \"diff:sample-json\": \"yarn i18n:checks && bash core/scripts/assert-golden-lhr-unchanged.sh\",\n    \"diff:flow-sample-json\": \"yarn i18n:collect-strings && bash core/scripts/assert-baseline-flow-result-unchanged.sh\",\n    \"computeBenchmarkIndex\": \"./core/scripts/benchmark.js\",\n    \"save-latest-run\": \"./core/scripts/save-latest-run.sh\",\n    \"compile-proto\": \"protoc --python_out=./ ./proto/lighthouse-result.proto && mv ./proto/*_pb2.py ./proto/scripts || (echo \\\\\"❌ Install protobuf = 3.20.x to compile the proto file.\\\\\" && false)\",\n    \"build-proto-roundtrip\": \"mkdir -p .tmp && python3 proto/scripts/json_roundtrip_via_proto.py\",\n    \"static-server\": \"node cli/test/fixtures/static-server.js\",\n    \"serve-dist\": \"cd dist && python3 -m http.server 7878\",\n    \"serve-gh-pages\": \"cd dist/gh-pages && python3 -m http.server 7333\",\n    \"serve-treemap\": \"yarn serve-gh-pages\",\n    \"serve-viewer\": \"yarn serve-gh-pages\",\n    \"flow-report\": \"yarn build-report --flow && node ./core/scripts/build-test-flow-report.js\",\n    \"generate-insight-audits\": \"node core/scripts/generate-insight-audits.js\"\n  },\n  \"devDependencies\": {\n    \"@build-tracker/cli\": \"^1.0.0-beta.15\",\n    \"@esbuild-kit/esm-loader\": \"^2.6.5\",\n    \"@esbuild-plugins/node-modules-polyfill\": \"^0.1.4\",\n    \"@eslint/compat\": \"^1.3.0\",\n    \"@eslint/eslintrc\": \"^3.3.1\",\n    \"@eslint/js\": \"^9.28.0\",\n    \"@formatjs/icu-messageformat-parser\": \"^2.6.2\",\n    \"@jest/fake-timers\": \"^29.7.0\",\n    \"@testing-library/preact\": \"^3.1.1\",\n    \"@testing-library/preact-hooks\": \"^1.1.0\",\n    \"@types/archiver\": \"^2.1.2\",\n    \"@types/chrome\": \"^0.0.154\",\n    \"@types/configstore\": \"^6.0.2\",\n    \"@types/cpy\": \"^5.1.0\",\n    \"@types/debug\": \"^4.1.7\",\n    \"@types/eslint\": \"^9.6.1\",\n    \"@types/estree\": \"^0.0.50\",\n    \"@types/gh-pages\": \"^2.0.0\",\n    \"@types/google.analytics\": \"0.0.39\",\n    \"@types/gtag.js\": \"0.0.20\",\n    \"@types/jpeg-js\": \"^0.3.7\",\n    \"@types/jsdom\": \"^16.2.13\",\n    \"@types/lodash-es\": \"^4.17.12\",\n    \"@types/mocha\": \"^9.0.0\",\n    \"@types/node\": \"*\",\n    \"@types/pako\": \"^1.0.1\",\n    \"@types/resize-observer-browser\": \"^0.1.1\",\n    \"@types/resolve\": \"^1.20.2\",\n    \"@types/semver\": \"^5.5.0\",\n    \"@types/ws\": \"^7.0.0\",\n    \"@types/yargs\": \"^17.0.8\",\n    \"@types/yargs-parser\": \"^20.2.1\",\n    \"@typescript-eslint/eslint-plugin\": \"^8.34.0\",\n    \"@typescript-eslint/parser\": \"^8.34.0\",\n    \"acorn\": \"^8.5.0\",\n    \"angular\": \"^1.7.4\",\n    \"archiver\": \"^7.0.1\",\n    \"builtin-modules\": \"^3.3.0\",\n    \"c8\": \"^7.11.3\",\n    \"chalk\": \"^2.4.1\",\n    \"chrome-devtools-frontend\": \"1.0.1526630\",\n    \"colors\": \"^1.4.0\",\n    \"concurrently\": \"^9.2.1\",\n    \"conventional-changelog-cli\": \"^2.1.1\",\n    \"core-js-compat\": \"^3.44.0\",\n    \"cpy\": \"^8.1.2\",\n    \"csv-validator\": \"^0.0.3\",\n    \"esbuild\": \"0.25.9\",\n    \"eslint\": \"^9.28.0\",\n    \"eslint-config-google\": \"^0.14.0\",\n    \"eslint-formatter-codeframe\": \"^7.32.1\",\n    \"eslint-plugin-import\": \"^2.25.3\",\n    \"eslint-plugin-local-rules\": \"1.1.0\",\n    \"expect\": \"^28.1.0\",\n    \"firebase\": \"^9.0.2\",\n    \"gh-pages\": \"^2.0.1\",\n    \"glob\": \"^7.1.3\",\n    \"globals\": \"^15.14.0\",\n    \"idb-keyval\": \"2.2.0\",\n    \"jest-mock\": \"^29.7.0\",\n    \"jest-snapshot\": \"^29.7.0\",\n    \"jsdom\": \"^12.2.0\",\n    \"lighthouse-plugin-soft-navigation\": \"^1.1.0\",\n    \"magic-string\": \"^0.25.7\",\n    \"mime-types\": \"^2.1.30\",\n    \"mocha\": \"^10.0.0\",\n    \"pako\": \"^2.1.0\",\n    \"preact\": \"^10.7.2\",\n    \"pretty-json-stringify\": \"^0.0.2\",\n    \"puppeteer\": \"^24.23.0\",\n    \"resolve\": \"^1.22.10\",\n    \"rollup-plugin-polyfill-node\": \"^0.12.0\",\n    \"source-map-support\": \"^0.5.21\",\n    \"terser\": \"^5.18.2\",\n    \"testdouble\": \"^3.20.2\",\n    \"typed-query-selector\": \"^2.12.0\",\n    \"typescript\": \"5.8.2\",\n    \"wait-for-expect\": \"^3.0.2\",\n    \"webtreemap-cdt\": \"^3.2.1\"\n  },\n  \"dependencies\": {\n    \"@paulirish/trace_engine\": \"0.0.61\",\n    \"@sentry/node\": \"^9.28.1\",\n    \"axe-core\": \"^4.11.0\",\n    \"chrome-launcher\": \"^1.2.1\",\n    \"configstore\": \"^7.0.0\",\n    \"csp_evaluator\": \"1.1.5\",\n    \"devtools-protocol\": \"0.0.1527314\",\n    \"enquirer\": \"^2.3.6\",\n    \"http-link-header\": \"^1.1.1\",\n    \"intl-messageformat\": \"^10.5.3\",\n    \"jpeg-js\": \"^0.4.4\",\n    \"js-library-detector\": \"^6.7.0\",\n    \"lighthouse-logger\": \"^2.0.2\",\n    \"lighthouse-stack-packs\": \"1.12.3\",\n    \"lodash-es\": \"^4.17.21\",\n    \"lookup-closest-locale\": \"6.2.0\",\n    \"open\": \"^8.4.0\",\n    \"puppeteer-core\": \"^24.23.0\",\n    \"robots-parser\": \"^3.0.1\",\n    \"speedline-core\": \"^1.4.3\",\n    \"third-party-web\": \"^0.27.0\",\n    \"tldts-icann\": \"^7.0.17\",\n    \"ws\": \"^7.0.0\",\n    \"yargs\": \"^17.3.1\",\n    \"yargs-parser\": \"^21.0.0\"\n  },\n  \"resolutions\": {\n    \"puppeteer/**/devtools-protocol\": \"0.0.1527314\",\n    \"puppeteer-core/**/devtools-protocol\": \"0.0.1527314\"\n  },\n  \"repository\": \"GoogleChrome/lighthouse\",\n  \"keywords\": [\n    \"google\",\n    \"chrome\",\n    \"devtools\"\n  ],\n  \"author\": \"Google LLC\",\n  \"license\": \"Apache-2.0\",\n  \"bugs\": {\n    \"url\": \"https://github.com/GoogleChrome/lighthouse/issues\"\n  },\n  \"homepage\": \"https://github.com/GoogleChrome/lighthouse#readme\",\n  \"packageManager\": \"yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e\"\n}\n`);\n    lighthouseVersion = pkg.version;\n  }\n});\n\n// core/lib/i18n/i18n.js\nimport path2 from \"path\";\nfunction lookupLocale(locales2, possibleLocales) {\n  if (typeof Intl !== \"object\") {\n    throw new Error(\"Lighthouse must be run in Node with `Intl` support. See https://nodejs.org/api/intl.html for help\");\n  }\n  const canonicalLocales = Intl.getCanonicalLocales(locales2);\n  const availableLocales = Intl.NumberFormat.supportedLocalesOf(canonicalLocales);\n  const localesWithMessages = possibleLocales || getAvailableLocales();\n  const localesWithmessagesObj = (\n    /** @type {Record<LH.Locale, LhlMessages>} */\n    Object.fromEntries(localesWithMessages.map((l) => [l, {}]))\n  );\n  const closestLocale = (0, import_lookup_closest_locale.default)(availableLocales, localesWithmessagesObj);\n  if (!closestLocale) {\n    if (Intl.NumberFormat.supportedLocalesOf(\"es\").length === 0) {\n      lighthouse_logger_default.warn(\"i18n\", \"Requested locale not available in this version of node. The `full-icu` npm module can provide additional locales. For help, see https://github.com/GoogleChrome/lighthouse/blob/main/readme.md#how-do-i-get-localized-lighthouse-results-via-the-cli\");\n    }\n    lighthouse_logger_default.warn(\"i18n\", `locale(s) '${locales2}' not available. Falling back to default '${DEFAULT_LOCALE}'`);\n  }\n  return closestLocale || DEFAULT_LOCALE;\n}\nfunction createIcuMessageFn(filename, fileStrings = {}) {\n  if (filename.startsWith(\"file://\")) filename = url_default.fileURLToPath(filename);\n  if (path2.isAbsolute(filename)) filename = path2.relative(LH_ROOT, filename);\n  const mergedStrings = { ...UIStrings, ...fileStrings };\n  const getIcuMessageFn = /* @__PURE__ */ __name((message, values) => {\n    const keyname = Object.keys(mergedStrings).find((key) => mergedStrings[key] === message);\n    if (!keyname) throw new Error(`Could not locate: ${message}`);\n    const filenameToLookup = keyname in fileStrings ? filename : path2.relative(LH_ROOT, getModulePath({ url: \"core/lib/i18n/i18n.js\" }));\n    const unixStyleFilename = filenameToLookup.replace(/\\\\/g, \"/\");\n    const i18nId = `${unixStyleFilename} | ${keyname}`;\n    return {\n      i18nId,\n      values,\n      formattedDefault: formatMessage(message, values, DEFAULT_LOCALE)\n    };\n  }, \"getIcuMessageFn\");\n  return getIcuMessageFn;\n}\nfunction isStringOrIcuMessage(value) {\n  return typeof value === \"string\" || isIcuMessage(value);\n}\nvar import_lookup_closest_locale, UIStrings;\nvar init_i18n = __esm({\n  \"core/lib/i18n/i18n.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_url();\n    import_lookup_closest_locale = __toESM(require_lookup_closest_locale(), 1);\n    init_lighthouse_logger();\n    init_format();\n    init_root2();\n    init_format();\n    init_esm_utils();\n    /**\n     * @license\n     * Copyright 2018 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    UIStrings = {\n      /** Used to show the duration in milliseconds that something lasted. The `{timeInMs}` placeholder will be replaced with the time duration, shown in milliseconds (e.g. 63 ms) */\n      ms: \"{timeInMs, number, milliseconds} ms\",\n      /** Used to show the duration in seconds that something lasted. The {timeInMs} placeholder will be replaced with the time duration, shown in seconds (e.g. 5.2 s) */\n      seconds: \"{timeInMs, number, seconds} s\",\n      /** Label shown per-audit to show how many bytes smaller the page could be if the user implemented the suggestions. The `{wastedBytes}` placeholder will be replaced with the number of bytes, shown in kibibytes (e.g. 148 KiB) */\n      displayValueByteSavings: \"Est savings of {wastedBytes, number, bytes} KiB\",\n      /** Label shown per-audit to show how many milliseconds faster the page load could be if the user implemented the suggestions. The `{wastedMs}` placeholder will be replaced with the time duration, shown in milliseconds (e.g. 140 ms) */\n      displayValueMsSavings: \"Est savings of {wastedMs, number, milliseconds} ms\",\n      /** Label shown per-audit to show how many HTML elements did not pass the audit. The `{# elements found}` placeholder will be replaced with the number of failing HTML elements. */\n      displayValueElementsFound: `{nodeCount, plural, =1 {1 element found} other {# elements found}}`,\n      /** Label for a column in a data table; entries will be the URL of a web resource */\n      columnURL: \"URL\",\n      /** Label for a column in a data table; entries will be the size or quantity of some resource, e.g. the width and height dimensions of an image or the number of images in a web page. */\n      columnSize: \"Size\",\n      /** Label for a column in a data table; entries will be the file size of a web resource in kilobytes. */\n      columnResourceSize: \"Resource Size\",\n      /** Label for a column in a data table; entries will be the download size of a web resource in kilobytes. */\n      columnTransferSize: \"Transfer Size\",\n      /** Label for a column in a data table; entries will be the time to live value of the cache header on a web resource. */\n      columnCacheTTL: \"Cache TTL\",\n      /** Label for a column in a data table; entries will be the number of kilobytes the user could reduce their page by if they implemented the suggestions. */\n      columnWastedBytes: \"Est Savings\",\n      /** Label for a column in a data table; entries will be the number of milliseconds the user could reduce page load by if they implemented the suggestions. */\n      columnWastedMs: \"Est Savings\",\n      /** Label for a table column that displays how much time each row spent blocking other work on the main thread, entries will be the number of milliseconds spent. */\n      columnBlockingTime: \"Main-Thread Blocking Time\",\n      /** Label for a column in a data table; entries will be the number of milliseconds spent during a particular activity. */\n      columnTimeSpent: \"Time Spent\",\n      /** Label for a column in a data table; entries will be the location of a specific line of code in a file, in the format \"line: 102\". */\n      columnLocation: \"Location\",\n      /** Label for a column in a data table; entries will be types of resources loaded over the network, e.g. \"Scripts\", \"Third-Party\", \"Stylesheet\". */\n      columnResourceType: \"Resource Type\",\n      /** Label for a column in a data table; entries will be the number of network requests done by a webpage. */\n      columnRequests: \"Requests\",\n      /** Label for a column in a data table; entries will be the names of arbitrary objects, e.g. the name of a Javascript library, or the name of a user defined timing event. */\n      columnName: \"Name\",\n      /** Label for a column in a data table; entries will be the locations of JavaScript or CSS code, e.g. the name of a Javascript package or module. */\n      columnSource: \"Source\",\n      /** Label for a column in a data table; entries will be a representation of a DOM element. */\n      columnElement: \"Element\",\n      /** Label for a column in a data table; entries will be the number of milliseconds since the page started loading. */\n      columnStartTime: \"Start Time\",\n      /** Label for a column in a data table; entries will be the total number of milliseconds from the start time until the end time. */\n      columnDuration: \"Duration\",\n      /** Label for a column in a data table; entries will be a representation of a DOM element that did not meet certain suggestions. */\n      columnFailingElem: \"Failing Elements\",\n      /** Label for a column in a data table; entries will be a description of the table item. */\n      columnDescription: \"Description\",\n      /** Label for a row in a data table; the row represents the total number of something. */\n      total: \"Total\",\n      /** Label for a row in a data table; entries will be the total number and byte size of all resources loaded by a web page. */\n      totalResourceType: \"Total\",\n      /** Label for a row in a data table; entries will be the total number and byte size of all 'Document' resources loaded by a web page. */\n      documentResourceType: \"Document\",\n      /** Label for a row in a data table; entries will be the total number and byte size of all 'Script' resources loaded by a web page. 'Script' refers to JavaScript or other files that are executable by a browser. */\n      scriptResourceType: \"Script\",\n      /** Label for a row in a data table; entries will be the total number and byte size of all 'Stylesheet' resources loaded by a web page. 'Stylesheet' refers to CSS stylesheets. */\n      stylesheetResourceType: \"Stylesheet\",\n      /** Label for a row in a data table; entries will be the total number and byte size of all 'Image' resources loaded by a web page. */\n      imageResourceType: \"Image\",\n      /** Label for a row in a data table; entries will be the total number and byte size of all 'Media' resources loaded by a web page. 'Media' refers to audio and video files. */\n      mediaResourceType: \"Media\",\n      /** Label for a row in a data table; entries will be the total number and byte size of all 'Font' resources loaded by a web page. */\n      fontResourceType: \"Font\",\n      /** Label for a row in a data table; entries will be the total number and byte size of all resources loaded by a web page that don't fit into the categories of Document, Script, Stylesheet, Image, Media, & Font.*/\n      otherResourceType: \"Other\",\n      /** Label for a row in a data table; entries will be the total number and byte size of all third-party resources loaded by a web page. 'Third-party resources are items loaded from URLs that aren't controlled by the owner of the web page. */\n      thirdPartyResourceType: \"Third-party\",\n      /** Label used to identify a value in a table where many individual values are aggregated to a single value, for brevity. \"Other resources\" could also be read as \"the rest of the resources\". Resource refers to network resources requested by the browser. */\n      otherResourcesLabel: \"Other resources\",\n      /** The name of the metric that marks the time at which the first text or image is painted by the browser. Shown to users as the label for the numeric metric value. Ideally fits within a ~40 character limit. */\n      firstContentfulPaintMetric: \"First Contentful Paint\",\n      /** The name of the metric that marks the time at which the page is fully loaded and is able to quickly respond to user input (clicks, taps, and keypresses feel responsive). Shown to users as the label for the numeric metric value. Ideally fits within a ~40 character limit. */\n      interactiveMetric: \"Time to Interactive\",\n      /** The name of the metric that marks the time at which a majority of the content has been painted by the browser. Shown to users as the label for the numeric metric value. Ideally fits within a ~40 character limit. */\n      firstMeaningfulPaintMetric: \"First Meaningful Paint\",\n      /** The name of a metric that calculates the total duration of blocking time for a web page. Blocking times are time periods when the page would be blocked (prevented) from responding to user input (clicks, taps, and keypresses will feel slow to respond). Shown to users as the label for the numeric metric value. Ideally fits within a ~40 character limit. */\n      totalBlockingTimeMetric: \"Total Blocking Time\",\n      /** The name of the metric \"Maximum Potential First Input Delay\" that marks the maximum estimated time between the page receiving input (a user clicking, tapping, or typing) and the page responding. Shown to users as the label for the numeric metric value. Ideally fits within a ~40 character limit. */\n      maxPotentialFIDMetric: \"Max Potential First Input Delay\",\n      /** The name of the metric that summarizes how quickly the page looked visually complete. The name of this metric is largely abstract and can be loosely translated. Shown to users as the label for the numeric metric value. Ideally fits within a ~40 character limit. */\n      speedIndexMetric: \"Speed Index\",\n      /** The name of the metric that marks the time at which the largest text or image is painted by the browser. Shown to users as the label for the numeric metric value. Ideally fits within a ~40 character limit. */\n      largestContentfulPaintMetric: \"Largest Contentful Paint\",\n      /** The name of the metric \"Cumulative Layout Shift\" that indicates how much the page changes its layout while it loads. If big segments of the page shift their location during load, the Cumulative Layout Shift will be higher. Shown to users as the label for the numeric metric value. Ideally fits within a ~40 character limit. */\n      cumulativeLayoutShiftMetric: \"Cumulative Layout Shift\",\n      /** The name of the \"Interaction to Next Paint\" metric that measures the time between a user interaction and when the browser displays a response on screen. Shown to users as the label for the numeric metric value. Ideally fits within a ~40 character limit. */\n      interactionToNextPaint: \"Interaction to Next Paint\",\n      /** Table item value for the severity of a small, or low impact vulnerability. Part of a ranking scale in the form: low, medium, high. */\n      itemSeverityLow: \"Low\",\n      /** Table item value for the severity of a vulnerability. Part of a ranking scale in the form: low, medium, high. */\n      itemSeverityMedium: \"Medium\",\n      /** Table item value for the severity of a high impact, or dangerous vulnerability. Part of a ranking scale in the form: low, medium, high. */\n      itemSeverityHigh: \"High\"\n    };\n    __name(lookupLocale, \"lookupLocale\");\n    __name(createIcuMessageFn, \"createIcuMessageFn\");\n    __name(isStringOrIcuMessage, \"isStringOrIcuMessage\");\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/lantern/core/LanternError.js\nvar LanternError;\nvar init_LanternError = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/lantern/core/LanternError.js\"() {\n    init_process_global();\n    LanternError = class extends Error {\n      static {\n        __name(this, \"LanternError\");\n      }\n    };\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/lantern/core/NetworkAnalyzer.js\nvar UrlUtils, INITIAL_CWD, DEFAULT_SERVER_RESPONSE_PERCENTAGE, SERVER_RESPONSE_PERCENTAGE_OF_TTFB, NetworkAnalyzer;\nvar init_NetworkAnalyzer = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/lantern/core/NetworkAnalyzer.js\"() {\n    init_process_global();\n    init_LanternError();\n    UrlUtils = class {\n      static {\n        __name(this, \"UrlUtils\");\n      }\n      /**\n       * There is fancy URL rewriting logic for the chrome://settings page that we need to work around.\n       * Why? Special handling was added by Chrome team to allow a pushState transition between chrome:// pages.\n       * As a result, the network URL (chrome://chrome/settings/) doesn't match the final document URL (chrome://settings/).\n       */\n      static rewriteChromeInternalUrl(url) {\n        if (!url?.startsWith(\"chrome://\")) {\n          return url;\n        }\n        if (url.endsWith(\"/\")) {\n          url = url.replace(/\\/$/, \"\");\n        }\n        return url.replace(/^chrome:\\/\\/chrome\\//, \"chrome://\");\n      }\n      /**\n       * Determine if url1 equals url2, ignoring URL fragments.\n       */\n      static equalWithExcludedFragments(url1, url2) {\n        [url1, url2] = [url1, url2].map(this.rewriteChromeInternalUrl);\n        try {\n          const urla = new URL(url1);\n          urla.hash = \"\";\n          const urlb = new URL(url2);\n          urlb.hash = \"\";\n          return urla.href === urlb.href;\n        } catch {\n          return false;\n        }\n      }\n    };\n    INITIAL_CWD = 14 * 1024;\n    DEFAULT_SERVER_RESPONSE_PERCENTAGE = 0.4;\n    SERVER_RESPONSE_PERCENTAGE_OF_TTFB = {\n      Document: 0.9,\n      XHR: 0.9,\n      Fetch: 0.9\n    };\n    NetworkAnalyzer = class _NetworkAnalyzer {\n      static {\n        __name(this, \"NetworkAnalyzer\");\n      }\n      static get summary() {\n        return \"__SUMMARY__\";\n      }\n      static groupByOrigin(records) {\n        const grouped = /* @__PURE__ */ new Map();\n        records.forEach((item) => {\n          const key = item.parsedURL.securityOrigin;\n          const group = grouped.get(key) || [];\n          group.push(item);\n          grouped.set(key, group);\n        });\n        return grouped;\n      }\n      static getSummary(values) {\n        values.sort((a, b) => a - b);\n        let median;\n        if (values.length === 0) {\n          median = values[0];\n        } else if (values.length % 2 === 0) {\n          const a = values[Math.floor((values.length - 1) / 2)];\n          const b = values[Math.floor((values.length - 1) / 2) + 1];\n          median = (a + b) / 2;\n        } else {\n          median = values[Math.floor((values.length - 1) / 2)];\n        }\n        return {\n          min: values[0],\n          max: values[values.length - 1],\n          avg: values.reduce((a, b) => a + b, 0) / values.length,\n          median\n        };\n      }\n      static summarize(values) {\n        const summaryByKey = /* @__PURE__ */ new Map();\n        const allEstimates = [];\n        for (const [key, estimates] of values) {\n          summaryByKey.set(key, _NetworkAnalyzer.getSummary(estimates));\n          allEstimates.push(...estimates);\n        }\n        summaryByKey.set(_NetworkAnalyzer.summary, _NetworkAnalyzer.getSummary(allEstimates));\n        return summaryByKey;\n      }\n      static estimateValueByOrigin(requests, iteratee) {\n        const connectionWasReused = _NetworkAnalyzer.estimateIfConnectionWasReused(requests);\n        const groupedByOrigin = _NetworkAnalyzer.groupByOrigin(requests);\n        const estimates = /* @__PURE__ */ new Map();\n        for (const [origin, originRequests] of groupedByOrigin.entries()) {\n          let originEstimates = [];\n          for (const request of originRequests) {\n            const timing = request.timing;\n            if (!timing) {\n              continue;\n            }\n            const value = iteratee({\n              request,\n              timing,\n              connectionReused: connectionWasReused.get(request.requestId)\n            });\n            if (typeof value !== \"undefined\") {\n              originEstimates = originEstimates.concat(value);\n            }\n          }\n          if (!originEstimates.length) {\n            continue;\n          }\n          estimates.set(origin, originEstimates);\n        }\n        return estimates;\n      }\n      /**\n       * Estimates the observed RTT to each origin based on how long the connection setup.\n       * For h1 and h2, this could includes two estimates - one for the TCP handshake, another for\n       * SSL negotiation.\n       * For h3, we get only one estimate since QUIC establishes a secure connection in a\n       * single handshake.\n       * This is the most accurate and preferred method of measurement when the data is available.\n       */\n      static estimateRTTViaConnectionTiming(info) {\n        const { timing, connectionReused, request } = info;\n        if (connectionReused) {\n          return;\n        }\n        const { connectStart, sslStart, sslEnd, connectEnd } = timing;\n        if (connectEnd >= 0 && connectStart >= 0 && request.protocol.startsWith(\"h3\")) {\n          return connectEnd - connectStart;\n        }\n        if (sslStart >= 0 && sslEnd >= 0 && sslStart !== connectStart) {\n          return [connectEnd - sslStart, sslStart - connectStart];\n        }\n        if (connectStart >= 0 && connectEnd >= 0) {\n          return connectEnd - connectStart;\n        }\n        return;\n      }\n      /**\n       * Estimates the observed RTT to each origin based on how long a download took on a fresh connection.\n       * NOTE: this will tend to overestimate the actual RTT quite significantly as the download can be\n       * slow for other reasons as well such as bandwidth constraints.\n       */\n      static estimateRTTViaDownloadTiming(info) {\n        const { timing, connectionReused, request } = info;\n        if (connectionReused) {\n          return;\n        }\n        if (request.transferSize <= INITIAL_CWD) {\n          return;\n        }\n        if (!Number.isFinite(timing.receiveHeadersEnd) || timing.receiveHeadersEnd < 0) {\n          return;\n        }\n        const totalTime = request.networkEndTime - request.networkRequestTime;\n        const downloadTimeAfterFirstByte = totalTime - timing.receiveHeadersEnd;\n        const numberOfRoundTrips = Math.log2(request.transferSize / INITIAL_CWD);\n        if (numberOfRoundTrips > 5) {\n          return;\n        }\n        return downloadTimeAfterFirstByte / numberOfRoundTrips;\n      }\n      /**\n       * Estimates the observed RTT to each origin based on how long it took until Chrome could\n       * start sending the actual request when a new connection was required.\n       * NOTE: this will tend to overestimate the actual RTT as the request can be delayed for other\n       * reasons as well such as more SSL handshakes if TLS False Start is not enabled.\n       */\n      static estimateRTTViaSendStartTiming(info) {\n        const { timing, connectionReused, request } = info;\n        if (connectionReused) {\n          return;\n        }\n        if (!Number.isFinite(timing.sendStart) || timing.sendStart < 0) {\n          return;\n        }\n        let roundTrips = 1;\n        if (!request.protocol.startsWith(\"h3\")) {\n          roundTrips += 1;\n        }\n        if (request.parsedURL.scheme === \"https\") {\n          roundTrips += 1;\n        }\n        return timing.sendStart / roundTrips;\n      }\n      /**\n       * Estimates the observed RTT to each origin based on how long it took until Chrome received the\n       * headers of the response (~TTFB).\n       * NOTE: this is the most inaccurate way to estimate the RTT, but in some environments it's all\n       * we have access to :(\n       */\n      static estimateRTTViaHeadersEndTiming(info) {\n        const { timing, connectionReused, request } = info;\n        if (!Number.isFinite(timing.receiveHeadersEnd) || timing.receiveHeadersEnd < 0) {\n          return;\n        }\n        if (!request.resourceType) {\n          return;\n        }\n        const serverResponseTimePercentage = SERVER_RESPONSE_PERCENTAGE_OF_TTFB[request.resourceType] || DEFAULT_SERVER_RESPONSE_PERCENTAGE;\n        const estimatedServerResponseTime = timing.receiveHeadersEnd * serverResponseTimePercentage;\n        let roundTrips = 1;\n        if (!connectionReused) {\n          roundTrips += 1;\n          if (!request.protocol.startsWith(\"h3\")) {\n            roundTrips += 1;\n          }\n          if (request.parsedURL.scheme === \"https\") {\n            roundTrips += 1;\n          }\n        }\n        return Math.max((timing.receiveHeadersEnd - estimatedServerResponseTime) / roundTrips, 3);\n      }\n      /**\n       * Given the RTT to each origin, estimates the observed server response times.\n       */\n      static estimateResponseTimeByOrigin(records, rttByOrigin) {\n        return _NetworkAnalyzer.estimateValueByOrigin(records, ({ request, timing }) => {\n          if (request.serverResponseTime !== void 0) {\n            return request.serverResponseTime;\n          }\n          if (!Number.isFinite(timing.receiveHeadersEnd) || timing.receiveHeadersEnd < 0) {\n            return;\n          }\n          if (!Number.isFinite(timing.sendEnd) || timing.sendEnd < 0) {\n            return;\n          }\n          const ttfb = timing.receiveHeadersEnd - timing.sendEnd;\n          const origin = request.parsedURL.securityOrigin;\n          const rtt = rttByOrigin.get(origin) || rttByOrigin.get(_NetworkAnalyzer.summary) || 0;\n          return Math.max(ttfb - rtt, 0);\n        });\n      }\n      static canTrustConnectionInformation(requests) {\n        const connectionIdWasStarted = /* @__PURE__ */ new Map();\n        for (const request of requests) {\n          const started = connectionIdWasStarted.get(request.connectionId) || !request.connectionReused;\n          connectionIdWasStarted.set(request.connectionId, started);\n        }\n        if (connectionIdWasStarted.size <= 1) {\n          return false;\n        }\n        return Array.from(connectionIdWasStarted.values()).every((started) => started);\n      }\n      /**\n       * Returns a map of requestId -> connectionReused, estimating the information if the information\n       * available in the records themselves appears untrustworthy.\n       */\n      static estimateIfConnectionWasReused(records, options) {\n        const { forceCoarseEstimates = false } = options || {};\n        if (!forceCoarseEstimates && _NetworkAnalyzer.canTrustConnectionInformation(records)) {\n          return new Map(records.map((request) => [request.requestId, Boolean(request.connectionReused)]));\n        }\n        const connectionWasReused = /* @__PURE__ */ new Map();\n        const groupedByOrigin = _NetworkAnalyzer.groupByOrigin(records);\n        for (const originRecords of groupedByOrigin.values()) {\n          const earliestReusePossible = originRecords.map((request) => request.networkEndTime).reduce((a, b) => Math.min(a, b), Infinity);\n          for (const request of originRecords) {\n            connectionWasReused.set(request.requestId, request.networkRequestTime >= earliestReusePossible || request.protocol === \"h2\");\n          }\n          const firstRecord = originRecords.reduce((a, b) => {\n            return a.networkRequestTime > b.networkRequestTime ? b : a;\n          });\n          connectionWasReused.set(firstRecord.requestId, false);\n        }\n        return connectionWasReused;\n      }\n      /**\n       * Estimates the RTT to each origin by examining observed network timing information.\n       * Attempts to use the most accurate information first and falls back to coarser estimates when it\n       * is unavailable.\n       */\n      static estimateRTTByOrigin(records, options) {\n        const {\n          forceCoarseEstimates = false,\n          // coarse estimates include lots of extra time and noise\n          // multiply by some factor to deflate the estimates a bit.\n          coarseEstimateMultiplier = 0.3,\n          useDownloadEstimates = true,\n          useSendStartEstimates = true,\n          useHeadersEndEstimates = true\n        } = options || {};\n        const connectionWasReused = _NetworkAnalyzer.estimateIfConnectionWasReused(records);\n        const groupedByOrigin = _NetworkAnalyzer.groupByOrigin(records);\n        const estimatesByOrigin = /* @__PURE__ */ new Map();\n        for (const [origin, originRequests] of groupedByOrigin.entries()) {\n          let collectEstimates = function(estimator, multiplier = 1) {\n            for (const request of originRequests) {\n              const timing = request.timing;\n              if (!timing || !request.transferSize) {\n                continue;\n              }\n              const estimates = estimator({\n                request,\n                timing,\n                connectionReused: connectionWasReused.get(request.requestId)\n              });\n              if (estimates === void 0) {\n                continue;\n              }\n              if (!Array.isArray(estimates)) {\n                originEstimates.push(estimates * multiplier);\n              } else {\n                originEstimates.push(...estimates.map((e) => e * multiplier));\n              }\n            }\n          };\n          __name(collectEstimates, \"collectEstimates\");\n          const originEstimates = [];\n          if (!forceCoarseEstimates) {\n            collectEstimates(this.estimateRTTViaConnectionTiming);\n          }\n          if (!originEstimates.length) {\n            if (useDownloadEstimates) {\n              collectEstimates(this.estimateRTTViaDownloadTiming, coarseEstimateMultiplier);\n            }\n            if (useSendStartEstimates) {\n              collectEstimates(this.estimateRTTViaSendStartTiming, coarseEstimateMultiplier);\n            }\n            if (useHeadersEndEstimates) {\n              collectEstimates(this.estimateRTTViaHeadersEndTiming, coarseEstimateMultiplier);\n            }\n          }\n          if (originEstimates.length) {\n            estimatesByOrigin.set(origin, originEstimates);\n          }\n        }\n        if (!estimatesByOrigin.size) {\n          throw new LanternError(\"No timing information available\");\n        }\n        return _NetworkAnalyzer.summarize(estimatesByOrigin);\n      }\n      /**\n       * Estimates the server response time of each origin. RTT times can be passed in or will be\n       * estimated automatically if not provided.\n       */\n      static estimateServerResponseTimeByOrigin(records, options) {\n        let rttByOrigin = options?.rttByOrigin;\n        if (!rttByOrigin) {\n          rttByOrigin = /* @__PURE__ */ new Map();\n          const rttSummaryByOrigin = _NetworkAnalyzer.estimateRTTByOrigin(records, options);\n          for (const [origin, summary] of rttSummaryByOrigin.entries()) {\n            rttByOrigin.set(origin, summary.min);\n          }\n        }\n        const estimatesByOrigin = _NetworkAnalyzer.estimateResponseTimeByOrigin(records, rttByOrigin);\n        return _NetworkAnalyzer.summarize(estimatesByOrigin);\n      }\n      /**\n       * Computes the average throughput for the given requests in bits/second.\n       * Excludes data URI, failed or otherwise incomplete, and cached requests.\n       * Returns null if there were no analyzable network requests.\n       */\n      static estimateThroughput(records) {\n        let totalBytes = 0;\n        const timeBoundaries = records.reduce((boundaries, request) => {\n          const scheme = request.parsedURL?.scheme;\n          if (scheme === \"data\" || request.failed || !request.finished || request.statusCode > 300 || !request.transferSize) {\n            return boundaries;\n          }\n          totalBytes += request.transferSize;\n          boundaries.push({ time: request.responseHeadersEndTime / 1e3, isStart: true });\n          boundaries.push({ time: request.networkEndTime / 1e3, isStart: false });\n          return boundaries;\n        }, []).sort((a, b) => a.time - b.time);\n        if (!timeBoundaries.length) {\n          return null;\n        }\n        let inflight = 0;\n        let currentStart = 0;\n        let totalDuration = 0;\n        timeBoundaries.forEach((boundary) => {\n          if (boundary.isStart) {\n            if (inflight === 0) {\n              currentStart = boundary.time;\n            }\n            inflight++;\n          } else {\n            inflight--;\n            if (inflight === 0) {\n              totalDuration += boundary.time - currentStart;\n            }\n          }\n        });\n        return totalBytes * 8 / totalDuration;\n      }\n      static computeRTTAndServerResponseTime(records) {\n        const rttByOrigin = /* @__PURE__ */ new Map();\n        for (const [origin, summary] of _NetworkAnalyzer.estimateRTTByOrigin(records).entries()) {\n          rttByOrigin.set(origin, summary.min);\n        }\n        const minimumRtt = Math.min(...Array.from(rttByOrigin.values()));\n        const responseTimeSummaries = _NetworkAnalyzer.estimateServerResponseTimeByOrigin(records, {\n          rttByOrigin\n        });\n        const additionalRttByOrigin = /* @__PURE__ */ new Map();\n        const serverResponseTimeByOrigin = /* @__PURE__ */ new Map();\n        for (const [origin, summary] of responseTimeSummaries.entries()) {\n          const rttForOrigin = rttByOrigin.get(origin) || minimumRtt;\n          additionalRttByOrigin.set(origin, rttForOrigin - minimumRtt);\n          serverResponseTimeByOrigin.set(origin, summary.median);\n        }\n        return {\n          rtt: minimumRtt,\n          additionalRttByOrigin,\n          serverResponseTimeByOrigin\n        };\n      }\n      static analyze(records) {\n        const throughput = _NetworkAnalyzer.estimateThroughput(records);\n        if (throughput === null) {\n          return null;\n        }\n        return {\n          throughput,\n          ..._NetworkAnalyzer.computeRTTAndServerResponseTime(records)\n        };\n      }\n      static findResourceForUrl(records, resourceUrl) {\n        return records.find((request) => resourceUrl.startsWith(request.url) && UrlUtils.equalWithExcludedFragments(request.url, resourceUrl));\n      }\n      static findLastDocumentForUrl(records, resourceUrl) {\n        const matchingRequests = records.filter((request) => request.resourceType === \"Document\" && !request.failed && // Note: `request.url` should never have a fragment, else this optimization gives wrong results.\n        resourceUrl.startsWith(request.url) && UrlUtils.equalWithExcludedFragments(request.url, resourceUrl));\n        return matchingRequests[matchingRequests.length - 1];\n      }\n      /**\n       * Resolves redirect chain given a main document.\n       * See: {@link NetworkAnalyzer.findLastDocumentForUrl} for how to retrieve main document.\n       */\n      static resolveRedirects(request) {\n        while (request.redirectDestination) {\n          request = request.redirectDestination;\n        }\n        return request;\n      }\n    };\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/lantern/core/core.js\nvar core_exports = {};\n__export(core_exports, {\n  LanternError: () => LanternError,\n  NetworkAnalyzer: () => NetworkAnalyzer\n});\nvar init_core = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/lantern/core/core.js\"() {\n    init_process_global();\n    init_LanternError();\n    init_NetworkAnalyzer();\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/lantern/graph/BaseNode.js\nvar BaseNode;\nvar init_BaseNode = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/lantern/graph/BaseNode.js\"() {\n    init_process_global();\n    init_core();\n    BaseNode = class _BaseNode {\n      static {\n        __name(this, \"BaseNode\");\n      }\n      static types = {\n        NETWORK: \"network\",\n        CPU: \"cpu\"\n      };\n      _id;\n      _isMainDocument;\n      dependents;\n      dependencies;\n      constructor(id) {\n        this._id = id;\n        this._isMainDocument = false;\n        this.dependents = [];\n        this.dependencies = [];\n      }\n      get id() {\n        return this._id;\n      }\n      get type() {\n        throw new LanternError(\"Unimplemented\");\n      }\n      /**\n       * In microseconds\n       */\n      get startTime() {\n        throw new LanternError(\"Unimplemented\");\n      }\n      /**\n       * In microseconds\n       */\n      get endTime() {\n        throw new LanternError(\"Unimplemented\");\n      }\n      setIsMainDocument(value) {\n        this._isMainDocument = value;\n      }\n      isMainDocument() {\n        return this._isMainDocument;\n      }\n      getDependents() {\n        return this.dependents.slice();\n      }\n      getNumberOfDependents() {\n        return this.dependents.length;\n      }\n      getDependencies() {\n        return this.dependencies.slice();\n      }\n      getNumberOfDependencies() {\n        return this.dependencies.length;\n      }\n      getRootNode() {\n        let rootNode = this;\n        while (rootNode.dependencies.length) {\n          rootNode = rootNode.dependencies[0];\n        }\n        return rootNode;\n      }\n      addDependent(node) {\n        node.addDependency(this);\n      }\n      addDependency(node) {\n        if (node === this) {\n          throw new LanternError(\"Cannot add dependency on itself\");\n        }\n        if (this.dependencies.includes(node)) {\n          return;\n        }\n        node.dependents.push(this);\n        this.dependencies.push(node);\n      }\n      removeDependent(node) {\n        node.removeDependency(this);\n      }\n      removeDependency(node) {\n        if (!this.dependencies.includes(node)) {\n          return;\n        }\n        const thisIndex = node.dependents.indexOf(this);\n        node.dependents.splice(thisIndex, 1);\n        this.dependencies.splice(this.dependencies.indexOf(node), 1);\n      }\n      // Unused in devtools, but used in LH.\n      removeAllDependencies() {\n        for (const node of this.dependencies.slice()) {\n          this.removeDependency(node);\n        }\n      }\n      /**\n       * Computes whether the given node is anywhere in the dependency graph of this node.\n       * While this method can prevent cycles, it walks the graph and should be used sparingly.\n       * Nodes are always considered dependent on themselves for the purposes of cycle detection.\n       */\n      isDependentOn(node) {\n        let isDependentOnNode = false;\n        this.traverse((currentNode) => {\n          if (isDependentOnNode) {\n            return;\n          }\n          isDependentOnNode = currentNode === node;\n        }, (currentNode) => {\n          if (isDependentOnNode) {\n            return [];\n          }\n          return currentNode.getDependencies();\n        });\n        return isDependentOnNode;\n      }\n      /**\n       * Clones the node's information without adding any dependencies/dependents.\n       */\n      cloneWithoutRelationships() {\n        const node = new _BaseNode(this.id);\n        node.setIsMainDocument(this._isMainDocument);\n        return node;\n      }\n      /**\n       * Clones the entire graph connected to this node filtered by the optional predicate. If a node is\n       * included by the predicate, all nodes along the paths between the node and the root will be included. If the\n       * node this was called on is not included in the resulting filtered graph, the method will throw.\n       *\n       * This does not clone NetworkNode's `record` or `rawRecord` fields. It may be reasonable to clone the former,\n       * to assist in graph construction, but the latter should never be cloned as one constraint of Lantern is that\n       * the underlying data records are accessible for plain object reference equality checks.\n       */\n      cloneWithRelationships(predicate) {\n        const rootNode = this.getRootNode();\n        const idsToIncludedClones = /* @__PURE__ */ new Map();\n        rootNode.traverse((node) => {\n          if (idsToIncludedClones.has(node.id)) {\n            return;\n          }\n          if (predicate === void 0) {\n            idsToIncludedClones.set(node.id, node.cloneWithoutRelationships());\n            return;\n          }\n          if (predicate(node)) {\n            node.traverse(\n              (node2) => idsToIncludedClones.set(node2.id, node2.cloneWithoutRelationships()),\n              // Dependencies already cloned have already cloned ancestors, so no need to visit again.\n              (node2) => node2.dependencies.filter((parent) => !idsToIncludedClones.has(parent.id))\n            );\n          }\n        });\n        rootNode.traverse((originalNode) => {\n          const clonedNode = idsToIncludedClones.get(originalNode.id);\n          if (!clonedNode) {\n            return;\n          }\n          for (const dependency of originalNode.dependencies) {\n            const clonedDependency = idsToIncludedClones.get(dependency.id);\n            if (!clonedDependency) {\n              throw new LanternError(\"Dependency somehow not cloned\");\n            }\n            clonedNode.addDependency(clonedDependency);\n          }\n        });\n        const clonedThisNode = idsToIncludedClones.get(this.id);\n        if (!clonedThisNode) {\n          throw new LanternError(\"Cloned graph missing node\");\n        }\n        return clonedThisNode;\n      }\n      /**\n       * Traverses all connected nodes in BFS order, calling `callback` exactly once\n       * on each. `traversalPath` is the shortest (though not necessarily unique)\n       * path from `node` to the root of the iteration.\n       *\n       * The `getNextNodes` function takes a visited node and returns which nodes to\n       * visit next. It defaults to returning the node's dependents.\n       */\n      traverse(callback, getNextNodes) {\n        for (const { node, traversalPath } of this.traverseGenerator(getNextNodes)) {\n          callback(node, traversalPath);\n        }\n      }\n      /**\n       * @see BaseNode.traverse\n       */\n      // clang-format off\n      *traverseGenerator(getNextNodes) {\n        if (!getNextNodes) {\n          getNextNodes = /* @__PURE__ */ __name((node) => node.getDependents(), \"getNextNodes\");\n        }\n        const queue = [[this]];\n        const visited = /* @__PURE__ */ new Set([this.id]);\n        while (queue.length) {\n          const traversalPath = queue.shift();\n          const node = traversalPath[0];\n          yield { node, traversalPath };\n          for (const nextNode of getNextNodes(node)) {\n            if (visited.has(nextNode.id)) {\n              continue;\n            }\n            visited.add(nextNode.id);\n            queue.push([nextNode, ...traversalPath]);\n          }\n        }\n      }\n      /**\n       * If the given node has a cycle, returns a path representing that cycle.\n       * Else returns null.\n       *\n       * Does a DFS on in its dependent graph.\n       */\n      static findCycle(node, direction = \"both\") {\n        if (direction === \"both\") {\n          return _BaseNode.findCycle(node, \"dependents\") || _BaseNode.findCycle(node, \"dependencies\");\n        }\n        const visited = /* @__PURE__ */ new Set();\n        const currentPath = [];\n        const toVisit = [node];\n        const depthAdded = /* @__PURE__ */ new Map([[node, 0]]);\n        while (toVisit.length) {\n          const currentNode = toVisit.pop();\n          if (currentPath.includes(currentNode)) {\n            return currentPath;\n          }\n          if (visited.has(currentNode)) {\n            continue;\n          }\n          while (currentPath.length > depthAdded.get(currentNode)) {\n            currentPath.pop();\n          }\n          visited.add(currentNode);\n          currentPath.push(currentNode);\n          const nodesToExplore = direction === \"dependents\" ? currentNode.dependents : currentNode.dependencies;\n          for (const nextNode of nodesToExplore) {\n            if (toVisit.includes(nextNode)) {\n              continue;\n            }\n            toVisit.push(nextNode);\n            depthAdded.set(nextNode, currentPath.length);\n          }\n        }\n        return null;\n      }\n      canDependOn(node) {\n        return node.startTime <= this.startTime;\n      }\n    };\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/lantern/graph/CPUNode.js\nvar CPUNode;\nvar init_CPUNode = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/lantern/graph/CPUNode.js\"() {\n    init_process_global();\n    init_BaseNode();\n    CPUNode = class _CPUNode extends BaseNode {\n      static {\n        __name(this, \"CPUNode\");\n      }\n      _event;\n      _childEvents;\n      correctedEndTs;\n      constructor(parentEvent, childEvents = [], correctedEndTs) {\n        const nodeId = `${parentEvent.tid}.${parentEvent.ts}`;\n        super(nodeId);\n        this._event = parentEvent;\n        this._childEvents = childEvents;\n        this.correctedEndTs = correctedEndTs;\n      }\n      get type() {\n        return BaseNode.types.CPU;\n      }\n      get startTime() {\n        return this._event.ts;\n      }\n      get endTime() {\n        if (this.correctedEndTs) {\n          return this.correctedEndTs;\n        }\n        return this._event.ts + this._event.dur;\n      }\n      get duration() {\n        return this.endTime - this.startTime;\n      }\n      get event() {\n        return this._event;\n      }\n      get childEvents() {\n        return this._childEvents;\n      }\n      /**\n       * Returns true if this node contains a Layout task.\n       */\n      didPerformLayout() {\n        return this._childEvents.some((evt) => evt.name === \"Layout\");\n      }\n      /**\n       * Returns the script URLs that had their EvaluateScript events occur in this task.\n       */\n      getEvaluateScriptURLs() {\n        const urls = /* @__PURE__ */ new Set();\n        for (const event of this._childEvents) {\n          if (event.name !== \"EvaluateScript\") {\n            continue;\n          }\n          if (!event.args.data?.url) {\n            continue;\n          }\n          urls.add(event.args.data.url);\n        }\n        return urls;\n      }\n      cloneWithoutRelationships() {\n        return new _CPUNode(this._event, this._childEvents, this.correctedEndTs);\n      }\n    };\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/lantern/graph/NetworkNode.js\nfunction isNonNetworkProtocol(protocol) {\n  const urlScheme = protocol.includes(\":\") ? protocol.slice(0, protocol.indexOf(\":\")) : protocol;\n  return NON_NETWORK_SCHEMES.includes(urlScheme);\n}\nvar NON_NETWORK_SCHEMES, NetworkNode;\nvar init_NetworkNode = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/lantern/graph/NetworkNode.js\"() {\n    init_process_global();\n    init_BaseNode();\n    NON_NETWORK_SCHEMES = [\n      \"blob\",\n      // @see https://developer.mozilla.org/en-US/docs/Web/API/URL/createObjectURL\n      \"data\",\n      // @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs\n      \"intent\",\n      // @see https://developer.chrome.com/docs/multidevice/android/intents/\n      \"file\",\n      // @see https://en.wikipedia.org/wiki/File_URI_scheme\n      \"filesystem\",\n      // @see https://developer.mozilla.org/en-US/docs/Web/API/FileSystem\n      \"chrome-extension\"\n    ];\n    __name(isNonNetworkProtocol, \"isNonNetworkProtocol\");\n    NetworkNode = class _NetworkNode extends BaseNode {\n      static {\n        __name(this, \"NetworkNode\");\n      }\n      _request;\n      constructor(networkRequest) {\n        super(networkRequest.requestId);\n        this._request = networkRequest;\n      }\n      get type() {\n        return BaseNode.types.NETWORK;\n      }\n      get startTime() {\n        return this._request.rendererStartTime * 1e3;\n      }\n      get endTime() {\n        return this._request.networkEndTime * 1e3;\n      }\n      get rawRequest() {\n        return this._request.rawRequest;\n      }\n      get request() {\n        return this._request;\n      }\n      get initiatorType() {\n        return this._request.initiator.type;\n      }\n      get fromDiskCache() {\n        return Boolean(this._request.fromDiskCache);\n      }\n      get isNonNetworkProtocol() {\n        return isNonNetworkProtocol(this.request.protocol) || // But `protocol` can fail to be populated if the request fails, so fallback to scheme.\n        isNonNetworkProtocol(this.request.parsedURL.scheme);\n      }\n      /**\n       * Returns whether this network request can be downloaded without a TCP connection.\n       * During simulation we treat data coming in over a network connection separately from on-device data.\n       */\n      get isConnectionless() {\n        return this.fromDiskCache || this.isNonNetworkProtocol;\n      }\n      hasRenderBlockingPriority() {\n        const priority = this._request.priority;\n        const isScript = this._request.resourceType === \"Script\";\n        const isDocument = this._request.resourceType === \"Document\";\n        const isBlockingScript = priority === \"High\" && isScript;\n        const isBlockingHtmlImport = priority === \"High\" && isDocument;\n        return priority === \"VeryHigh\" || isBlockingScript || isBlockingHtmlImport;\n      }\n      cloneWithoutRelationships() {\n        const node = new _NetworkNode(this._request);\n        node.setIsMainDocument(this._isMainDocument);\n        return node;\n      }\n    };\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/lantern/graph/PageDependencyGraph.js\nvar SCHEDULABLE_TASK_TITLE_LH, SCHEDULABLE_TASK_TITLE_ALT1, SCHEDULABLE_TASK_TITLE_ALT2, SCHEDULABLE_TASK_TITLE_ALT3, SIGNIFICANT_DUR_THRESHOLD_MS, IGNORED_MIME_TYPES_REGEX, PageDependencyGraph;\nvar init_PageDependencyGraph = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/lantern/graph/PageDependencyGraph.js\"() {\n    init_process_global();\n    init_core();\n    init_CPUNode();\n    init_NetworkNode();\n    SCHEDULABLE_TASK_TITLE_LH = \"RunTask\";\n    SCHEDULABLE_TASK_TITLE_ALT1 = \"ThreadControllerImpl::RunTask\";\n    SCHEDULABLE_TASK_TITLE_ALT2 = \"ThreadControllerImpl::DoWork\";\n    SCHEDULABLE_TASK_TITLE_ALT3 = \"TaskQueueManager::ProcessTaskFromWorkQueue\";\n    SIGNIFICANT_DUR_THRESHOLD_MS = 10;\n    IGNORED_MIME_TYPES_REGEX = /^video/;\n    PageDependencyGraph = class _PageDependencyGraph {\n      static {\n        __name(this, \"PageDependencyGraph\");\n      }\n      static getNetworkInitiators(request) {\n        if (!request.initiator) {\n          return [];\n        }\n        if (request.initiator.url) {\n          return [request.initiator.url];\n        }\n        if (request.initiator.type === \"script\") {\n          const scriptURLs = /* @__PURE__ */ new Set();\n          let stack = request.initiator.stack;\n          while (stack) {\n            const callFrames = stack.callFrames || [];\n            for (const frame of callFrames) {\n              if (frame.url) {\n                scriptURLs.add(frame.url);\n              }\n            }\n            stack = stack.parent;\n          }\n          return Array.from(scriptURLs);\n        }\n        return [];\n      }\n      static getNetworkNodeOutput(networkRequests) {\n        const nodes = [];\n        const idToNodeMap = /* @__PURE__ */ new Map();\n        const urlToNodeMap = /* @__PURE__ */ new Map();\n        const frameIdToNodeMap = /* @__PURE__ */ new Map();\n        networkRequests.forEach((request) => {\n          if (IGNORED_MIME_TYPES_REGEX.test(request.mimeType)) {\n            return;\n          }\n          if (request.fromWorker) {\n            return;\n          }\n          while (idToNodeMap.has(request.requestId)) {\n            request.requestId += \":duplicate\";\n          }\n          const node = new NetworkNode(request);\n          nodes.push(node);\n          const urlList = urlToNodeMap.get(request.url) || [];\n          urlList.push(node);\n          idToNodeMap.set(request.requestId, node);\n          urlToNodeMap.set(request.url, urlList);\n          if (request.frameId && request.resourceType === \"Document\" && request.documentURL === request.url) {\n            const value = frameIdToNodeMap.has(request.frameId) ? null : node;\n            frameIdToNodeMap.set(request.frameId, value);\n          }\n        });\n        return { nodes, idToNodeMap, urlToNodeMap, frameIdToNodeMap };\n      }\n      static isScheduleableTask(evt) {\n        return evt.name === SCHEDULABLE_TASK_TITLE_LH || evt.name === SCHEDULABLE_TASK_TITLE_ALT1 || evt.name === SCHEDULABLE_TASK_TITLE_ALT2 || evt.name === SCHEDULABLE_TASK_TITLE_ALT3;\n      }\n      /**\n       * There should *always* be at least one top level event, having 0 typically means something is\n       * drastically wrong with the trace and we should just give up early and loudly.\n       */\n      static assertHasToplevelEvents(events) {\n        const hasToplevelTask = events.some(this.isScheduleableTask);\n        if (!hasToplevelTask) {\n          throw new LanternError(\"Could not find any top level events\");\n        }\n      }\n      static getCPUNodes(mainThreadEvents) {\n        const nodes = [];\n        let i = 0;\n        _PageDependencyGraph.assertHasToplevelEvents(mainThreadEvents);\n        while (i < mainThreadEvents.length) {\n          const evt = mainThreadEvents[i];\n          i++;\n          if (!_PageDependencyGraph.isScheduleableTask(evt) || !evt.dur) {\n            continue;\n          }\n          let correctedEndTs = void 0;\n          const children = [];\n          for (const endTime = evt.ts + evt.dur; i < mainThreadEvents.length && mainThreadEvents[i].ts < endTime; i++) {\n            const event = mainThreadEvents[i];\n            if (_PageDependencyGraph.isScheduleableTask(event) && event.dur) {\n              correctedEndTs = event.ts - 1;\n              break;\n            }\n            children.push(event);\n          }\n          nodes.push(new CPUNode(evt, children, correctedEndTs));\n        }\n        return nodes;\n      }\n      static linkNetworkNodes(rootNode, networkNodeOutput) {\n        networkNodeOutput.nodes.forEach((node) => {\n          const directInitiatorRequest = node.request.initiatorRequest || rootNode.request;\n          const directInitiatorNode = networkNodeOutput.idToNodeMap.get(directInitiatorRequest.requestId) || rootNode;\n          const canDependOnInitiator = !directInitiatorNode.isDependentOn(node) && node.canDependOn(directInitiatorNode);\n          const initiators = _PageDependencyGraph.getNetworkInitiators(node.request);\n          if (initiators.length) {\n            initiators.forEach((initiator) => {\n              const parentCandidates = networkNodeOutput.urlToNodeMap.get(initiator) || [];\n              if (parentCandidates.length === 1 && parentCandidates[0].startTime <= node.startTime && !parentCandidates[0].isDependentOn(node)) {\n                node.addDependency(parentCandidates[0]);\n              } else if (canDependOnInitiator) {\n                directInitiatorNode.addDependent(node);\n              }\n            });\n          } else if (canDependOnInitiator) {\n            directInitiatorNode.addDependent(node);\n          }\n          if (node !== rootNode && node.getDependencies().length === 0 && node.canDependOn(rootNode)) {\n            node.addDependency(rootNode);\n          }\n          if (!node.request.redirects) {\n            return;\n          }\n          const redirects = [...node.request.redirects, node.request];\n          for (let i = 1; i < redirects.length; i++) {\n            const redirectNode = networkNodeOutput.idToNodeMap.get(redirects[i - 1].requestId);\n            const actualNode = networkNodeOutput.idToNodeMap.get(redirects[i].requestId);\n            if (actualNode && redirectNode) {\n              actualNode.addDependency(redirectNode);\n            }\n          }\n        });\n      }\n      static linkCPUNodes(rootNode, networkNodeOutput, cpuNodes) {\n        const linkableResourceTypes = /* @__PURE__ */ new Set([\n          \"XHR\",\n          \"Fetch\",\n          \"Script\"\n        ]);\n        function addDependentNetworkRequest(cpuNode, reqId) {\n          const networkNode = networkNodeOutput.idToNodeMap.get(reqId);\n          if (!networkNode || // Ignore all network nodes that started before this CPU task started\n          // A network request that started earlier could not possibly have been started by this task\n          networkNode.startTime <= cpuNode.startTime) {\n            return;\n          }\n          const { request } = networkNode;\n          const resourceType = request.resourceType || request.redirectDestination?.resourceType;\n          if (!linkableResourceTypes.has(resourceType)) {\n            return;\n          }\n          cpuNode.addDependent(networkNode);\n        }\n        __name(addDependentNetworkRequest, \"addDependentNetworkRequest\");\n        function addDependencyOnFrame(cpuNode, frameId) {\n          if (!frameId) {\n            return;\n          }\n          const networkNode = networkNodeOutput.frameIdToNodeMap.get(frameId);\n          if (!networkNode) {\n            return;\n          }\n          if (networkNode.startTime >= cpuNode.startTime) {\n            return;\n          }\n          cpuNode.addDependency(networkNode);\n        }\n        __name(addDependencyOnFrame, \"addDependencyOnFrame\");\n        function addDependencyOnUrl(cpuNode, url) {\n          if (!url) {\n            return;\n          }\n          const minimumAllowableTimeSinceNetworkNodeEnd = -100 * 1e3;\n          const candidates = networkNodeOutput.urlToNodeMap.get(url) || [];\n          let minCandidate = null;\n          let minDistance = Infinity;\n          for (const candidate of candidates) {\n            if (cpuNode.startTime <= candidate.startTime) {\n              return;\n            }\n            const distance = cpuNode.startTime - candidate.endTime;\n            if (distance >= minimumAllowableTimeSinceNetworkNodeEnd && distance < minDistance) {\n              minCandidate = candidate;\n              minDistance = distance;\n            }\n          }\n          if (!minCandidate) {\n            return;\n          }\n          cpuNode.addDependency(minCandidate);\n        }\n        __name(addDependencyOnUrl, \"addDependencyOnUrl\");\n        const timers = /* @__PURE__ */ new Map();\n        for (const node of cpuNodes) {\n          for (const evt of node.childEvents) {\n            if (!evt.args.data) {\n              continue;\n            }\n            const argsUrl = evt.args.data.url;\n            const stackTraceUrls = (evt.args.data.stackTrace || []).map((l) => l.url).filter(Boolean);\n            switch (evt.name) {\n              case \"TimerInstall\":\n                timers.set(evt.args.data.timerId, node);\n                stackTraceUrls.forEach((url) => addDependencyOnUrl(node, url));\n                break;\n              case \"TimerFire\": {\n                const installer = timers.get(evt.args.data.timerId);\n                if (!installer || installer.endTime > node.startTime) {\n                  break;\n                }\n                installer.addDependent(node);\n                break;\n              }\n              case \"InvalidateLayout\":\n              case \"ScheduleStyleRecalculation\":\n                addDependencyOnFrame(node, evt.args.data.frame);\n                stackTraceUrls.forEach((url) => addDependencyOnUrl(node, url));\n                break;\n              case \"EvaluateScript\":\n                addDependencyOnFrame(node, evt.args.data.frame);\n                addDependencyOnUrl(node, argsUrl);\n                stackTraceUrls.forEach((url) => addDependencyOnUrl(node, url));\n                break;\n              case \"XHRReadyStateChange\":\n                if (evt.args.data.readyState !== 4) {\n                  break;\n                }\n                addDependencyOnUrl(node, argsUrl);\n                stackTraceUrls.forEach((url) => addDependencyOnUrl(node, url));\n                break;\n              case \"FunctionCall\":\n              case \"v8.compile\":\n                addDependencyOnFrame(node, evt.args.data.frame);\n                addDependencyOnUrl(node, argsUrl);\n                break;\n              case \"ParseAuthorStyleSheet\":\n                addDependencyOnFrame(node, evt.args.data.frame);\n                addDependencyOnUrl(node, evt.args.data.styleSheetUrl);\n                break;\n              case \"ResourceSendRequest\":\n                addDependencyOnFrame(node, evt.args.data.frame);\n                addDependentNetworkRequest(node, evt.args.data.requestId);\n                stackTraceUrls.forEach((url) => addDependencyOnUrl(node, url));\n                break;\n            }\n          }\n          if (node.getNumberOfDependencies() === 0 && node.canDependOn(rootNode)) {\n            node.addDependency(rootNode);\n          }\n        }\n        const minimumEvtDur = SIGNIFICANT_DUR_THRESHOLD_MS * 1e3;\n        let foundFirstLayout = false;\n        let foundFirstPaint = false;\n        let foundFirstParse = false;\n        for (const node of cpuNodes) {\n          let isFirst = false;\n          if (!foundFirstLayout && node.childEvents.some((evt) => evt.name === \"Layout\")) {\n            isFirst = foundFirstLayout = true;\n          }\n          if (!foundFirstPaint && node.childEvents.some((evt) => evt.name === \"Paint\")) {\n            isFirst = foundFirstPaint = true;\n          }\n          if (!foundFirstParse && node.childEvents.some((evt) => evt.name === \"ParseHTML\")) {\n            isFirst = foundFirstParse = true;\n          }\n          if (isFirst || node.duration >= minimumEvtDur) {\n            continue;\n          }\n          if (node.getNumberOfDependencies() === 1 || node.getNumberOfDependents() <= 1) {\n            _PageDependencyGraph.pruneNode(node);\n          }\n        }\n      }\n      /**\n       * Removes the given node from the graph, but retains all paths between its dependencies and\n       * dependents.\n       */\n      static pruneNode(node) {\n        const dependencies = node.getDependencies();\n        const dependents = node.getDependents();\n        for (const dependency of dependencies) {\n          node.removeDependency(dependency);\n          for (const dependent of dependents) {\n            dependency.addDependent(dependent);\n          }\n        }\n        for (const dependent of dependents) {\n          node.removeDependent(dependent);\n        }\n      }\n      /**\n       * TODO: remove when CDT backend in Lighthouse is gone. Until then, this is a useful debugging tool\n       * to find delta between using CDP or the trace to create the network requests.\n       *\n       * When a test fails using the trace backend, I enabled this debug method and copied the network\n       * requests when CDP was used, then when trace is used, and diff'd them. This method helped\n       * remove non-logical differences from the comparison (order of properties, slight rounding\n       * discrepancies, removing object cycles, etc).\n       *\n       * When using for a unit test, make sure to do `.only` so you are getting what you expect.\n       */\n      static debugNormalizeRequests(lanternRequests) {\n        for (const request of lanternRequests) {\n          request.rendererStartTime = Math.round(request.rendererStartTime * 1e3) / 1e3;\n          request.networkRequestTime = Math.round(request.networkRequestTime * 1e3) / 1e3;\n          request.responseHeadersEndTime = Math.round(request.responseHeadersEndTime * 1e3) / 1e3;\n          request.networkEndTime = Math.round(request.networkEndTime * 1e3) / 1e3;\n        }\n        for (const r of lanternRequests) {\n          delete r.rawRequest;\n          if (r.initiatorRequest) {\n            r.initiatorRequest = { id: r.initiatorRequest.requestId };\n          }\n          if (r.redirectDestination) {\n            r.redirectDestination = { id: r.redirectDestination.requestId };\n          }\n          if (r.redirectSource) {\n            r.redirectSource = { id: r.redirectSource.requestId };\n          }\n          if (r.redirects) {\n            r.redirects = r.redirects.map((r2) => r2.requestId);\n          }\n        }\n        const requests = lanternRequests.map((r) => ({\n          requestId: r.requestId,\n          connectionId: r.connectionId,\n          connectionReused: r.connectionReused,\n          url: r.url,\n          protocol: r.protocol,\n          parsedURL: r.parsedURL,\n          documentURL: r.documentURL,\n          rendererStartTime: r.rendererStartTime,\n          networkRequestTime: r.networkRequestTime,\n          responseHeadersEndTime: r.responseHeadersEndTime,\n          networkEndTime: r.networkEndTime,\n          transferSize: r.transferSize,\n          resourceSize: r.resourceSize,\n          fromDiskCache: r.fromDiskCache,\n          fromMemoryCache: r.fromMemoryCache,\n          finished: r.finished,\n          statusCode: r.statusCode,\n          redirectSource: r.redirectSource,\n          redirectDestination: r.redirectDestination,\n          redirects: r.redirects,\n          failed: r.failed,\n          initiator: r.initiator,\n          timing: r.timing ? {\n            requestTime: r.timing.requestTime,\n            proxyStart: r.timing.proxyStart,\n            proxyEnd: r.timing.proxyEnd,\n            dnsStart: r.timing.dnsStart,\n            dnsEnd: r.timing.dnsEnd,\n            connectStart: r.timing.connectStart,\n            connectEnd: r.timing.connectEnd,\n            sslStart: r.timing.sslStart,\n            sslEnd: r.timing.sslEnd,\n            workerStart: r.timing.workerStart,\n            workerReady: r.timing.workerReady,\n            workerFetchStart: r.timing.workerFetchStart,\n            workerRespondWithSettled: r.timing.workerRespondWithSettled,\n            sendStart: r.timing.sendStart,\n            sendEnd: r.timing.sendEnd,\n            pushStart: r.timing.pushStart,\n            pushEnd: r.timing.pushEnd,\n            receiveHeadersStart: r.timing.receiveHeadersStart,\n            receiveHeadersEnd: r.timing.receiveHeadersEnd\n          } : r.timing,\n          resourceType: r.resourceType,\n          mimeType: r.mimeType,\n          priority: r.priority,\n          initiatorRequest: r.initiatorRequest,\n          frameId: r.frameId,\n          fromWorker: r.fromWorker,\n          isLinkPreload: r.isLinkPreload,\n          serverResponseTime: r.serverResponseTime\n        })).filter((r) => !r.fromWorker);\n        const debug2 = requests;\n        console.log(debug2);\n      }\n      static createGraph(mainThreadEvents, networkRequests, url) {\n        const networkNodeOutput = _PageDependencyGraph.getNetworkNodeOutput(networkRequests);\n        const cpuNodes = _PageDependencyGraph.getCPUNodes(mainThreadEvents);\n        const { requestedUrl, mainDocumentUrl } = url;\n        if (!requestedUrl) {\n          throw new LanternError(\"requestedUrl is required to get the root request\");\n        }\n        if (!mainDocumentUrl) {\n          throw new LanternError(\"mainDocumentUrl is required to get the main resource\");\n        }\n        const rootRequest = NetworkAnalyzer.findResourceForUrl(networkRequests, requestedUrl);\n        if (!rootRequest) {\n          throw new LanternError(\"rootRequest not found\");\n        }\n        const rootNode = networkNodeOutput.idToNodeMap.get(rootRequest.requestId);\n        if (!rootNode) {\n          throw new LanternError(\"rootNode not found\");\n        }\n        const mainDocumentRequest = NetworkAnalyzer.findLastDocumentForUrl(networkRequests, mainDocumentUrl);\n        if (!mainDocumentRequest) {\n          throw new LanternError(\"mainDocumentRequest not found\");\n        }\n        const mainDocumentNode = networkNodeOutput.idToNodeMap.get(mainDocumentRequest.requestId);\n        if (!mainDocumentNode) {\n          throw new LanternError(\"mainDocumentNode not found\");\n        }\n        _PageDependencyGraph.linkNetworkNodes(rootNode, networkNodeOutput);\n        _PageDependencyGraph.linkCPUNodes(rootNode, networkNodeOutput, cpuNodes);\n        mainDocumentNode.setIsMainDocument(true);\n        if (NetworkNode.findCycle(rootNode)) {\n          throw new LanternError(\"Invalid dependency graph created, cycle detected\");\n        }\n        return rootNode;\n      }\n      // Unused, but useful for debugging.\n      static printGraph(rootNode, widthInCharacters = 80) {\n        function padRight(str, target, padChar = \" \") {\n          return str + padChar.repeat(Math.max(target - str.length, 0));\n        }\n        __name(padRight, \"padRight\");\n        const nodes = [];\n        rootNode.traverse((node) => nodes.push(node));\n        nodes.sort((a, b) => a.startTime - b.startTime);\n        const nodeToLabel = /* @__PURE__ */ new Map();\n        rootNode.traverse((node) => {\n          const ascii = 65 + nodeToLabel.size;\n          let label;\n          if (ascii > 90) {\n            label = `Z${ascii - 90}`;\n          } else {\n            label = String.fromCharCode(ascii);\n          }\n          nodeToLabel.set(node, label);\n        });\n        const min = nodes[0].startTime;\n        const max = nodes.reduce((max2, node) => Math.max(max2, node.endTime), 0);\n        const totalTime = max - min;\n        const timePerCharacter = totalTime / widthInCharacters;\n        nodes.forEach((node) => {\n          const offset = Math.round((node.startTime - min) / timePerCharacter);\n          const length = Math.ceil((node.endTime - node.startTime) / timePerCharacter);\n          const bar = padRight(\"\", offset) + padRight(\"\", length, \"=\");\n          const displayName = node.request ? node.request.url : node.type;\n          console.log(padRight(bar, widthInCharacters), `| ${displayName.slice(0, 50)}`);\n        });\n        console.log();\n        nodes.forEach((node) => {\n          const displayName = node.request ? node.request.url : node.type;\n          console.log(nodeToLabel.get(node), displayName.slice(0, widthInCharacters - 5));\n          for (const child of node.dependents) {\n            const displayName2 = child.request ? child.request.url : child.type;\n            console.log(\"  ->\", nodeToLabel.get(child), displayName2.slice(0, widthInCharacters - 10));\n          }\n          console.log();\n        });\n        const cyclePath = NetworkNode.findCycle(rootNode);\n        console.log(\"Cycle?\", cyclePath ? \"yes\" : \"no\");\n        if (cyclePath) {\n          const path7 = [...cyclePath];\n          path7.push(path7[0]);\n          console.log(path7.map((node) => nodeToLabel.get(node)).join(\" -> \"));\n        }\n      }\n    };\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/lantern/graph/graph.js\nvar graph_exports = {};\n__export(graph_exports, {\n  BaseNode: () => BaseNode,\n  CPUNode: () => CPUNode,\n  NetworkNode: () => NetworkNode,\n  PageDependencyGraph: () => PageDependencyGraph\n});\nvar init_graph = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/lantern/graph/graph.js\"() {\n    init_process_global();\n    init_BaseNode();\n    init_CPUNode();\n    init_NetworkNode();\n    init_PageDependencyGraph();\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/lantern/metrics/Metric.js\nvar Metric;\nvar init_Metric = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/lantern/metrics/Metric.js\"() {\n    init_process_global();\n    init_core();\n    init_graph();\n    Metric = class {\n      static {\n        __name(this, \"Metric\");\n      }\n      static getScriptUrls(dependencyGraph, treatNodeAsRenderBlocking) {\n        const scriptUrls = /* @__PURE__ */ new Set();\n        dependencyGraph.traverse((node) => {\n          if (node.type !== BaseNode.types.NETWORK) {\n            return;\n          }\n          if (node.request.resourceType !== \"Script\") {\n            return;\n          }\n          if (treatNodeAsRenderBlocking?.(node)) {\n            scriptUrls.add(node.request.url);\n          }\n        });\n        return scriptUrls;\n      }\n      static get coefficients() {\n        throw new LanternError(\"coefficients unimplemented!\");\n      }\n      /**\n       * Returns the coefficients, scaled by the throttling settings if needed by the metric.\n       * Some lantern metrics (speed-index) use components in their estimate that are not\n       * from the simulator. In this case, we need to adjust the coefficients as the target throttling\n       * settings change.\n       */\n      static getScaledCoefficients(_rttMs) {\n        return this.coefficients;\n      }\n      static getOptimisticGraph(_dependencyGraph, _processedNavigation) {\n        throw new LanternError(\"Optimistic graph unimplemented!\");\n      }\n      static getPessimisticGraph(_dependencyGraph, _processedNavigation) {\n        throw new LanternError(\"Pessmistic graph unimplemented!\");\n      }\n      static getEstimateFromSimulation(simulationResult, _extras) {\n        return simulationResult;\n      }\n      static compute(data31, extras) {\n        const { simulator, graph: graph2, processedNavigation } = data31;\n        const metricName = this.name.replace(\"Lantern\", \"\");\n        const optimisticGraph = this.getOptimisticGraph(graph2, processedNavigation);\n        const pessimisticGraph = this.getPessimisticGraph(graph2, processedNavigation);\n        let simulateOptions = { label: `optimistic${metricName}` };\n        const optimisticSimulation = simulator.simulate(optimisticGraph, simulateOptions);\n        simulateOptions = { label: `pessimistic${metricName}` };\n        const pessimisticSimulation = simulator.simulate(pessimisticGraph, simulateOptions);\n        const optimisticEstimate = this.getEstimateFromSimulation(optimisticSimulation, { ...extras, optimistic: true });\n        const pessimisticEstimate = this.getEstimateFromSimulation(pessimisticSimulation, { ...extras, optimistic: false });\n        const coefficients = this.getScaledCoefficients(simulator.rtt);\n        const interceptMultiplier = coefficients.intercept > 0 ? Math.min(1, optimisticEstimate.timeInMs / 1e3) : 1;\n        const timing = coefficients.intercept * interceptMultiplier + coefficients.optimistic * optimisticEstimate.timeInMs + coefficients.pessimistic * pessimisticEstimate.timeInMs;\n        return {\n          timing,\n          optimisticEstimate,\n          pessimisticEstimate,\n          optimisticGraph,\n          pessimisticGraph\n        };\n      }\n    };\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/lantern/metrics/FirstContentfulPaint.js\nvar FirstContentfulPaint;\nvar init_FirstContentfulPaint = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/lantern/metrics/FirstContentfulPaint.js\"() {\n    init_process_global();\n    init_graph();\n    init_Metric();\n    FirstContentfulPaint = class extends Metric {\n      static {\n        __name(this, \"FirstContentfulPaint\");\n      }\n      static get coefficients() {\n        return {\n          intercept: 0,\n          optimistic: 0.5,\n          pessimistic: 0.5\n        };\n      }\n      /**\n       * Computes the set of URLs that *appeared* to be render-blocking based on our filter,\n       * *but definitely were not* render-blocking based on the timing of their EvaluateScript task.\n       * It also computes the set of corresponding CPU node ids that were needed for the paint at the\n       * given timestamp.\n       */\n      static getRenderBlockingNodeData(graph2, { cutoffTimestamp, treatNodeAsRenderBlocking, additionalCpuNodesToTreatAsRenderBlocking }) {\n        const scriptUrlToNodeMap = /* @__PURE__ */ new Map();\n        const cpuNodes = [];\n        graph2.traverse((node) => {\n          if (node.type === BaseNode.types.CPU) {\n            if (node.startTime <= cutoffTimestamp) {\n              cpuNodes.push(node);\n            }\n            const scriptUrls = node.getEvaluateScriptURLs();\n            for (const url of scriptUrls) {\n              const existing = scriptUrlToNodeMap.get(url) || node;\n              scriptUrlToNodeMap.set(url, node.startTime < existing.startTime ? node : existing);\n            }\n          }\n        });\n        cpuNodes.sort((a, b) => a.startTime - b.startTime);\n        const possiblyRenderBlockingScriptUrls = Metric.getScriptUrls(graph2, (node) => {\n          return node.endTime <= cutoffTimestamp && treatNodeAsRenderBlocking(node);\n        });\n        const definitelyNotRenderBlockingScriptUrls = /* @__PURE__ */ new Set();\n        const renderBlockingCpuNodeIds = /* @__PURE__ */ new Set();\n        for (const url of possiblyRenderBlockingScriptUrls) {\n          const cpuNodeForUrl = scriptUrlToNodeMap.get(url);\n          if (!cpuNodeForUrl) {\n            continue;\n          }\n          if (cpuNodes.includes(cpuNodeForUrl)) {\n            renderBlockingCpuNodeIds.add(cpuNodeForUrl.id);\n            continue;\n          }\n          definitelyNotRenderBlockingScriptUrls.add(url);\n        }\n        const firstLayout = cpuNodes.find((node) => node.didPerformLayout());\n        if (firstLayout) {\n          renderBlockingCpuNodeIds.add(firstLayout.id);\n        }\n        const firstPaint = cpuNodes.find((node) => node.childEvents.some((e) => e.name === \"Paint\"));\n        if (firstPaint) {\n          renderBlockingCpuNodeIds.add(firstPaint.id);\n        }\n        const firstParse = cpuNodes.find((node) => node.childEvents.some((e) => e.name === \"ParseHTML\"));\n        if (firstParse) {\n          renderBlockingCpuNodeIds.add(firstParse.id);\n        }\n        if (additionalCpuNodesToTreatAsRenderBlocking) {\n          cpuNodes.filter(additionalCpuNodesToTreatAsRenderBlocking).forEach((node) => renderBlockingCpuNodeIds.add(node.id));\n        }\n        return {\n          definitelyNotRenderBlockingScriptUrls,\n          renderBlockingCpuNodeIds\n        };\n      }\n      /**\n       * Computes the graph required for the first paint of interest.\n       */\n      static getFirstPaintBasedGraph(dependencyGraph, { cutoffTimestamp, treatNodeAsRenderBlocking, additionalCpuNodesToTreatAsRenderBlocking }) {\n        const rbData = this.getRenderBlockingNodeData(dependencyGraph, {\n          cutoffTimestamp,\n          treatNodeAsRenderBlocking,\n          additionalCpuNodesToTreatAsRenderBlocking\n        });\n        const { definitelyNotRenderBlockingScriptUrls, renderBlockingCpuNodeIds } = rbData;\n        return dependencyGraph.cloneWithRelationships((node) => {\n          if (node.type === BaseNode.types.NETWORK) {\n            const endedAfterPaint = node.endTime > cutoffTimestamp || node.startTime > cutoffTimestamp;\n            if (endedAfterPaint && !node.isMainDocument()) {\n              return false;\n            }\n            const url = node.request.url;\n            if (definitelyNotRenderBlockingScriptUrls.has(url)) {\n              return false;\n            }\n            return treatNodeAsRenderBlocking(node);\n          }\n          return renderBlockingCpuNodeIds.has(node.id);\n        });\n      }\n      static getOptimisticGraph(dependencyGraph, processedNavigation) {\n        return this.getFirstPaintBasedGraph(dependencyGraph, {\n          cutoffTimestamp: processedNavigation.timestamps.firstContentfulPaint,\n          // In the optimistic graph we exclude resources that appeared to be render blocking but were\n          // initiated by a script. While they typically have a very high importance and tend to have a\n          // significant impact on the page's content, these resources don't technically block rendering.\n          treatNodeAsRenderBlocking: /* @__PURE__ */ __name((node) => node.hasRenderBlockingPriority() && node.initiatorType !== \"script\", \"treatNodeAsRenderBlocking\")\n        });\n      }\n      static getPessimisticGraph(dependencyGraph, processedNavigation) {\n        return this.getFirstPaintBasedGraph(dependencyGraph, {\n          cutoffTimestamp: processedNavigation.timestamps.firstContentfulPaint,\n          treatNodeAsRenderBlocking: /* @__PURE__ */ __name((node) => node.hasRenderBlockingPriority(), \"treatNodeAsRenderBlocking\")\n        });\n      }\n    };\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/lantern/metrics/Interactive.js\nvar CRITICAL_LONG_TASK_THRESHOLD, Interactive;\nvar init_Interactive = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/lantern/metrics/Interactive.js\"() {\n    init_process_global();\n    init_core();\n    init_graph();\n    init_Metric();\n    CRITICAL_LONG_TASK_THRESHOLD = 20;\n    Interactive = class _Interactive extends Metric {\n      static {\n        __name(this, \"Interactive\");\n      }\n      static get coefficients() {\n        return {\n          intercept: 0,\n          optimistic: 0.45,\n          pessimistic: 0.55\n        };\n      }\n      static getOptimisticGraph(dependencyGraph) {\n        const minimumCpuTaskDuration = CRITICAL_LONG_TASK_THRESHOLD * 1e3;\n        return dependencyGraph.cloneWithRelationships((node) => {\n          if (node.type === BaseNode.types.CPU) {\n            return node.duration > minimumCpuTaskDuration;\n          }\n          const isImage = node.request.resourceType === \"Image\";\n          const isScript = node.request.resourceType === \"Script\";\n          return !isImage && (isScript || node.request.priority === \"High\" || node.request.priority === \"VeryHigh\");\n        });\n      }\n      static getPessimisticGraph(dependencyGraph) {\n        return dependencyGraph;\n      }\n      static getEstimateFromSimulation(simulationResult, extras) {\n        if (!extras.lcpResult) {\n          throw new LanternError(\"missing lcpResult\");\n        }\n        const lastTaskAt = _Interactive.getLastLongTaskEndTime(simulationResult.nodeTimings);\n        const minimumTime = extras.optimistic ? extras.lcpResult.optimisticEstimate.timeInMs : extras.lcpResult.pessimisticEstimate.timeInMs;\n        return {\n          timeInMs: Math.max(minimumTime, lastTaskAt),\n          nodeTimings: simulationResult.nodeTimings\n        };\n      }\n      static compute(data31, extras) {\n        const lcpResult = extras?.lcpResult;\n        if (!lcpResult) {\n          throw new LanternError(\"LCP is required to calculate the Interactive metric\");\n        }\n        const metricResult = super.compute(data31, extras);\n        metricResult.timing = Math.max(metricResult.timing, lcpResult.timing);\n        return metricResult;\n      }\n      static getLastLongTaskEndTime(nodeTimings, duration = 50) {\n        return Array.from(nodeTimings.entries()).filter(([node, timing]) => {\n          if (node.type !== BaseNode.types.CPU) {\n            return false;\n          }\n          return timing.duration > duration;\n        }).map(([_, timing]) => timing.endTime).reduce((max, x) => Math.max(max || 0, x || 0), 0);\n      }\n    };\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/lantern/metrics/LargestContentfulPaint.js\nvar LargestContentfulPaint;\nvar init_LargestContentfulPaint = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/lantern/metrics/LargestContentfulPaint.js\"() {\n    init_process_global();\n    init_core();\n    init_FirstContentfulPaint();\n    init_Metric();\n    LargestContentfulPaint = class _LargestContentfulPaint extends Metric {\n      static {\n        __name(this, \"LargestContentfulPaint\");\n      }\n      static get coefficients() {\n        return {\n          intercept: 0,\n          optimistic: 0.5,\n          pessimistic: 0.5\n        };\n      }\n      /**\n       * Low priority image nodes are usually offscreen and very unlikely to be the\n       * resource that is required for LCP. Our LCP graphs include everything except for these images.\n       */\n      static isNotLowPriorityImageNode(node) {\n        if (node.type !== \"network\") {\n          return true;\n        }\n        const isImage = node.request.resourceType === \"Image\";\n        const isLowPriority = node.request.priority === \"Low\" || node.request.priority === \"VeryLow\";\n        return !isImage || !isLowPriority;\n      }\n      static getOptimisticGraph(dependencyGraph, processedNavigation) {\n        const lcp = processedNavigation.timestamps.largestContentfulPaint;\n        if (!lcp) {\n          throw new LanternError(\"NO_LCP\");\n        }\n        return FirstContentfulPaint.getFirstPaintBasedGraph(dependencyGraph, {\n          cutoffTimestamp: lcp,\n          treatNodeAsRenderBlocking: _LargestContentfulPaint.isNotLowPriorityImageNode\n        });\n      }\n      static getPessimisticGraph(dependencyGraph, processedNavigation) {\n        const lcp = processedNavigation.timestamps.largestContentfulPaint;\n        if (!lcp) {\n          throw new LanternError(\"NO_LCP\");\n        }\n        return FirstContentfulPaint.getFirstPaintBasedGraph(dependencyGraph, {\n          cutoffTimestamp: lcp,\n          treatNodeAsRenderBlocking: /* @__PURE__ */ __name((_) => true, \"treatNodeAsRenderBlocking\"),\n          // For pessimistic LCP we'll include *all* layout nodes\n          additionalCpuNodesToTreatAsRenderBlocking: /* @__PURE__ */ __name((node) => node.didPerformLayout(), \"additionalCpuNodesToTreatAsRenderBlocking\")\n        });\n      }\n      static getEstimateFromSimulation(simulationResult) {\n        const nodeTimesNotOffscreenImages = Array.from(simulationResult.nodeTimings.entries()).filter((entry) => _LargestContentfulPaint.isNotLowPriorityImageNode(entry[0])).map((entry) => entry[1].endTime);\n        return {\n          timeInMs: Math.max(...nodeTimesNotOffscreenImages),\n          nodeTimings: simulationResult.nodeTimings\n        };\n      }\n      static compute(data31, extras) {\n        const fcpResult = extras?.fcpResult;\n        if (!fcpResult) {\n          throw new LanternError(\"FCP is required to calculate the LCP metric\");\n        }\n        const metricResult = super.compute(data31, extras);\n        metricResult.timing = Math.max(metricResult.timing, fcpResult.timing);\n        return metricResult;\n      }\n    };\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/lantern/metrics/MaxPotentialFID.js\nvar MaxPotentialFID;\nvar init_MaxPotentialFID = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/lantern/metrics/MaxPotentialFID.js\"() {\n    init_process_global();\n    init_core();\n    init_graph();\n    init_Metric();\n    MaxPotentialFID = class _MaxPotentialFID extends Metric {\n      static {\n        __name(this, \"MaxPotentialFID\");\n      }\n      static get coefficients() {\n        return {\n          intercept: 0,\n          optimistic: 0.5,\n          pessimistic: 0.5\n        };\n      }\n      static getOptimisticGraph(dependencyGraph) {\n        return dependencyGraph;\n      }\n      static getPessimisticGraph(dependencyGraph) {\n        return dependencyGraph;\n      }\n      static getEstimateFromSimulation(simulation, extras) {\n        if (!extras.fcpResult) {\n          throw new LanternError(\"missing fcpResult\");\n        }\n        const fcpTimeInMs = extras.optimistic ? extras.fcpResult.pessimisticEstimate.timeInMs : extras.fcpResult.optimisticEstimate.timeInMs;\n        const timings = _MaxPotentialFID.getTimingsAfterFCP(simulation.nodeTimings, fcpTimeInMs);\n        return {\n          timeInMs: Math.max(...timings.map((timing) => timing.duration), 16),\n          nodeTimings: simulation.nodeTimings\n        };\n      }\n      static compute(data31, extras) {\n        const fcpResult = extras?.fcpResult;\n        if (!fcpResult) {\n          throw new LanternError(\"FCP is required to calculate the Max Potential FID metric\");\n        }\n        return super.compute(data31, extras);\n      }\n      static getTimingsAfterFCP(nodeTimings, fcpTimeInMs) {\n        return Array.from(nodeTimings.entries()).filter(([node, timing]) => node.type === BaseNode.types.CPU && timing.endTime > fcpTimeInMs).map(([_, timing]) => timing);\n      }\n    };\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/lantern/metrics/SpeedIndex.js\nvar mobileSlow4GRtt, SpeedIndex;\nvar init_SpeedIndex = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/lantern/metrics/SpeedIndex.js\"() {\n    init_process_global();\n    init_core();\n    init_graph();\n    init_Metric();\n    mobileSlow4GRtt = 150;\n    SpeedIndex = class _SpeedIndex extends Metric {\n      static {\n        __name(this, \"SpeedIndex\");\n      }\n      static get coefficients() {\n        return {\n          // Note that the optimistic estimate is based on the real observed speed index rather than a\n          // real lantern graph (and the final estimate will be Math.max(FCP, Speed Index)).\n          intercept: 0,\n          optimistic: 1.4,\n          pessimistic: 0.4\n        };\n      }\n      static getScaledCoefficients(rttMs) {\n        const defaultCoefficients = this.coefficients;\n        const defaultRttExcess = mobileSlow4GRtt - 30;\n        const multiplier = Math.max((rttMs - 30) / defaultRttExcess, 0);\n        return {\n          intercept: defaultCoefficients.intercept * multiplier,\n          optimistic: 0.5 + (defaultCoefficients.optimistic - 0.5) * multiplier,\n          pessimistic: 0.5 + (defaultCoefficients.pessimistic - 0.5) * multiplier\n        };\n      }\n      static getOptimisticGraph(dependencyGraph) {\n        return dependencyGraph;\n      }\n      static getPessimisticGraph(dependencyGraph) {\n        return dependencyGraph;\n      }\n      static getEstimateFromSimulation(simulationResult, extras) {\n        if (!extras.fcpResult) {\n          throw new LanternError(\"missing fcpResult\");\n        }\n        if (extras.observedSpeedIndex === void 0) {\n          throw new LanternError(\"missing observedSpeedIndex\");\n        }\n        const fcpTimeInMs = extras.fcpResult.pessimisticEstimate.timeInMs;\n        const estimate = extras.optimistic ? extras.observedSpeedIndex : _SpeedIndex.computeLayoutBasedSpeedIndex(simulationResult.nodeTimings, fcpTimeInMs);\n        return {\n          timeInMs: estimate,\n          nodeTimings: simulationResult.nodeTimings\n        };\n      }\n      static compute(data31, extras) {\n        const fcpResult = extras?.fcpResult;\n        if (!fcpResult) {\n          throw new LanternError(\"FCP is required to calculate the SpeedIndex metric\");\n        }\n        const metricResult = super.compute(data31, extras);\n        metricResult.timing = Math.max(metricResult.timing, fcpResult.timing);\n        return metricResult;\n      }\n      /**\n       * Approximate speed index using layout events from the simulated node timings.\n       * The layout-based speed index is the weighted average of the endTime of CPU nodes that contained\n       * a 'Layout' task. log(duration) is used as the weight to stand for \"significance\" to the page.\n       *\n       * If no layout events can be found or the endTime of a CPU task is too early, FCP is used instead.\n       *\n       * This approach was determined after evaluating the accuracy/complexity tradeoff of many\n       * different methods. Read more in the evaluation doc.\n       *\n       * @see https://docs.google.com/document/d/1qJWXwxoyVLVadezIp_Tgdk867G3tDNkkVRvUJSH3K1E/edit#\n       */\n      static computeLayoutBasedSpeedIndex(nodeTimings, fcpTimeInMs) {\n        const layoutWeights = [];\n        for (const [node, timing] of nodeTimings.entries()) {\n          if (node.type !== BaseNode.types.CPU) {\n            continue;\n          }\n          if (node.childEvents.some((x) => x.name === \"Layout\")) {\n            const timingWeight = Math.max(Math.log2(timing.endTime - timing.startTime), 0);\n            layoutWeights.push({ time: timing.endTime, weight: timingWeight });\n          }\n        }\n        const totalWeightedTime = layoutWeights.map((evt) => evt.weight * Math.max(evt.time, fcpTimeInMs)).reduce((a, b) => a + b, 0);\n        const totalWeight = layoutWeights.map((evt) => evt.weight).reduce((a, b) => a + b, 0);\n        if (!totalWeight) {\n          return fcpTimeInMs;\n        }\n        return totalWeightedTime / totalWeight;\n      }\n    };\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/lantern/metrics/TBTUtils.js\nvar TBTUtils_exports = {};\n__export(TBTUtils_exports, {\n  BLOCKING_TIME_THRESHOLD: () => BLOCKING_TIME_THRESHOLD,\n  calculateSumOfBlockingTime: () => calculateSumOfBlockingTime,\n  calculateTbtImpactForEvent: () => calculateTbtImpactForEvent\n});\nfunction calculateTbtImpactForEvent(event, startTimeMs, endTimeMs, topLevelEvent) {\n  let threshold = BLOCKING_TIME_THRESHOLD;\n  if (topLevelEvent) {\n    threshold *= event.duration / topLevelEvent.duration;\n  }\n  if (event.duration < threshold) {\n    return 0;\n  }\n  if (event.end < startTimeMs) {\n    return 0;\n  }\n  if (event.start > endTimeMs) {\n    return 0;\n  }\n  const clippedStart = Math.max(event.start, startTimeMs);\n  const clippedEnd = Math.min(event.end, endTimeMs);\n  const clippedDuration = clippedEnd - clippedStart;\n  if (clippedDuration < threshold) {\n    return 0;\n  }\n  return clippedDuration - threshold;\n}\nfunction calculateSumOfBlockingTime(topLevelEvents, startTimeMs, endTimeMs) {\n  if (endTimeMs <= startTimeMs) {\n    return 0;\n  }\n  let sumBlockingTime = 0;\n  for (const event of topLevelEvents) {\n    sumBlockingTime += calculateTbtImpactForEvent(event, startTimeMs, endTimeMs);\n  }\n  return sumBlockingTime;\n}\nvar BLOCKING_TIME_THRESHOLD;\nvar init_TBTUtils = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/lantern/metrics/TBTUtils.js\"() {\n    init_process_global();\n    BLOCKING_TIME_THRESHOLD = 50;\n    __name(calculateTbtImpactForEvent, \"calculateTbtImpactForEvent\");\n    __name(calculateSumOfBlockingTime, \"calculateSumOfBlockingTime\");\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/lantern/metrics/TotalBlockingTime.js\nvar TotalBlockingTime;\nvar init_TotalBlockingTime = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/lantern/metrics/TotalBlockingTime.js\"() {\n    init_process_global();\n    init_core();\n    init_graph();\n    init_Metric();\n    init_TBTUtils();\n    TotalBlockingTime = class _TotalBlockingTime extends Metric {\n      static {\n        __name(this, \"TotalBlockingTime\");\n      }\n      static get coefficients() {\n        return {\n          intercept: 0,\n          optimistic: 0.5,\n          pessimistic: 0.5\n        };\n      }\n      static getOptimisticGraph(dependencyGraph) {\n        return dependencyGraph;\n      }\n      static getPessimisticGraph(dependencyGraph) {\n        return dependencyGraph;\n      }\n      static getEstimateFromSimulation(simulation, extras) {\n        if (!extras.fcpResult) {\n          throw new LanternError(\"missing fcpResult\");\n        }\n        if (!extras.interactiveResult) {\n          throw new LanternError(\"missing interactiveResult\");\n        }\n        const fcpTimeInMs = extras.optimistic ? extras.fcpResult.pessimisticEstimate.timeInMs : extras.fcpResult.optimisticEstimate.timeInMs;\n        const interactiveTimeMs = extras.optimistic ? extras.interactiveResult.optimisticEstimate.timeInMs : extras.interactiveResult.pessimisticEstimate.timeInMs;\n        const minDurationMs = BLOCKING_TIME_THRESHOLD;\n        const events = _TotalBlockingTime.getTopLevelEvents(simulation.nodeTimings, minDurationMs);\n        return {\n          timeInMs: calculateSumOfBlockingTime(events, fcpTimeInMs, interactiveTimeMs),\n          nodeTimings: simulation.nodeTimings\n        };\n      }\n      static compute(data31, extras) {\n        const fcpResult = extras?.fcpResult;\n        if (!fcpResult) {\n          throw new LanternError(\"FCP is required to calculate the TBT metric\");\n        }\n        const interactiveResult = extras?.fcpResult;\n        if (!interactiveResult) {\n          throw new LanternError(\"Interactive is required to calculate the TBT metric\");\n        }\n        return super.compute(data31, extras);\n      }\n      static getTopLevelEvents(nodeTimings, minDurationMs) {\n        const events = [];\n        for (const [node, timing] of nodeTimings.entries()) {\n          if (node.type !== BaseNode.types.CPU) {\n            continue;\n          }\n          if (timing.duration < minDurationMs) {\n            continue;\n          }\n          events.push({\n            start: timing.startTime,\n            end: timing.endTime,\n            duration: timing.duration\n          });\n        }\n        return events;\n      }\n    };\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/lantern/metrics/metrics.js\nvar metrics_exports = {};\n__export(metrics_exports, {\n  FirstContentfulPaint: () => FirstContentfulPaint,\n  Interactive: () => Interactive,\n  LargestContentfulPaint: () => LargestContentfulPaint,\n  MaxPotentialFID: () => MaxPotentialFID,\n  Metric: () => Metric,\n  SpeedIndex: () => SpeedIndex,\n  TBTUtils: () => TBTUtils_exports,\n  TotalBlockingTime: () => TotalBlockingTime\n});\nvar init_metrics = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/lantern/metrics/metrics.js\"() {\n    init_process_global();\n    init_FirstContentfulPaint();\n    init_Interactive();\n    init_LargestContentfulPaint();\n    init_MaxPotentialFID();\n    init_Metric();\n    init_SpeedIndex();\n    init_TotalBlockingTime();\n    init_TBTUtils();\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/lantern/simulation/TCPConnection.js\nvar INITIAL_CONGESTION_WINDOW, TCP_SEGMENT_SIZE, TCPConnection;\nvar init_TCPConnection = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/lantern/simulation/TCPConnection.js\"() {\n    init_process_global();\n    INITIAL_CONGESTION_WINDOW = 10;\n    TCP_SEGMENT_SIZE = 1460;\n    TCPConnection = class _TCPConnection {\n      static {\n        __name(this, \"TCPConnection\");\n      }\n      warmed;\n      ssl;\n      h2;\n      rtt;\n      throughput;\n      serverLatency;\n      _congestionWindow;\n      h2OverflowBytesDownloaded;\n      constructor(rtt, throughput, serverLatency = 0, ssl = true, h2 = false) {\n        this.warmed = false;\n        this.ssl = ssl;\n        this.h2 = h2;\n        this.rtt = rtt;\n        this.throughput = throughput;\n        this.serverLatency = serverLatency;\n        this._congestionWindow = INITIAL_CONGESTION_WINDOW;\n        this.h2OverflowBytesDownloaded = 0;\n      }\n      static maximumSaturatedConnections(rtt, availableThroughput) {\n        const roundTripsPerSecond = 1e3 / rtt;\n        const bytesPerRoundTrip = TCP_SEGMENT_SIZE;\n        const bytesPerSecond = roundTripsPerSecond * bytesPerRoundTrip;\n        const minimumThroughputRequiredPerRequest = bytesPerSecond * 8;\n        return Math.floor(availableThroughput / minimumThroughputRequiredPerRequest);\n      }\n      computeMaximumCongestionWindowInSegments() {\n        const bytesPerSecond = this.throughput / 8;\n        const secondsPerRoundTrip = this.rtt / 1e3;\n        const bytesPerRoundTrip = bytesPerSecond * secondsPerRoundTrip;\n        return Math.floor(bytesPerRoundTrip / TCP_SEGMENT_SIZE);\n      }\n      setThroughput(throughput) {\n        this.throughput = throughput;\n      }\n      setCongestionWindow(congestion) {\n        this._congestionWindow = congestion;\n      }\n      setWarmed(warmed) {\n        this.warmed = warmed;\n      }\n      isH2() {\n        return this.h2;\n      }\n      get congestionWindow() {\n        return this._congestionWindow;\n      }\n      /**\n       * Sets the number of excess bytes that are available to this connection on future downloads, only\n       * applies to H2 connections.\n       */\n      setH2OverflowBytesDownloaded(bytes) {\n        if (!this.h2) {\n          return;\n        }\n        this.h2OverflowBytesDownloaded = bytes;\n      }\n      clone() {\n        return Object.assign(new _TCPConnection(this.rtt, this.throughput), this);\n      }\n      /**\n       * Simulates a network download of a particular number of bytes over an optional maximum amount of time\n       * and returns information about the ending state.\n       *\n       * See https://hpbn.co/building-blocks-of-tcp/#three-way-handshake and\n       *  https://hpbn.co/transport-layer-security-tls/#tls-handshake for details.\n       */\n      simulateDownloadUntil(bytesToDownload, options) {\n        const { timeAlreadyElapsed = 0, maximumTimeToElapse = Infinity, dnsResolutionTime = 0 } = options || {};\n        if (this.warmed && this.h2) {\n          bytesToDownload -= this.h2OverflowBytesDownloaded;\n        }\n        const twoWayLatency = this.rtt;\n        const oneWayLatency = twoWayLatency / 2;\n        const maximumCongestionWindow = this.computeMaximumCongestionWindowInSegments();\n        let handshakeAndRequest = oneWayLatency;\n        if (!this.warmed) {\n          handshakeAndRequest = // DNS lookup\n          dnsResolutionTime + // SYN\n          oneWayLatency + // SYN ACK\n          oneWayLatency + // ACK + initial request\n          oneWayLatency + // ClientHello/ServerHello assuming TLS False Start is enabled (https://istlsfastyet.com/#server-performance).\n          (this.ssl ? twoWayLatency : 0);\n        }\n        let roundTrips = Math.ceil(handshakeAndRequest / twoWayLatency);\n        let timeToFirstByte = handshakeAndRequest + this.serverLatency + oneWayLatency;\n        if (this.warmed && this.h2) {\n          timeToFirstByte = 0;\n        }\n        const timeElapsedForTTFB = Math.max(timeToFirstByte - timeAlreadyElapsed, 0);\n        const maximumDownloadTimeToElapse = maximumTimeToElapse - timeElapsedForTTFB;\n        let congestionWindow = Math.min(this._congestionWindow, maximumCongestionWindow);\n        let totalBytesDownloaded = 0;\n        if (timeElapsedForTTFB > 0) {\n          totalBytesDownloaded = congestionWindow * TCP_SEGMENT_SIZE;\n        } else {\n          roundTrips = 0;\n        }\n        let downloadTimeElapsed = 0;\n        let bytesRemaining = bytesToDownload - totalBytesDownloaded;\n        while (bytesRemaining > 0 && downloadTimeElapsed <= maximumDownloadTimeToElapse) {\n          roundTrips++;\n          downloadTimeElapsed += twoWayLatency;\n          congestionWindow = Math.max(Math.min(maximumCongestionWindow, congestionWindow * 2), 1);\n          const bytesDownloadedInWindow = congestionWindow * TCP_SEGMENT_SIZE;\n          totalBytesDownloaded += bytesDownloadedInWindow;\n          bytesRemaining -= bytesDownloadedInWindow;\n        }\n        const timeElapsed = timeElapsedForTTFB + downloadTimeElapsed;\n        const extraBytesDownloaded = this.h2 ? Math.max(totalBytesDownloaded - bytesToDownload, 0) : 0;\n        const bytesDownloaded = Math.max(Math.min(totalBytesDownloaded, bytesToDownload), 0);\n        let connectionTiming;\n        if (!this.warmed) {\n          connectionTiming = {\n            dnsResolutionTime,\n            connectionTime: handshakeAndRequest - dnsResolutionTime,\n            sslTime: this.ssl ? twoWayLatency : void 0,\n            timeToFirstByte\n          };\n        } else if (this.h2) {\n          connectionTiming = {\n            timeToFirstByte\n          };\n        } else {\n          connectionTiming = {\n            connectionTime: handshakeAndRequest,\n            timeToFirstByte\n          };\n        }\n        return {\n          roundTrips,\n          timeElapsed,\n          bytesDownloaded,\n          extraBytesDownloaded,\n          congestionWindow,\n          connectionTiming\n        };\n      }\n    };\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/lantern/simulation/ConnectionPool.js\nvar DEFAULT_SERVER_RESPONSE_TIME, TLS_SCHEMES, CONNECTIONS_PER_ORIGIN, ConnectionPool;\nvar init_ConnectionPool = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/lantern/simulation/ConnectionPool.js\"() {\n    init_process_global();\n    init_core();\n    init_TCPConnection();\n    DEFAULT_SERVER_RESPONSE_TIME = 30;\n    TLS_SCHEMES = [\"https\", \"wss\"];\n    CONNECTIONS_PER_ORIGIN = 6;\n    ConnectionPool = class {\n      static {\n        __name(this, \"ConnectionPool\");\n      }\n      options;\n      records;\n      connectionsByOrigin;\n      connectionsByRequest;\n      _connectionsInUse;\n      connectionReusedByRequestId;\n      constructor(records, options) {\n        this.options = options;\n        this.records = records;\n        this.connectionsByOrigin = /* @__PURE__ */ new Map();\n        this.connectionsByRequest = /* @__PURE__ */ new Map();\n        this._connectionsInUse = /* @__PURE__ */ new Set();\n        this.connectionReusedByRequestId = NetworkAnalyzer.estimateIfConnectionWasReused(records, {\n          forceCoarseEstimates: true\n        });\n        this.initializeConnections();\n      }\n      connectionsInUse() {\n        return Array.from(this._connectionsInUse);\n      }\n      initializeConnections() {\n        const connectionReused = this.connectionReusedByRequestId;\n        const additionalRttByOrigin = this.options.additionalRttByOrigin;\n        const serverResponseTimeByOrigin = this.options.serverResponseTimeByOrigin;\n        const recordsByOrigin = NetworkAnalyzer.groupByOrigin(this.records);\n        for (const [origin, requests] of recordsByOrigin.entries()) {\n          const connections = [];\n          const additionalRtt = additionalRttByOrigin.get(origin) || 0;\n          const responseTime = serverResponseTimeByOrigin.get(origin) || DEFAULT_SERVER_RESPONSE_TIME;\n          for (const request of requests) {\n            if (connectionReused.get(request.requestId)) {\n              continue;\n            }\n            const isTLS = TLS_SCHEMES.includes(request.parsedURL.scheme);\n            const isH2 = request.protocol === \"h2\";\n            const connection = new TCPConnection(this.options.rtt + additionalRtt, this.options.throughput, responseTime, isTLS, isH2);\n            connections.push(connection);\n          }\n          if (!connections.length) {\n            throw new LanternError(`Could not find a connection for origin: ${origin}`);\n          }\n          const minConnections = connections[0].isH2() ? 1 : CONNECTIONS_PER_ORIGIN;\n          while (connections.length < minConnections) {\n            connections.push(connections[0].clone());\n          }\n          this.connectionsByOrigin.set(origin, connections);\n        }\n      }\n      findAvailableConnectionWithLargestCongestionWindow(connections) {\n        let maxConnection = null;\n        for (let i = 0; i < connections.length; i++) {\n          const connection = connections[i];\n          if (this._connectionsInUse.has(connection)) {\n            continue;\n          }\n          const currentMax = maxConnection?.congestionWindow || -Infinity;\n          if (connection.congestionWindow > currentMax) {\n            maxConnection = connection;\n          }\n        }\n        return maxConnection;\n      }\n      /**\n       * This method finds an available connection to the origin specified by the network request or null\n       * if no connection was available. If returned, connection will not be available for other network\n       * records until release is called.\n       */\n      acquire(request) {\n        if (this.connectionsByRequest.has(request)) {\n          throw new LanternError(\"Record already has a connection\");\n        }\n        const origin = request.parsedURL.securityOrigin;\n        const connections = this.connectionsByOrigin.get(origin) || [];\n        const connectionToUse = this.findAvailableConnectionWithLargestCongestionWindow(connections);\n        if (!connectionToUse) {\n          return null;\n        }\n        this._connectionsInUse.add(connectionToUse);\n        this.connectionsByRequest.set(request, connectionToUse);\n        return connectionToUse;\n      }\n      /**\n       * Return the connection currently being used to fetch a request. If no connection\n       * currently being used for this request, an error will be thrown.\n       */\n      acquireActiveConnectionFromRequest(request) {\n        const activeConnection = this.connectionsByRequest.get(request);\n        if (!activeConnection) {\n          throw new LanternError(\"Could not find an active connection for request\");\n        }\n        return activeConnection;\n      }\n      release(request) {\n        const connection = this.connectionsByRequest.get(request);\n        this.connectionsByRequest.delete(request);\n        if (connection) {\n          this._connectionsInUse.delete(connection);\n        }\n      }\n    };\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/lantern/simulation/Constants.js\nvar DEVTOOLS_RTT_ADJUSTMENT_FACTOR, DEVTOOLS_THROUGHPUT_ADJUSTMENT_FACTOR, throttling, Constants;\nvar init_Constants = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/lantern/simulation/Constants.js\"() {\n    init_process_global();\n    DEVTOOLS_RTT_ADJUSTMENT_FACTOR = 3.75;\n    DEVTOOLS_THROUGHPUT_ADJUSTMENT_FACTOR = 0.9;\n    throttling = {\n      DEVTOOLS_RTT_ADJUSTMENT_FACTOR,\n      DEVTOOLS_THROUGHPUT_ADJUSTMENT_FACTOR,\n      // These values align with WebPageTest's definition of \"Fast 3G\"\n      // But offer similar characteristics to roughly the 75th percentile of 4G connections.\n      mobileSlow4G: {\n        rttMs: 150,\n        throughputKbps: 1.6 * 1024,\n        requestLatencyMs: 150 * DEVTOOLS_RTT_ADJUSTMENT_FACTOR,\n        downloadThroughputKbps: 1.6 * 1024 * DEVTOOLS_THROUGHPUT_ADJUSTMENT_FACTOR,\n        uploadThroughputKbps: 750 * DEVTOOLS_THROUGHPUT_ADJUSTMENT_FACTOR,\n        cpuSlowdownMultiplier: 4\n      },\n      // These values partially align with WebPageTest's definition of \"Regular 3G\".\n      // These values are meant to roughly align with Chrome UX report's 3G definition which are based\n      // on HTTP RTT of 300-1400ms and downlink throughput of <700kbps.\n      mobileRegular3G: {\n        rttMs: 300,\n        throughputKbps: 700,\n        requestLatencyMs: 300 * DEVTOOLS_RTT_ADJUSTMENT_FACTOR,\n        downloadThroughputKbps: 700 * DEVTOOLS_THROUGHPUT_ADJUSTMENT_FACTOR,\n        uploadThroughputKbps: 700 * DEVTOOLS_THROUGHPUT_ADJUSTMENT_FACTOR,\n        cpuSlowdownMultiplier: 4\n      },\n      // Using a \"broadband\" connection type\n      // Corresponds to \"Dense 4G 25th percentile\" in https://docs.google.com/document/d/1Ft1Bnq9-t4jK5egLSOc28IL4TvR-Tt0se_1faTA4KTY/edit#heading=h.bb7nfy2x9e5v\n      desktopDense4G: {\n        rttMs: 40,\n        throughputKbps: 10 * 1024,\n        cpuSlowdownMultiplier: 1,\n        requestLatencyMs: 0,\n        // 0 means unset\n        downloadThroughputKbps: 0,\n        uploadThroughputKbps: 0\n      }\n    };\n    Constants = { throttling };\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/lantern/simulation/DNSCache.js\nvar DNS_RESOLUTION_RTT_MULTIPLIER, DNSCache;\nvar init_DNSCache = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/lantern/simulation/DNSCache.js\"() {\n    init_process_global();\n    DNS_RESOLUTION_RTT_MULTIPLIER = 2;\n    DNSCache = class _DNSCache {\n      static {\n        __name(this, \"DNSCache\");\n      }\n      static rttMultiplier = DNS_RESOLUTION_RTT_MULTIPLIER;\n      rtt;\n      resolvedDomainNames;\n      constructor({ rtt }) {\n        this.rtt = rtt;\n        this.resolvedDomainNames = /* @__PURE__ */ new Map();\n      }\n      getTimeUntilResolution(request, options) {\n        const { requestedAt = 0, shouldUpdateCache = false } = options || {};\n        const domain = request.parsedURL.host;\n        const cacheEntry = this.resolvedDomainNames.get(domain);\n        let timeUntilResolved = this.rtt * _DNSCache.rttMultiplier;\n        if (cacheEntry) {\n          const timeUntilCachedIsResolved = Math.max(cacheEntry.resolvedAt - requestedAt, 0);\n          timeUntilResolved = Math.min(timeUntilCachedIsResolved, timeUntilResolved);\n        }\n        const resolvedAt = requestedAt + timeUntilResolved;\n        if (shouldUpdateCache) {\n          this.updateCacheResolvedAtIfNeeded(request, resolvedAt);\n        }\n        return timeUntilResolved;\n      }\n      updateCacheResolvedAtIfNeeded(request, resolvedAt) {\n        const domain = request.parsedURL.host;\n        const cacheEntry = this.resolvedDomainNames.get(domain) || { resolvedAt };\n        cacheEntry.resolvedAt = Math.min(cacheEntry.resolvedAt, resolvedAt);\n        this.resolvedDomainNames.set(domain, cacheEntry);\n      }\n      /**\n       * Forcefully sets the DNS resolution time for a request.\n       * Useful for testing and alternate execution simulations.\n       */\n      setResolvedAt(domain, resolvedAt) {\n        this.resolvedDomainNames.set(domain, { resolvedAt });\n      }\n    };\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/lantern/simulation/SimulationTimingMap.js\nvar SimulatorTimingMap;\nvar init_SimulationTimingMap = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/lantern/simulation/SimulationTimingMap.js\"() {\n    init_process_global();\n    init_core();\n    init_graph();\n    SimulatorTimingMap = class {\n      static {\n        __name(this, \"SimulatorTimingMap\");\n      }\n      nodeTimings;\n      constructor() {\n        this.nodeTimings = /* @__PURE__ */ new Map();\n      }\n      getNodes() {\n        return Array.from(this.nodeTimings.keys());\n      }\n      setReadyToStart(node, values) {\n        this.nodeTimings.set(node, values);\n      }\n      setInProgress(node, values) {\n        const nodeTiming = {\n          ...this.getQueued(node),\n          startTime: values.startTime,\n          timeElapsed: 0\n        };\n        this.nodeTimings.set(node, node.type === BaseNode.types.NETWORK ? { ...nodeTiming, timeElapsedOvershoot: 0, bytesDownloaded: 0 } : nodeTiming);\n      }\n      setCompleted(node, values) {\n        const nodeTiming = {\n          ...this.getInProgress(node),\n          endTime: values.endTime,\n          connectionTiming: values.connectionTiming\n        };\n        this.nodeTimings.set(node, nodeTiming);\n      }\n      setCpu(node, values) {\n        const nodeTiming = {\n          ...this.getCpuStarted(node),\n          timeElapsed: values.timeElapsed\n        };\n        this.nodeTimings.set(node, nodeTiming);\n      }\n      setCpuEstimated(node, values) {\n        const nodeTiming = {\n          ...this.getCpuStarted(node),\n          estimatedTimeElapsed: values.estimatedTimeElapsed\n        };\n        this.nodeTimings.set(node, nodeTiming);\n      }\n      setNetwork(node, values) {\n        const nodeTiming = {\n          ...this.getNetworkStarted(node),\n          timeElapsed: values.timeElapsed,\n          timeElapsedOvershoot: values.timeElapsedOvershoot,\n          bytesDownloaded: values.bytesDownloaded\n        };\n        this.nodeTimings.set(node, nodeTiming);\n      }\n      setNetworkEstimated(node, values) {\n        const nodeTiming = {\n          ...this.getNetworkStarted(node),\n          estimatedTimeElapsed: values.estimatedTimeElapsed\n        };\n        this.nodeTimings.set(node, nodeTiming);\n      }\n      getQueued(node) {\n        const timing = this.nodeTimings.get(node);\n        if (!timing) {\n          throw new LanternError(`Node ${node.id} not yet queued`);\n        }\n        return timing;\n      }\n      getCpuStarted(node) {\n        const timing = this.nodeTimings.get(node);\n        if (!timing) {\n          throw new LanternError(`Node ${node.id} not yet queued`);\n        }\n        if (!(\"startTime\" in timing)) {\n          throw new LanternError(`Node ${node.id} not yet started`);\n        }\n        if (\"bytesDownloaded\" in timing) {\n          throw new LanternError(`Node ${node.id} timing not valid`);\n        }\n        return timing;\n      }\n      getNetworkStarted(node) {\n        const timing = this.nodeTimings.get(node);\n        if (!timing) {\n          throw new LanternError(`Node ${node.id} not yet queued`);\n        }\n        if (!(\"startTime\" in timing)) {\n          throw new LanternError(`Node ${node.id} not yet started`);\n        }\n        if (!(\"bytesDownloaded\" in timing)) {\n          throw new LanternError(`Node ${node.id} timing not valid`);\n        }\n        return timing;\n      }\n      getInProgress(node) {\n        const timing = this.nodeTimings.get(node);\n        if (!timing) {\n          throw new LanternError(`Node ${node.id} not yet queued`);\n        }\n        if (!(\"startTime\" in timing)) {\n          throw new LanternError(`Node ${node.id} not yet started`);\n        }\n        if (!(\"estimatedTimeElapsed\" in timing)) {\n          throw new LanternError(`Node ${node.id} not yet in progress`);\n        }\n        return timing;\n      }\n      getCompleted(node) {\n        const timing = this.nodeTimings.get(node);\n        if (!timing) {\n          throw new LanternError(`Node ${node.id} not yet queued`);\n        }\n        if (!(\"startTime\" in timing)) {\n          throw new LanternError(`Node ${node.id} not yet started`);\n        }\n        if (!(\"estimatedTimeElapsed\" in timing)) {\n          throw new LanternError(`Node ${node.id} not yet in progress`);\n        }\n        if (!(\"endTime\" in timing)) {\n          throw new LanternError(`Node ${node.id} not yet completed`);\n        }\n        return timing;\n      }\n    };\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/lantern/simulation/Simulator.js\nvar defaultThrottling, DEFAULT_MAXIMUM_CONCURRENT_REQUESTS, DEFAULT_LAYOUT_TASK_MULTIPLIER, DEFAULT_MAXIMUM_CPU_TASK_DURATION, NodeState, PriorityStartTimePenalty, ALL_SIMULATION_NODE_TIMINGS, Simulator;\nvar init_Simulator = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/lantern/simulation/Simulator.js\"() {\n    init_process_global();\n    init_core();\n    init_graph();\n    init_ConnectionPool();\n    init_Constants();\n    init_DNSCache();\n    init_SimulationTimingMap();\n    init_TCPConnection();\n    defaultThrottling = Constants.throttling.mobileSlow4G;\n    DEFAULT_MAXIMUM_CONCURRENT_REQUESTS = 10;\n    DEFAULT_LAYOUT_TASK_MULTIPLIER = 0.5;\n    DEFAULT_MAXIMUM_CPU_TASK_DURATION = 1e4;\n    NodeState = {\n      NotReadyToStart: 0,\n      ReadyToStart: 1,\n      InProgress: 2,\n      Complete: 3\n    };\n    PriorityStartTimePenalty = {\n      VeryHigh: 0,\n      High: 0.25,\n      Medium: 0.5,\n      Low: 1,\n      VeryLow: 2\n    };\n    ALL_SIMULATION_NODE_TIMINGS = /* @__PURE__ */ new Map();\n    Simulator = class _Simulator {\n      static {\n        __name(this, \"Simulator\");\n      }\n      static createSimulator(settings) {\n        const { throttlingMethod, throttling: throttling3, precomputedLanternData, networkAnalysis } = settings;\n        const options = {\n          additionalRttByOrigin: networkAnalysis.additionalRttByOrigin,\n          serverResponseTimeByOrigin: networkAnalysis.serverResponseTimeByOrigin,\n          observedThroughput: networkAnalysis.throughput\n        };\n        if (precomputedLanternData) {\n          options.additionalRttByOrigin = new Map(Object.entries(precomputedLanternData.additionalRttByOrigin));\n          options.serverResponseTimeByOrigin = new Map(Object.entries(precomputedLanternData.serverResponseTimeByOrigin));\n        }\n        switch (throttlingMethod) {\n          case \"provided\":\n            options.rtt = networkAnalysis.rtt;\n            options.throughput = networkAnalysis.throughput;\n            options.cpuSlowdownMultiplier = 1;\n            options.layoutTaskMultiplier = 1;\n            break;\n          case \"devtools\":\n            if (throttling3) {\n              options.rtt = throttling3.requestLatencyMs / Constants.throttling.DEVTOOLS_RTT_ADJUSTMENT_FACTOR;\n              options.throughput = throttling3.downloadThroughputKbps * 1024 / Constants.throttling.DEVTOOLS_THROUGHPUT_ADJUSTMENT_FACTOR;\n            }\n            options.cpuSlowdownMultiplier = 1;\n            options.layoutTaskMultiplier = 1;\n            break;\n          case \"simulate\":\n            if (throttling3) {\n              options.rtt = throttling3.rttMs;\n              options.throughput = throttling3.throughputKbps * 1024;\n              options.cpuSlowdownMultiplier = throttling3.cpuSlowdownMultiplier;\n            }\n            break;\n          default:\n            break;\n        }\n        return new _Simulator(options);\n      }\n      options;\n      _rtt;\n      throughput;\n      maximumConcurrentRequests;\n      cpuSlowdownMultiplier;\n      layoutTaskMultiplier;\n      cachedNodeListByStartPosition;\n      nodeTimings;\n      numberInProgressByType;\n      nodes;\n      dns;\n      connectionPool;\n      constructor(options) {\n        this.options = Object.assign({\n          rtt: defaultThrottling.rttMs,\n          throughput: defaultThrottling.throughputKbps * 1024,\n          maximumConcurrentRequests: DEFAULT_MAXIMUM_CONCURRENT_REQUESTS,\n          cpuSlowdownMultiplier: defaultThrottling.cpuSlowdownMultiplier,\n          layoutTaskMultiplier: DEFAULT_LAYOUT_TASK_MULTIPLIER,\n          additionalRttByOrigin: /* @__PURE__ */ new Map(),\n          serverResponseTimeByOrigin: /* @__PURE__ */ new Map()\n        }, options);\n        this._rtt = this.options.rtt;\n        this.throughput = this.options.throughput;\n        this.maximumConcurrentRequests = Math.max(Math.min(TCPConnection.maximumSaturatedConnections(this._rtt, this.throughput), this.options.maximumConcurrentRequests), 1);\n        this.cpuSlowdownMultiplier = this.options.cpuSlowdownMultiplier;\n        this.layoutTaskMultiplier = this.cpuSlowdownMultiplier * this.options.layoutTaskMultiplier;\n        this.cachedNodeListByStartPosition = [];\n        this.nodeTimings = new SimulatorTimingMap();\n        this.numberInProgressByType = /* @__PURE__ */ new Map();\n        this.nodes = {};\n        this.dns = new DNSCache({ rtt: this._rtt });\n        this.connectionPool = null;\n        if (!Number.isFinite(this._rtt)) {\n          throw new LanternError(`Invalid rtt ${this._rtt}`);\n        }\n        if (!Number.isFinite(this.throughput)) {\n          throw new LanternError(`Invalid throughput ${this.throughput}`);\n        }\n      }\n      get rtt() {\n        return this._rtt;\n      }\n      initializeConnectionPool(graph2) {\n        const records = [];\n        graph2.getRootNode().traverse((node) => {\n          if (node.type === BaseNode.types.NETWORK) {\n            records.push(node.request);\n          }\n        });\n        this.connectionPool = new ConnectionPool(records, this.options);\n      }\n      /**\n       * Initializes the various state data structures such _nodeTimings and the _node Sets by state.\n       */\n      initializeAuxiliaryData() {\n        this.nodeTimings = new SimulatorTimingMap();\n        this.numberInProgressByType = /* @__PURE__ */ new Map();\n        this.nodes = {};\n        this.cachedNodeListByStartPosition = [];\n        for (const state of Object.values(NodeState)) {\n          this.nodes[state] = /* @__PURE__ */ new Set();\n        }\n      }\n      numberInProgress(type) {\n        return this.numberInProgressByType.get(type) || 0;\n      }\n      markNodeAsReadyToStart(node, queuedTime) {\n        const nodeStartPosition = _Simulator.computeNodeStartPosition(node);\n        const firstNodeIndexWithGreaterStartPosition = this.cachedNodeListByStartPosition.findIndex((candidate) => _Simulator.computeNodeStartPosition(candidate) > nodeStartPosition);\n        const insertionIndex = firstNodeIndexWithGreaterStartPosition === -1 ? this.cachedNodeListByStartPosition.length : firstNodeIndexWithGreaterStartPosition;\n        this.cachedNodeListByStartPosition.splice(insertionIndex, 0, node);\n        this.nodes[NodeState.ReadyToStart].add(node);\n        this.nodes[NodeState.NotReadyToStart].delete(node);\n        this.nodeTimings.setReadyToStart(node, { queuedTime });\n      }\n      markNodeAsInProgress(node, startTime) {\n        const indexOfNodeToStart = this.cachedNodeListByStartPosition.indexOf(node);\n        this.cachedNodeListByStartPosition.splice(indexOfNodeToStart, 1);\n        this.nodes[NodeState.InProgress].add(node);\n        this.nodes[NodeState.ReadyToStart].delete(node);\n        this.numberInProgressByType.set(node.type, this.numberInProgress(node.type) + 1);\n        this.nodeTimings.setInProgress(node, { startTime });\n      }\n      markNodeAsComplete(node, endTime, connectionTiming) {\n        this.nodes[NodeState.Complete].add(node);\n        this.nodes[NodeState.InProgress].delete(node);\n        this.numberInProgressByType.set(node.type, this.numberInProgress(node.type) - 1);\n        this.nodeTimings.setCompleted(node, { endTime, connectionTiming });\n        for (const dependent of node.getDependents()) {\n          const dependencies = dependent.getDependencies();\n          if (dependencies.some((dep) => !this.nodes[NodeState.Complete].has(dep))) {\n            continue;\n          }\n          this.markNodeAsReadyToStart(dependent, endTime);\n        }\n      }\n      acquireConnection(request) {\n        return this.connectionPool.acquire(request);\n      }\n      getNodesSortedByStartPosition() {\n        return Array.from(this.cachedNodeListByStartPosition);\n      }\n      startNodeIfPossible(node, totalElapsedTime) {\n        if (node.type === BaseNode.types.CPU) {\n          if (this.numberInProgress(node.type) === 0) {\n            this.markNodeAsInProgress(node, totalElapsedTime);\n          }\n          return;\n        }\n        if (node.type !== BaseNode.types.NETWORK) {\n          throw new LanternError(\"Unsupported\");\n        }\n        if (!node.isConnectionless) {\n          const numberOfActiveRequests = this.numberInProgress(node.type);\n          if (numberOfActiveRequests >= this.maximumConcurrentRequests) {\n            return;\n          }\n          const connection = this.acquireConnection(node.request);\n          if (!connection) {\n            return;\n          }\n        }\n        this.markNodeAsInProgress(node, totalElapsedTime);\n      }\n      /**\n       * Updates each connection in use with the available throughput based on the number of network requests\n       * currently in flight.\n       */\n      updateNetworkCapacity() {\n        const inFlight = this.numberInProgress(BaseNode.types.NETWORK);\n        if (inFlight === 0) {\n          return;\n        }\n        for (const connection of this.connectionPool.connectionsInUse()) {\n          connection.setThroughput(this.throughput / inFlight);\n        }\n      }\n      /**\n       * Estimates the number of milliseconds remaining given current conditions before the node is complete.\n       */\n      estimateTimeRemaining(node) {\n        if (node.type === BaseNode.types.CPU) {\n          return this.estimateCPUTimeRemaining(node);\n        }\n        if (node.type === BaseNode.types.NETWORK) {\n          return this.estimateNetworkTimeRemaining(node);\n        }\n        throw new LanternError(\"Unsupported\");\n      }\n      estimateCPUTimeRemaining(cpuNode) {\n        const timingData = this.nodeTimings.getCpuStarted(cpuNode);\n        const multiplier = cpuNode.didPerformLayout() ? this.layoutTaskMultiplier : this.cpuSlowdownMultiplier;\n        const totalDuration = Math.min(Math.round(cpuNode.duration / 1e3 * multiplier), DEFAULT_MAXIMUM_CPU_TASK_DURATION);\n        const estimatedTimeElapsed = totalDuration - timingData.timeElapsed;\n        this.nodeTimings.setCpuEstimated(cpuNode, { estimatedTimeElapsed });\n        return estimatedTimeElapsed;\n      }\n      estimateNetworkTimeRemaining(networkNode) {\n        const request = networkNode.request;\n        const timingData = this.nodeTimings.getNetworkStarted(networkNode);\n        let timeElapsed = 0;\n        if (networkNode.fromDiskCache) {\n          const sizeInMb = (request.resourceSize || 0) / 1024 / 1024;\n          timeElapsed = 8 + 20 * sizeInMb - timingData.timeElapsed;\n        } else if (networkNode.isNonNetworkProtocol) {\n          const sizeInMb = (request.resourceSize || 0) / 1024 / 1024;\n          timeElapsed = 2 + 10 * sizeInMb - timingData.timeElapsed;\n        } else {\n          const connection = this.connectionPool.acquireActiveConnectionFromRequest(request);\n          const dnsResolutionTime = this.dns.getTimeUntilResolution(request, {\n            requestedAt: timingData.startTime,\n            shouldUpdateCache: true\n          });\n          const timeAlreadyElapsed = timingData.timeElapsed;\n          const calculation = connection.simulateDownloadUntil(request.transferSize - timingData.bytesDownloaded, { timeAlreadyElapsed, dnsResolutionTime, maximumTimeToElapse: Infinity });\n          timeElapsed = calculation.timeElapsed;\n        }\n        const estimatedTimeElapsed = timeElapsed + timingData.timeElapsedOvershoot;\n        this.nodeTimings.setNetworkEstimated(networkNode, { estimatedTimeElapsed });\n        return estimatedTimeElapsed;\n      }\n      /**\n       * Computes and returns the minimum estimated completion time of the nodes currently in progress.\n       */\n      findNextNodeCompletionTime() {\n        let minimumTime = Infinity;\n        for (const node of this.nodes[NodeState.InProgress]) {\n          minimumTime = Math.min(minimumTime, this.estimateTimeRemaining(node));\n        }\n        return minimumTime;\n      }\n      /**\n       * Given a time period, computes the progress toward completion that the node made during that time.\n       */\n      updateProgressMadeInTimePeriod(node, timePeriodLength, totalElapsedTime) {\n        const timingData = this.nodeTimings.getInProgress(node);\n        const isFinished = timingData.estimatedTimeElapsed === timePeriodLength;\n        if (node.type === BaseNode.types.CPU || node.isConnectionless) {\n          if (isFinished) {\n            this.markNodeAsComplete(node, totalElapsedTime);\n          } else {\n            timingData.timeElapsed += timePeriodLength;\n          }\n          return;\n        }\n        if (node.type !== BaseNode.types.NETWORK) {\n          throw new LanternError(\"Unsupported\");\n        }\n        if (!(\"bytesDownloaded\" in timingData)) {\n          throw new LanternError(\"Invalid timing data\");\n        }\n        const request = node.request;\n        const connection = this.connectionPool.acquireActiveConnectionFromRequest(request);\n        const dnsResolutionTime = this.dns.getTimeUntilResolution(request, {\n          requestedAt: timingData.startTime,\n          shouldUpdateCache: true\n        });\n        const calculation = connection.simulateDownloadUntil(request.transferSize - timingData.bytesDownloaded, {\n          dnsResolutionTime,\n          timeAlreadyElapsed: timingData.timeElapsed,\n          maximumTimeToElapse: timePeriodLength - timingData.timeElapsedOvershoot\n        });\n        connection.setCongestionWindow(calculation.congestionWindow);\n        connection.setH2OverflowBytesDownloaded(calculation.extraBytesDownloaded);\n        if (isFinished) {\n          connection.setWarmed(true);\n          this.connectionPool.release(request);\n          this.markNodeAsComplete(node, totalElapsedTime, calculation.connectionTiming);\n        } else {\n          timingData.timeElapsed += calculation.timeElapsed;\n          timingData.timeElapsedOvershoot += calculation.timeElapsed - timePeriodLength;\n          timingData.bytesDownloaded += calculation.bytesDownloaded;\n        }\n      }\n      computeFinalNodeTimings() {\n        const completeNodeTimingEntries = this.nodeTimings.getNodes().map((node) => {\n          return [node, this.nodeTimings.getCompleted(node)];\n        });\n        completeNodeTimingEntries.sort((a, b) => a[1].startTime - b[1].startTime);\n        const nodeTimingEntries = completeNodeTimingEntries.map(([node, timing]) => {\n          return [\n            node,\n            {\n              startTime: timing.startTime,\n              endTime: timing.endTime,\n              duration: timing.endTime - timing.startTime\n            }\n          ];\n        });\n        return {\n          nodeTimings: new Map(nodeTimingEntries),\n          completeNodeTimings: new Map(completeNodeTimingEntries)\n        };\n      }\n      getOptions() {\n        return this.options;\n      }\n      /**\n       * Estimates the time taken to process all of the graph's nodes, returns the overall time along with\n       * each node annotated by start/end times.\n       *\n       * Simulator/connection pool are allowed to deviate from what was\n       * observed in the trace/devtoolsLog and start requests as soon as they are queued (i.e. do not\n       * wait around for a warm connection to be available if the original request was fetched on a warm\n       * connection).\n       */\n      simulate(graph2, options) {\n        if (BaseNode.findCycle(graph2)) {\n          throw new LanternError(\"Cannot simulate graph with cycle\");\n        }\n        options = Object.assign({\n          label: void 0\n        }, options);\n        this.dns = new DNSCache({ rtt: this._rtt });\n        this.initializeConnectionPool(graph2);\n        this.initializeAuxiliaryData();\n        const nodesNotReadyToStart = this.nodes[NodeState.NotReadyToStart];\n        const nodesReadyToStart = this.nodes[NodeState.ReadyToStart];\n        const nodesInProgress = this.nodes[NodeState.InProgress];\n        const rootNode = graph2.getRootNode();\n        rootNode.traverse((node) => nodesNotReadyToStart.add(node));\n        let totalElapsedTime = 0;\n        let iteration = 0;\n        this.markNodeAsReadyToStart(rootNode, totalElapsedTime);\n        while (nodesReadyToStart.size || nodesInProgress.size) {\n          for (const node of this.getNodesSortedByStartPosition()) {\n            this.startNodeIfPossible(node, totalElapsedTime);\n          }\n          if (!nodesInProgress.size) {\n            throw new LanternError(\"Failed to start a node\");\n          }\n          this.updateNetworkCapacity();\n          const minimumTime = this.findNextNodeCompletionTime();\n          totalElapsedTime += minimumTime;\n          if (!Number.isFinite(minimumTime) || iteration > 1e5) {\n            throw new LanternError(\"Simulation failed, depth exceeded\");\n          }\n          iteration++;\n          for (const node of nodesInProgress) {\n            this.updateProgressMadeInTimePeriod(node, minimumTime, totalElapsedTime);\n          }\n        }\n        const { nodeTimings, completeNodeTimings } = this.computeFinalNodeTimings();\n        ALL_SIMULATION_NODE_TIMINGS.set(options.label || \"unlabeled\", completeNodeTimings);\n        return {\n          timeInMs: totalElapsedTime,\n          nodeTimings\n        };\n      }\n      computeWastedMsFromWastedBytes(wastedBytes) {\n        const { throughput, observedThroughput } = this.options;\n        const bitsPerSecond = throughput === 0 ? observedThroughput : throughput;\n        if (bitsPerSecond === 0) {\n          return 0;\n        }\n        const wastedBits = wastedBytes * 8;\n        const wastedMs = wastedBits / bitsPerSecond * 1e3;\n        return Math.round(wastedMs / 10) * 10;\n      }\n      // Used by Lighthouse asset-saver\n      static get allNodeTimings() {\n        return ALL_SIMULATION_NODE_TIMINGS;\n      }\n      /**\n       * We attempt to start nodes by their observed start time using the request priority as a tie breaker.\n       * When simulating, just because a low priority image started 5ms before a high priority image doesn't mean\n       * it would have happened like that when the network was slower.\n       */\n      static computeNodeStartPosition(node) {\n        if (node.type === \"cpu\") {\n          return node.startTime;\n        }\n        return node.startTime + (PriorityStartTimePenalty[node.request.priority] * 1e3 * 1e3 || 0);\n      }\n    };\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/lantern/simulation/simulation.js\nvar simulation_exports = {};\n__export(simulation_exports, {\n  ConnectionPool: () => ConnectionPool,\n  Constants: () => Constants,\n  DNSCache: () => DNSCache,\n  Simulator: () => Simulator,\n  SimulatorTimingMap: () => SimulatorTimingMap,\n  TCPConnection: () => TCPConnection\n});\nvar init_simulation = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/lantern/simulation/simulation.js\"() {\n    init_process_global();\n    init_ConnectionPool();\n    init_Constants();\n    init_DNSCache();\n    init_SimulationTimingMap();\n    init_Simulator();\n    init_TCPConnection();\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/lantern/types/Lantern.js\nvar NetworkRequestTypes;\nvar init_Lantern = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/lantern/types/Lantern.js\"() {\n    init_process_global();\n    NetworkRequestTypes = {\n      XHR: \"XHR\",\n      Fetch: \"Fetch\",\n      EventSource: \"EventSource\",\n      Script: \"Script\",\n      Stylesheet: \"Stylesheet\",\n      Image: \"Image\",\n      Media: \"Media\",\n      Font: \"Font\",\n      Document: \"Document\",\n      TextTrack: \"TextTrack\",\n      WebSocket: \"WebSocket\",\n      Other: \"Other\",\n      Manifest: \"Manifest\",\n      SignedExchange: \"SignedExchange\",\n      Ping: \"Ping\",\n      Preflight: \"Preflight\",\n      CSPViolationReport: \"CSPViolationReport\",\n      Prefetch: \"Prefetch\",\n      FedCM: \"FedCM\"\n    };\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/lantern/types/types.js\nvar types_exports = {};\n__export(types_exports, {\n  NetworkRequestTypes: () => NetworkRequestTypes\n});\nvar init_types = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/lantern/types/types.js\"() {\n    init_process_global();\n    init_Lantern();\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/lantern/lantern.js\nvar init_lantern = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/lantern/lantern.js\"() {\n    init_process_global();\n    init_core();\n    init_graph();\n    init_metrics();\n    init_simulation();\n    init_types();\n  }\n});\n\n// node_modules/@paulirish/trace_engine/node_modules/third-party-web/lib/create-entity-finder-api.js\nvar require_create_entity_finder_api = __commonJS({\n  \"node_modules/@paulirish/trace_engine/node_modules/third-party-web/lib/create-entity-finder-api.js\"(exports2, module2) {\n    init_process_global();\n    var DOMAIN_IN_URL_REGEX = /:\\/\\/(\\S*?)(:\\d+)?(\\/|$)/;\n    var DOMAIN_CHARACTERS = /([a-z0-9.-]+\\.[a-z0-9]+|localhost)/i;\n    var IP_REGEX = /^\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}$/;\n    var ROOT_DOMAIN_REGEX = /[^.]+\\.([^.]+|(gov|com|co|ne)\\.\\w{2})$/i;\n    function getDomainFromOriginOrURL(originOrURL) {\n      if (typeof originOrURL !== \"string\") return null;\n      if (originOrURL.length > 1e4 || originOrURL.startsWith(\"data:\")) return null;\n      if (DOMAIN_IN_URL_REGEX.test(originOrURL)) return originOrURL.match(DOMAIN_IN_URL_REGEX)[1];\n      if (DOMAIN_CHARACTERS.test(originOrURL)) return originOrURL.match(DOMAIN_CHARACTERS)[0];\n      return null;\n    }\n    __name(getDomainFromOriginOrURL, \"getDomainFromOriginOrURL\");\n    function getRootDomain(originOrURL) {\n      const domain = getDomainFromOriginOrURL(originOrURL);\n      if (!domain) return null;\n      if (IP_REGEX.test(domain)) return domain;\n      const match = domain.match(ROOT_DOMAIN_REGEX);\n      return match && match[0] || domain;\n    }\n    __name(getRootDomain, \"getRootDomain\");\n    function sliceSubdomainFromDomain(domain, rootDomain) {\n      if (domain.length <= rootDomain.length) return domain;\n      return domain.split(\".\").slice(1).join(\".\");\n    }\n    __name(sliceSubdomainFromDomain, \"sliceSubdomainFromDomain\");\n    function getEntityInDataset(entityByDomain, entityBySubDomain, entityByRootDomain, originOrURL) {\n      const domain = getDomainFromOriginOrURL(originOrURL);\n      const rootDomain = getRootDomain(domain);\n      if (!domain || !rootDomain) return void 0;\n      if (entityByDomain.has(domain)) return entityByDomain.get(domain);\n      for (let subdomain = domain; subdomain.length > rootDomain.length; subdomain = sliceSubdomainFromDomain(subdomain, rootDomain)) {\n        if (entityBySubDomain.has(subdomain)) return entityBySubDomain.get(subdomain);\n      }\n      if (entityByRootDomain.has(rootDomain)) return entityByRootDomain.get(rootDomain);\n      return void 0;\n    }\n    __name(getEntityInDataset, \"getEntityInDataset\");\n    function getProductInDataset(entityByDomain, entityBySubDomain, entityByRootDomain, originOrURL) {\n      const entity = getEntityInDataset(\n        entityByDomain,\n        entityBySubDomain,\n        entityByRootDomain,\n        originOrURL\n      );\n      const products = entity && entity.products;\n      if (!products) return void 0;\n      if (typeof originOrURL !== \"string\") return void 0;\n      for (const product of products) {\n        for (const pattern of product.urlPatterns) {\n          if (pattern instanceof RegExp && pattern.test(originOrURL)) return product;\n          if (typeof pattern === \"string\" && originOrURL.includes(pattern)) return product;\n        }\n      }\n      return void 0;\n    }\n    __name(getProductInDataset, \"getProductInDataset\");\n    function cloneEntities(entities) {\n      return entities.map((entity_) => {\n        const entity = {\n          company: entity_.name,\n          categories: [entity_.category],\n          ...entity_\n        };\n        const products = (entity_.products || []).map((product) => ({\n          company: entity.company,\n          category: entity.category,\n          categories: [entity.category],\n          facades: [],\n          ...product,\n          urlPatterns: (product.urlPatterns || []).map(\n            (s) => s.startsWith(\"REGEXP:\") ? new RegExp(s.slice(\"REGEXP:\".length)) : s\n          )\n        }));\n        entity.products = products;\n        return entity;\n      });\n    }\n    __name(cloneEntities, \"cloneEntities\");\n    function createAPIFromDataset(entities_) {\n      const entities = cloneEntities(entities_);\n      const entityByDomain = /* @__PURE__ */ new Map();\n      const entityByRootDomain = /* @__PURE__ */ new Map();\n      const entityBySubDomain = /* @__PURE__ */ new Map();\n      for (const entity of entities) {\n        entity.totalExecutionTime = Number(entity.totalExecutionTime) || 0;\n        entity.totalOccurrences = Number(entity.totalOccurrences) || 0;\n        entity.averageExecutionTime = entity.totalExecutionTime / entity.totalOccurrences;\n        for (const domain of entity.domains) {\n          if (entityByDomain.has(domain)) {\n            const duplicate = entityByDomain.get(domain);\n            throw new Error(`Duplicate domain ${domain} (${entity.name} and ${duplicate.name})`);\n          }\n          entityByDomain.set(domain, entity);\n          const rootDomain = getRootDomain(domain);\n          if (domain.startsWith(\"*.\")) {\n            const wildcardDomain = domain.slice(2);\n            if (wildcardDomain === rootDomain) entityByRootDomain.set(rootDomain, entity);\n            else entityBySubDomain.set(wildcardDomain, entity);\n          }\n        }\n      }\n      for (const [rootDomain, entity] of entityByRootDomain.entries()) {\n        if (!entity) entityByRootDomain.delete(rootDomain);\n      }\n      const getEntity = getEntityInDataset.bind(\n        null,\n        entityByDomain,\n        entityBySubDomain,\n        entityByRootDomain\n      );\n      const getProduct = getProductInDataset.bind(\n        null,\n        entityByDomain,\n        entityBySubDomain,\n        entityByRootDomain\n      );\n      return { getEntity, getProduct, getRootDomain, entities };\n    }\n    __name(createAPIFromDataset, \"createAPIFromDataset\");\n    module2.exports = { createAPIFromDataset };\n  }\n});\n\n// node_modules/@paulirish/trace_engine/node_modules/third-party-web/dist/entities.json\nvar require_entities = __commonJS({\n  \"node_modules/@paulirish/trace_engine/node_modules/third-party-web/dist/entities.json\"(exports2, module2) {\n    module2.exports = [{ name: \"Google/Doubleclick Ads\", company: \"Google\", homepage: \"https://marketingplatform.google.com/about/enterprise/\", category: \"ad\", domains: [\"adservice.google.com\", \"adservice.google.com.au\", \"adservice.google.com.sg\", \"adservice.google.com.br\", \"adservice.google.com.ua\", \"adservice.google.co.uk\", \"adservice.google.co.jp\", \"adservice.google.co.in\", \"adservice.google.co.kr\", \"adservice.google.co.id\", \"adservice.google.co.nz\", \"adservice.google.ie\", \"adservice.google.se\", \"adservice.google.de\", \"adservice.google.ca\", \"adservice.google.be\", \"adservice.google.es\", \"adservice.google.ch\", \"adservice.google.fr\", \"adservice.google.nl\", \"*.googleadservices.com\", \"*.googlesyndication.com\", \"*.googletagservices.com\", \"*.2mdn.net\", \"*.doubleclick.net\"], examples: [\"pagead2.googlesyndication.com\", \"tpc.googlesyndication.com\", \"ade.googlesyndication.com\", \"googleads.g.doubleclick.net\", \"googleads4.g.doubleclick.net\", \"securepubads.g.doubleclick.net\", \"pubads.g.doubleclic\\\nk.net\", \"static.doubleclick.net\", \"cm.g.doubleclick.net\", \"bid.g.doubleclick.net\", \"s0.2mdn.net\", \"stats.g.doubleclick.net\", \"survey.g.doubleclick.net\", \"fls.doubleclick.net\", \"ad.doubleclick.net\", \"www.googleadservices.com\", \"https://www.googletagservices.com/tag/js/gpt.js\"], totalExecutionTime: 3224311743, totalOccurrences: 1232210 }, { name: \"Facebook\", homepage: \"https://www.facebook.com\", category: \"social\", domains: [\"*.facebook.com\", \"*.atlassbx.com\", \"*.fbsbx.com\", \"fbcdn-photos-e-a.akamaihd.net\", \"*.facebook.net\", \"*.fbcdn.net\"], examples: [\"www.facebook.com\", \"connect.facebook.net\", \"staticxx.facebook.com\", \"static.xx.fbcdn.net\", \"m.facebook.com\", \"an.facebook.com\", \"platform-lookaside.fbsbx.com\"], products: [{ name: \"Facebook Messenger Customer Chat\", urlPatterns: [\"REGEXP:connect\\\\.facebook\\\\.net\\\\/.*\\\\/sdk\\\\/xfbml\\\\.customerchat\\\\.js\"], facades: [{ name: \"React Live Chat Loader\", repo: \"https://github.com/calibreapp/react-live-chat-loader\" }] }], totalExecutionTime: 1097107210,\n    totalOccurrences: 3157799 }, { name: \"Instagram\", homepage: \"https://www.instagram.com\", category: \"social\", domains: [\"*.cdninstagram.com\", \"*.instagram.com\"], examples: [\"scontent.cdninstagram.com\"], totalExecutionTime: 31988464, totalOccurrences: 20376 }, { name: \"Google CDN\", company: \"Google\", homepage: \"https://developers.google.com/speed/libraries/\", category: \"cdn\", domains: [\"ajax.googleapis.com\", \"commondatastorage.googleapis.com\", \"www.gstatic.com\", \"ssl.gstatic.com\"], totalExecutionTime: 4805631169, totalOccurrences: 3192326 }, { name: \"Google Maps\", company: \"Google\", homepage: \"https://www.google.com/maps\", category: \"utility\", domains: [\"maps.google.com\", \"maps-api-ssl.google.com\", \"maps.googleapis.com\", \"mts.googleapis.com\", \"mt.googleapis.com\", \"mt0.googleapis.com\", \"mt1.googleapis.com\", \"mt2.googleapis.com\", \"mt3.googleapis.com\", \"khm0.googleapis.com\", \"khm1.googleapis.com\", \"khms.googleapis.com\", \"khms1.googleapis.com\", \"khms2.googleapis.com\", \"maps.gstatic.com\"],\n    totalExecutionTime: 904392768, totalOccurrences: 1195850 }, { name: \"Other Google APIs/SDKs\", company: \"Google\", homepage: \"https://developers.google.com/apis-explorer/#p/\", category: \"utility\", domains: [\"accounts.google.com\", \"apis.google.com\", \"calendar.google.com\", \"clients2.google.com\", \"cse.google.com\", \"news.google.com\", \"pay.google.com\", \"payments.google.com\", \"play.google.com\", \"smartlock.google.com\", \"www.google.com\", \"www.google.de\", \"www.google.co.jp\", \"www.google.com.au\", \"www.google.co.uk\", \"www.google.ie\", \"www.google.com.sg\", \"www.google.co.in\", \"www.google.com.br\", \"www.google.ca\", \"www.google.co.kr\", \"www.google.co.nz\", \"www.google.co.id\", \"www.google.fr\", \"www.google.be\", \"www.google.com.ua\", \"www.google.nl\", \"www.google.ru\", \"www.google.se\", \"www.googleapis.com\", \"imasdk.googleapis.com\", \"storage.googleapis.com\", \"translate.googleapis.com\", \"translate.google.com\", \"translate-pa.googleapis.com\", \"lh3.googleusercontent.com\", \"jnn-pa.googleapis.com\", \"csi.gstatic.c\\\nom\"], totalExecutionTime: 1158368443, totalOccurrences: 2638940 }, { name: \"Firebase\", homepage: \"https://developers.google.com/apis-explorer/#p/\", category: \"utility\", domains: [\"firebasestorage.googleapis.com\", \"firestore.googleapis.com\", \"firebaseinstallations.googleapis.com\", \"firebase.googleapis.com\", \"firebaseremoteconfig.googleapis.com\"], totalExecutionTime: 201194, totalOccurrences: 493 }, { name: \"Google Analytics\", company: \"Google\", homepage: \"https://marketingplatform.google.com/about/analytics/\", category: \"analytics\", domains: [\"*.google-analytics.com\", \"*.urchin.com\", \"analytics.google.com\"], examples: [\"www.google-analytics.com\", \"ssl.google-analytics.com\", \"analytics.google.com/g/collect\"], totalExecutionTime: 495649535, totalOccurrences: 4231882 }, { name: \"Google Optimize\", company: \"Google\", homepage: \"https://marketingplatform.google.com/about/optimize/\", category: \"analytics\", domains: [\"www.googleoptimize.com\"], examples: [\"https://www.googleoptimize.com/optimize\\\n.js?id=\"], totalExecutionTime: 9330261, totalOccurrences: 38797 }, { name: \"Google AMP\", company: \"Google\", homepage: \"https://github.com/google/amp-client-id-library\", category: \"analytics\", domains: [\"ampcid.google.com\"] }, { name: \"Google Tag Manager\", company: \"Google\", homepage: \"https://marketingplatform.google.com/about/tag-manager/\", category: \"tag-manager\", domains: [\"*.googletagmanager.com\"], examples: [\"www.googletagmanager.com\"], totalExecutionTime: 6770912735, totalOccurrences: 8124119 }, { name: \"Google Fonts\", company: \"Google\", homepage: \"https://fonts.google.com/\", category: \"cdn\", domains: [\"fonts.googleapis.com\", \"fonts.gstatic.com\"], totalExecutionTime: 53081, totalOccurrences: 220864 }, { name: \"Adobe TypeKit\", company: \"Adobe\", homepage: \"https://fonts.adobe.com/\", category: \"cdn\", domains: [\"*.typekit.com\", \"*.typekit.net\"], examples: [\"use.typekit.net\", \"p.typekit.net\"], totalExecutionTime: 78981507, totalOccurrences: 119621 }, { name: \"YouTube\", homepage: \"http\\\ns://youtube.com\", category: \"video\", domains: [\"*.youtube.com\", \"*.ggpht.com\", \"*.youtube-nocookie.com\", \"*.ytimg.com\"], examples: [\"www.youtube.com\", \"s.ytimg.com\", \"yt3.ggpht.com\", \"img.youtube.com\", \"fcmatch.youtube.com\"], products: [{ name: \"YouTube Embedded Player\", urlPatterns: [\"youtube.com/embed/\"], facades: [{ name: \"Lite YouTube\", repo: \"https://github.com/paulirish/lite-youtube-embed\" }, { name: \"Ngx Lite Video\", repo: \"https://github.com/karim-mamdouh/ngx-lite-video\" }] }], totalExecutionTime: 6277579675, totalOccurrences: 977311 }, { name: \"Twitter\", homepage: \"https://twitter.com\", category: \"social\", domains: [\"*.vine.co\", \"*.twimg.com\", \"*.twitpic.com\", \"platform.twitter.com\", \"syndication.twitter.com\"], examples: [\"cdn.syndication.twimg.com\", \"abs.twimg.com\", \"pbs.twimg.com\"], totalExecutionTime: 804233203, totalOccurrences: 319957 }, { name: \"AddThis\", homepage: \"https://www.addthis.com/\", category: \"social\", domains: [\"*.addthis.com\", \"*.addthiscdn.com\", \"*.addthised\\\nge.com\"], examples: [\"s7.addthis.com\", \"r.dlx.addthis.com\", \"su.addthis.com\", \"x.dlx.addthis.com\"], totalExecutionTime: 23, totalOccurrences: 42 }, { name: \"AddToAny\", homepage: \"https://www.addtoany.com/\", category: \"social\", domains: [\"*.addtoany.com\"], examples: [\"static.addtoany.com\"], totalExecutionTime: 10606113, totalOccurrences: 66065 }, { name: \"Akamai\", homepage: \"https://www.akamai.com/\", category: \"cdn\", domains: [\"23.62.3.183\", \"*.akamaitechnologies.com\", \"*.akamaitechnologies.fr\", \"*.akamai.net\", \"*.akamaiedge.net\", \"*.akamaihd.net\", \"*.akamaized.net\", \"*.edgefcs.net\", \"*.edgekey.net\", \"edgesuite.net\", \"*.srip.net\"], totalExecutionTime: 4795669, totalOccurrences: 9820 }, { name: \"Blogger\", homepage: \"https://www.blogger.com/\", category: \"hosting\", domains: [\"*.blogblog.com\", \"*.blogger.com\", \"*.blogspot.com\", \"images-blogger-opensocial.googleusercontent.com\"], examples: [\"1.bp.blogspot.com\", \"www.blogger.com\"], totalExecutionTime: 58390438, totalOccurrences: 213326 }, { name: \"\\\nGravatar\", homepage: \"https://en.gravatar.com/\", category: \"social\", domains: [\"*.gravatar.com\"], examples: [\"secure.gravatar.com\", \"www.gravatar.com\"], totalExecutionTime: 9235, totalOccurrences: 43 }, { name: \"Yandex Metrica\", company: \"Yandex\", homepage: \"https://metrica.yandex.com/about?\", category: \"analytics\", domains: [\"mc.yandex.ru\", \"mc.yandex.com\", \"d31j93rd8oukbv.cloudfront.net\"], totalExecutionTime: 1438544698, totalOccurrences: 602136 }, { name: \"Hotjar\", homepage: \"https://www.hotjar.com/\", category: \"analytics\", domains: [\"*.hotjar.com\", \"*.hotjar.io\"], examples: [\"script.hotjar.com\", \"static.hotjar.com\", \"in.hotjar.com\", \"vc.hotjar.io\", \"vars.hotjar.com\"], totalExecutionTime: 241418055, totalOccurrences: 333356 }, { name: \"Baidu Analytics\", homepage: \"https://tongji.baidu.com/web/welcome/login\", category: \"analytics\", domains: [\"hm.baidu.com\", \"hmcdn.baidu.com\"], examples: [\"hm.baidu.com\", \"hmcdn.baidu.com\"], totalExecutionTime: 7739347, totalOccurrences: 32612 }, { name: \"\\\nInsider\", homepage: \"\", category: \"analytics\", domains: [\"*.useinsider.com\"], examples: [\"hit.api.useinsider.com\"], totalExecutionTime: 2214966, totalOccurrences: 1861 }, { name: \"Adobe Experience Cloud\", company: \"Adobe\", homepage: \"\", category: \"analytics\", domains: [\"*.2o7.net\", \"du8783wkf05yr.cloudfront.net\", \"*.hitbox.com\", \"*.imageg.net\", \"*.nedstat.com\", \"*.omtrdc.net\"], examples: [\"audiag.112.2o7.net\", \"du8783wkf05yr.cloudfront.net/NS_mbox.js\"], totalExecutionTime: 2369, totalOccurrences: 38 }, { name: \"Adobe Tag Manager\", company: \"Adobe\", homepage: \"https://www.adobe.com/experience-platform/\", category: \"tag-manager\", domains: [\"*.adobedtm.com\", \"*.demdex.net\", \"*.everesttech.net\", \"sstats.adobe.com\", \"hbrt.adobe.com\"], examples: [\"assets.adobedtm.com\", \"sync-tm.everesttech.net\", \"cm.everesttech.net\"], totalExecutionTime: 34937564, totalOccurrences: 200160 }, { name: \"jQuery CDN\", homepage: \"https://code.jquery.com/\", category: \"cdn\", domains: [\"*.jquery.com\"], examples: [\"co\\\nde.jquery.com\"], totalExecutionTime: 302334055, totalOccurrences: 724477 }, { name: \"Cloudflare CDN\", homepage: \"https://cdnjs.com/\", category: \"cdn\", domains: [\"cdnjs.cloudflare.com\", \"amp.cloudflare.com\"], totalExecutionTime: 337711119, totalOccurrences: 666628 }, { name: \"Cloudflare\", homepage: \"https://www.cloudflare.com/website-optimization/\", category: \"utility\", domains: [\"ajax.cloudflare.com\", \"*.nel.cloudflare.com\", \"static.cloudflareinsights.com\"], totalExecutionTime: 58723052, totalOccurrences: 467719 }, { name: \"WordPress\", company: \"Automattic\", homepage: \"https://wp.com/\", category: \"hosting\", domains: [\"*.wordpress.com\", \"s0.wp.com\", \"s2.wp.com\", \"*.w.org\", \"c0.wp.com\", \"s1.wp.com\", \"i0.wp.com\", \"i1.wp.com\", \"i2.wp.com\", \"widgets.wp.com\"], examples: [\"s.w.org\"], totalExecutionTime: 220910650, totalOccurrences: 308694 }, { name: \"WordPress Site Stats\", company: \"Automattic\", homepage: \"https://wp.com/\", category: \"analytics\", domains: [\"pixel.wp.com\", \"stats.wp.com\"], totalExecutionTime: 8573549,\n    totalOccurrences: 128931 }, { name: \"Hatena Blog\", homepage: \"https://hatenablog.com/\", category: \"hosting\", domains: [\"*.st-hatena.com\", \"*.hatena.ne.jp\"], examples: [\"cdn.blog.st-hatena.com\", \"cdn.pool.st-hatena.com\", \"cdn7.www.st-hatena.com\", \"s.hatena.ne.jp\", \"b.st-hatena.com\"], totalExecutionTime: 106337940, totalOccurrences: 43183 }, { name: \"Shopify\", homepage: \"https://www.shopify.com/\", category: \"hosting\", domains: [\"*.shopify.com\", \"*.shopifyapps.com\", \"*.shopifycdn.com\", \"*.shopifysvc.com\"], examples: [\"cdn.shopify.com\", \"productreviews.shopifycdn.com\", \"monorail-edge.shopifysvc.com\"], totalExecutionTime: 287428893, totalOccurrences: 338668 }, { name: \"Dealer\", homepage: \"https://www.dealer.com/\", category: \"hosting\", domains: [\"*.dealer.com\"], examples: [\"static.dealer.com\"], totalExecutionTime: 871324, totalOccurrences: 2620 }, { name: \"PIXNET\", homepage: \"https://www.pixnet.net/\", category: \"social\", domains: [\"*.pixfs.net\", \"*.pixnet.net\"], examples: [\"front.pixfs.n\\\net\", \"falcon-asset.pixfs.net\", \"pixgame-asset.pixfs.net\"], totalExecutionTime: 18541448, totalOccurrences: 13718 }, { name: \"Moat\", homepage: \"https://moat.com/\", category: \"ad\", domains: [\"*.moatads.com\", \"*.moatpixel.com\"], examples: [\"z.moatads.com\", \"px.moatads.com\", \"geo.moatads.com\", \"sejs.moatads.com\", \"mb.moatads.com\", \"v4.moatads.com\"] }, { name: \"33 Across\", homepage: \"https://33across.com/\", category: \"ad\", domains: [\"*.33across.com\"], examples: [\"sic.33across.com\", \"cdn-sic.33across.com\"], totalExecutionTime: 10002146, totalOccurrences: 192648 }, { name: \"OpenX\", homepage: \"https://www.openx.com/\", category: \"ad\", domains: [\"*.deliverimp.com\", \"*.openxadexchange.com\", \"*.servedbyopenx.com\", \"*.jump-time.net\", \"*.openx.net\", \"*.openxcdn.net\"], examples: [\"uk-ads.openx.net\", \"us-ads.openx.net\", \"33across-d.openx.net\", \"rtb.openx.net\", \"us-u.openx.net\", \"eu-u.openx.net\", \"u.openx.net\"], totalExecutionTime: 6274934, totalOccurrences: 76561 }, { name: \"Amazon Ads\", homepage: \"ht\\\ntps://ad.amazon.com/\", category: \"ad\", domains: [\"*.amazon-adsystem.com\"], examples: [\"s.amazon-adsystem.com\", \"c.amazon-adsystem.com\", \"aax.amazon-adsystem.com\", \"z-na.amazon-adsystem.com\", \"fls-na.amazon-adsystem.com\", \"aax-us-east.amazon-adsystem.com\", \"ir-na.amazon-adsystem.com\"], totalExecutionTime: 98703856, totalOccurrences: 240331 }, { name: \"Rubicon Project\", homepage: \"https://rubiconproject.com/\", category: \"ad\", domains: [\"*.rubiconproject.com\", \"*.chango.com\", \"*.fimserve.com\"], examples: [\"pixel.rubiconproject.com\", \"fastlane.rubiconproject.com\", \"secure-assets.rubiconproject.com\", \"eus.rubiconproject.com\", \"pixel-us-east.rubiconproject.com\", \"token.rubiconproject.com\", \"ads.rubiconproject.com\"], totalExecutionTime: 287111007, totalOccurrences: 270271 }, { name: \"The Trade Desk\", homepage: \"https://www.thetradedesk.com/\", category: \"ad\", domains: [\"*.adsrvr.org\", \"d1eoo1tco6rr5e.cloudfront.net\"], examples: [\"js.adsrvr.org\", \"match.adsrvr.org\", \"insight.adsrvr.org\", \"usw-l\\\nax.adsrvr.org\", \"data.adsrvr.org\", \"snap.adsrvr.org\"], totalExecutionTime: 2197325, totalOccurrences: 25346 }, { name: \"Bidswitch\", homepage: \"https://www.bidswitch.com/\", category: \"ad\", domains: [\"*.bidswitch.net\"], examples: [\"x.bidswitch.net\"], totalExecutionTime: 25660, totalOccurrences: 68217 }, { name: \"LiveRamp IdentityLink\", homepage: \"https://liveramp.com/discover-identitylink/\", category: \"analytics\", domains: [\"*.circulate.com\", \"*.rlcdn.com\"], examples: [\"idsync.rlcdn.com\", \"id.rlcdn.com\", \"api.rlcdn.com\", \"cdn.rlcdn.com\"], totalExecutionTime: 141414, totalOccurrences: 1461 }, { name: \"Drawbridge\", homepage: \"https://www.drawbridge.com/\", category: \"ad\", domains: [\"*.adsymptotic.com\"] }, { name: \"AOL / Oath / Verizon Media\", homepage: \"https://www.oath.com/\", category: \"ad\", domains: [\"*.advertising.com\", \"*.aol.com\", \"*.aolcdn.com\", \"*.blogsmithmedia.com\", \"*.oath.com\", \"*.aol.net\", \"*.tacoda.net\", \"*.aol.co.uk\"], examples: [\"pixel.advertising.com\", \"dtm.advertising.com\",\n    \"tag.sp.advertising.com\", \"service.sp.advertising.com\", \"adtech.advertising.com\", \"adaptv.advertising.com\", \"mighty.aol.net\", \"consent.cmp.oath.com\"], totalExecutionTime: 165968, totalOccurrences: 278 }, { name: \"Xaxis\", homepage: \"https://www.xaxis.com/\", category: \"ad\", domains: [\"*.247realmedia.com\", \"*.mookie1.com\", \"*.gmads.net\"], examples: [\"t.mookie1.com\", \"odr.mookie1.com\"], totalExecutionTime: 28343, totalOccurrences: 209 }, { name: \"Freshdesk\", company: \"Freshworks\", homepage: \"https://freshdesk.com/\", category: \"customer-success\", domains: [\"d36mpcpuzc4ztk.cloudfront.net\"], totalExecutionTime: 64296, totalOccurrences: 225 }, { name: \"Help Scout\", homepage: \"https://www.helpscout.net/\", category: \"customer-success\", domains: [\"djtflbt20bdde.cloudfront.net\", \"*.helpscout.net\"], examples: [\"beacon-v2.helpscout.net\"], products: [{ name: \"Help Scout Beacon\", urlPatterns: [\"beacon-v2.helpscout.net\"], facades: [{ name: \"React Live Chat Loader\", repo: \"https://github.com/calibre\\\napp/react-live-chat-loader\" }] }], totalExecutionTime: 2186050, totalOccurrences: 4906 }, { name: \"Alexa\", homepage: \"https://www.alexa.com/\", category: \"analytics\", domains: [\"*.alexametrics.com\", \"d31qbv1cthcecs.cloudfront.net\"], examples: [\"certify.alexametrics.com\"] }, { name: \"OneSignal\", homepage: \"https://onesignal.com/\", category: \"utility\", domains: [\"*.onesignal.com\"], examples: [\"cdn.onesignal.com\", \"https://onesignal.com/api/v1/sync/\"], totalExecutionTime: 17761218, totalOccurrences: 68282 }, { name: \"Lucky Orange\", homepage: \"https://www.luckyorange.com/\", category: \"analytics\", domains: [\"*.luckyorange.com\", \"d10lpsik1i8c69.cloudfront.net\", \"*.luckyorange.net\"], totalExecutionTime: 12779009, totalOccurrences: 16442 }, { name: \"Crazy Egg\", homepage: \"https://www.crazyegg.com/\", category: \"analytics\", domains: [\"*.cetrk.com\", \"*.crazyegg.com\", \"dnn506yrbagrg.cloudfront.net\"], totalExecutionTime: 27593244, totalOccurrences: 43822 }, { name: \"Hello Bar\", homepage: \"https://ww\\\nw.hellobar.com/\", category: \"marketing\", domains: [\"*.hellobar.com\"], totalExecutionTime: 1533955, totalOccurrences: 4502 }, { name: \"Yandex Ads\", company: \"Yandex\", homepage: \"https://yandex.com/adv/\", category: \"ad\", domains: [\"an.yandex.ru\"], totalExecutionTime: 5171537, totalOccurrences: 8488 }, { name: \"Salesforce\", homepage: \"https://www.salesforce.com/products/marketing-cloud/\", category: \"analytics\", domains: [\"*.krxd.net\"], examples: [\"cdn.krxd.net\", \"beacon.krxd.net\", \"consumer.krxd.net\", \"usermatch.krxd.net\"] }, { name: \"Salesforce Commerce Cloud\", homepage: \"https://www.salesforce.com/products/commerce-cloud/overview/\", category: \"hosting\", domains: [\"*.cquotient.com\", \"*.demandware.net\", \"demandware.edgesuite.net\"], totalExecutionTime: 2045309, totalOccurrences: 4127 }, { name: \"Optimizely\", homepage: \"https://www.optimizely.com/\", category: \"analytics\", domains: [\"*.optimizely.com\"], examples: [\"cdn.optimizely.com\", \"cdn-pci.optimizely.com\", \"logx.optimizely.com\", \"cdn3.o\\\nptimizely.com\"], totalExecutionTime: 12599739, totalOccurrences: 15998 }, { name: \"LiveChat\", homepage: \"https://www.livechat.com/\", category: \"customer-success\", domains: [\"*.livechatinc.com\", \"*.livechat.com\", \"*.livechat-static.com\"], examples: [\"cdn.livechatinc.com\", \"secure.livechatinc.com\"], totalExecutionTime: 49171416, totalOccurrences: 39034 }, { name: \"VK\", homepage: \"https://vk.com/\", category: \"social\", domains: [\"*.vk.com\"], totalExecutionTime: 91334176, totalOccurrences: 22377 }, { name: \"Tumblr\", homepage: \"https://tumblr.com/\", category: \"social\", domains: [\"*.tumblr.com\"], examples: [\"assets.tumblr.com\", \"static.tumblr.com\"], totalExecutionTime: 45570825, totalOccurrences: 18114 }, { name: \"Wistia\", homepage: \"https://wistia.com/\", category: \"video\", domains: [\"*.wistia.com\", \"embedwistia-a.akamaihd.net\", \"*.wistia.net\"], examples: [\"fast.wistia.com\", \"fast.wistia.net\", \"distillery.wistia.com\", \"pipedream.wistia.com\"], totalExecutionTime: 115722112, totalOccurrences: 27059 },\n    { name: \"Brightcove\", homepage: \"https://www.brightcove.com/en/\", category: \"video\", domains: [\"*.brightcove.com\", \"*.brightcove.net\", \"*.zencdn.net\"], examples: [\"vjs.zencdn.net\", \"players.brightcove.net\"], totalExecutionTime: 15099708, totalOccurrences: 13745 }, { name: \"JSDelivr CDN\", homepage: \"https://www.jsdelivr.com/\", category: \"cdn\", domains: [\"*.jsdelivr.net\"], examples: [\"cdn.jsdelivr.net\"], totalExecutionTime: 260364458, totalOccurrences: 399959 }, { name: \"Sumo\", homepage: \"https://sumo.com/\", category: \"marketing\", domains: [\"*.sumo.com\", \"*.sumome.com\", \"sumo.b-cdn.net\"], examples: [\"sumo.b-cdn.net\", \"load.sumo.com\", \"load.sumome.com\"], totalExecutionTime: 16489977, totalOccurrences: 10901 }, { name: \"Vimeo\", homepage: \"https://vimeo.com/\", category: \"video\", domains: [\"*.vimeo.com\", \"*.vimeocdn.com\"], examples: [\"f.vimeocdn.com\", \"player.vimeo.com\", \"i.vimeocdn.com\"], products: [{ name: \"Vimeo Embedded Player\", urlPatterns: [\"player.vimeo.com/video/\"], facades: [{ name: \"\\\nLite Vimeo\", repo: \"https://github.com/slightlyoff/lite-vimeo\" }, { name: \"Lite Vimeo Embed\", repo: \"https://github.com/luwes/lite-vimeo-embed\" }, { name: \"Ngx Lite Video\", repo: \"https://github.com/karim-mamdouh/ngx-lite-video\" }] }], totalExecutionTime: 263943622, totalOccurrences: 120397 }, { name: \"Disqus\", homepage: \"https://disqus.com/\", category: \"social\", domains: [\"*.disqus.com\", \"*.disquscdn.com\"], examples: [\"c.disquscdn.com\"], totalExecutionTime: 3697272, totalOccurrences: 1775 }, { name: \"Yandex APIs\", company: \"Yandex\", homepage: \"https://yandex.ru/\", category: \"utility\", domains: [\"api-maps.yandex.ru\", \"money.yandex.ru\"], totalExecutionTime: 40765111, totalOccurrences: 51601 }, { name: \"Yandex CDN\", company: \"Yandex\", homepage: \"https://yandex.ru/\", category: \"cdn\", domains: [\"*.yandex.st\", \"*.yastatic.net\"], examples: [\"https://yastatic.net/share2/share.js\", \"https://yastatic.net/jquery/2.1.4/jquery.min.js\"] }, { name: \"Integral Ad Science\", homepage: \"https://integrala\\\nds.com/uk/\", category: \"ad\", domains: [\"*.adsafeprotected.com\", \"*.iasds01.com\"], examples: [\"pixel.adsafeprotected.com\", \"static.adsafeprotected.com\", \"fw.adsafeprotected.com\", \"cdn.adsafeprotected.com\", \"dt.adsafeprotected.com\"], totalExecutionTime: 88554254, totalOccurrences: 21660 }, { name: \"Tealium\", homepage: \"https://tealium.com/\", category: \"tag-manager\", domains: [\"*.aniview.com\", \"*.delvenetworks.com\", \"*.limelight.com\", \"*.tiqcdn.com\", \"*.llnwd.net\", \"*.tealiumiq.com\"], examples: [\"tags.tiqcdn.com\", \"tealium.hs.llnwd.net\", \"link.videoplatform.limelight.com\", \"datacloud.tealiumiq.com\"], totalExecutionTime: 20176561, totalOccurrences: 75434 }, { name: \"Pubmatic\", homepage: \"https://pubmatic.com/\", category: \"ad\", domains: [\"*.pubmatic.com\"], examples: [\"image6.pubmatic.com\", \"ads.pubmatic.com\", \"image2.pubmatic.com\", \"simage2.pubmatic.com\", \"image4.pubmatic.com\", \"simage4.pubmatic.com\", \"image5.pubmatic.com\", \"hbopenbid.pubmatic.com\"], totalExecutionTime: 417694368, totalOccurrences: 279418 },\n    { name: \"Olark\", homepage: \"https://www.olark.com/\", category: \"customer-success\", domains: [\"*.olark.com\"], examples: [\"static.olark.com\"], totalExecutionTime: 9840846, totalOccurrences: 6534 }, { name: \"Tawk.to\", homepage: \"https://www.tawk.to/\", category: \"customer-success\", domains: [\"*.tawk.to\"], examples: [\"embed.tawk.to\"], totalExecutionTime: 43074965, totalOccurrences: 111088 }, { name: \"OptinMonster\", homepage: \"https://optinmonster.com/\", category: \"marketing\", domains: [\"*.opmnstr.com\", \"*.optmnstr.com\", \"*.optmstr.com\"], examples: [\"a.optmstr.com\", \"api.opmnstr.com\", \"a.optmnstr.com\"], totalExecutionTime: 1035991, totalOccurrences: 2346 }, { name: \"ZenDesk\", homepage: \"https://zendesk.com/\", category: \"customer-success\", domains: [\"*.zdassets.com\", \"*.zendesk.com\", \"*.zopim.com\"], examples: [\"assets.zendesk.com\", \"static.zdassets.com\", \"v2.zopim.com\"], totalExecutionTime: 106701440, totalOccurrences: 72537 }, { name: \"Pusher\", homepage: \"https://pusher.com/\", category: \"\\\nutility\", domains: [\"*.pusher.com\", \"*.pusherapp.com\"], examples: [\"stats.pusher.com\"], totalExecutionTime: 152727, totalOccurrences: 1698 }, { name: \"Drift\", homepage: \"https://www.drift.com/\", category: \"marketing\", domains: [\"*.drift.com\", \"*.driftt.com\"], examples: [\"js.driftt.com\", \"api.drift.com\"], products: [{ name: \"Drift Live Chat\", urlPatterns: [\"REGEXP:js\\\\.driftt\\\\.com\\\\/include\\\\/.*\\\\/.*\\\\.js\"], facades: [{ name: \"React Live Chat Loader\", repo: \"https://github.com/calibreapp/react-live-chat-loader\" }] }], totalExecutionTime: 30179596, totalOccurrences: 5515 }, { name: \"Sentry\", homepage: \"https://sentry.io/\", category: \"utility\", domains: [\"*.getsentry.com\", \"*.ravenjs.com\", \"*.sentry-cdn.com\", \"*.sentry.io\"], examples: [\"cdn.ravenjs.com\", \"browser.sentry-cdn.com\"], totalExecutionTime: 47937360, totalOccurrences: 85598 }, { name: \"Amazon Web Services\", homepage: \"https://aws.amazon.com/s3/\", category: \"other\", domains: [\"*.amazon.com\", \"*.amazonaws.com\", \"*.amazonwebapps.c\\\nom\", \"*.amazonwebservices.com\", \"*.elasticbeanstalk.com\", \"*.images-amazon.com\", \"*.amazon.co.uk\"], examples: [\"s3.amazonaws.com\", \"us-east-1.amazonaws.com\", \"api-cdn.amazon.com\", \"ecx.images-amazon.com\", \"ws.amazon.co.uk\"], totalExecutionTime: 51892201, totalOccurrences: 119152 }, { name: \"Amazon Pay\", homepage: \"https://pay.amazon.com\", category: \"utility\", domains: [\"payments.amazon.com\", \"*.payments-amazon.com\"], totalExecutionTime: 1234650, totalOccurrences: 6833 }, { name: \"Media.net\", homepage: \"https://www.media.net/\", category: \"ad\", domains: [\"*.media.net\", \"*.mnet-ad.net\"], examples: [\"contextual.media.net\", \"cdnwest-xch.media.net\", \"hbx.media.net\", \"cs.media.net\", \"hblg.media.net\"], totalExecutionTime: 24973689, totalOccurrences: 97679 }, { name: \"Yahoo!\", homepage: \"https://www.yahoo.com/\", category: \"ad\", domains: [\"*.bluelithium.com\", \"*.hostingprod.com\", \"*.lexity.com\", \"*.yahoo.com\", \"*.yahooapis.com\", \"*.yimg.com\", \"*.zenfs.com\", \"*.yahoo.net\"], examples: [\"ads.yahoo.\\\ncom\", \"analytics.yahoo.com\", \"geo.yahoo.com\", \"udc.yahoo.com\", \"ganon.yahoo.com\", \"ads.yap.yahoo.com\"], totalExecutionTime: 2617276, totalOccurrences: 24800 }, { name: \"Adroll\", homepage: \"https://www.adroll.com/\", category: \"ad\", domains: [\"*.adroll.com\"], examples: [\"d.adroll.com\", \"s.adroll.com\"], totalExecutionTime: 11884188, totalOccurrences: 30782 }, { name: \"Twitch\", homepage: \"https://twitch.tv/\", category: \"video\", domains: [\"*.twitch.tv\"], examples: [\"player.twitch.tv\"], totalExecutionTime: 18452667, totalOccurrences: 1255 }, { name: \"Taboola\", homepage: \"https://www.taboola.com/\", category: \"ad\", domains: [\"*.taboola.com\", \"*.taboolasyndication.com\"], examples: [\"cdn.taboola.com\", \"trc.taboola.com\", \"vidstat.taboola.com\", \"images.taboola.com\"], totalExecutionTime: 32631891, totalOccurrences: 49191 }, { name: \"Sizmek\", homepage: \"https://www.sizmek.com/\", category: \"ad\", domains: [\"*.serving-sys.com\", \"*.peer39.net\"], examples: [\"secure-ds.serving-sys.com\", \"ds.serving-sys.co\\\nm\", \"bs.serving-sys.com\"], totalExecutionTime: 6679849, totalOccurrences: 4307 }, { name: \"Scorecard Research\", homepage: \"https://www.scorecardresearch.com/\", category: \"ad\", domains: [\"*.scorecardresearch.com\"], examples: [\"sb.scorecardresearch.com\", \"sa.scorecardresearch.com\", \"b.scorecardresearch.com\"], totalExecutionTime: 4399371, totalOccurrences: 54577 }, { name: \"Criteo\", homepage: \"https://www.criteo.com/\", category: \"ad\", domains: [\"*.criteo.com\", \"*.emailretargeting.com\", \"*.criteo.net\"], examples: [\"static.criteo.net\", \"bidder.criteo.com\", \"dis.criteo.com\", \"gum.criteo.com\", \"sslwidget.criteo.com\", \"dis.us.criteo.com\"], totalExecutionTime: 25625451, totalOccurrences: 213880 }, { name: \"Segment\", homepage: \"https://segment.com/\", category: \"analytics\", domains: [\"*.segment.com\", \"*.segment.io\"], examples: [\"cdn.segment.com\", \"api.segment.io\"], totalExecutionTime: 11055141, totalOccurrences: 27036 }, { name: \"ShareThis\", homepage: \"https://www.sharethis.com/\", category: \"soci\\\nal\", domains: [\"*.sharethis.com\"], examples: [\"w.sharethis.com\", \"ws.sharethis.com\", \"t.sharethis.com\"], totalExecutionTime: 30807804, totalOccurrences: 88829 }, { name: \"Distil Networks\", homepage: \"https://www.distilnetworks.com/\", category: \"utility\", domains: [\"*.areyouahuman.com\"], examples: [\"n-cdn.areyouahuman.com\"] }, { name: \"Connexity\", homepage: \"https://connexity.com/\", category: \"analytics\", domains: [\"*.connexity.net\"] }, { name: \"Popads\", homepage: \"https://www.popads.net/\", category: \"ad\", domains: [\"*.popads.net\"], examples: [\"serve.popads.net\", \"c1.popads.net\"], totalExecutionTime: 756593, totalOccurrences: 427 }, { name: \"CreateJS CDN\", homepage: \"https://code.createjs.com/\", category: \"cdn\", domains: [\"*.createjs.com\"], examples: [\"code.createjs.com\"], totalExecutionTime: 13654049, totalOccurrences: 3880 }, { name: \"Squarespace\", homepage: \"https://www.squarespace.com/\", category: \"hosting\", domains: [\"*.squarespace.com\"], examples: [\"static.squarespace.com\", \"stati\\\nc1.squarespace.com\"], totalExecutionTime: 1106480464, totalOccurrences: 243154 }, { name: \"Media Math\", homepage: \"https://www.mediamath.com/\", category: \"ad\", domains: [\"*.mathads.com\", \"*.mathtag.com\"], examples: [\"mathid.mathtag.com\", \"sync.mathtag.com\", \"pixel.mathtag.com\"], totalExecutionTime: 20783, totalOccurrences: 305 }, { name: \"Mixpanel\", homepage: \"https://mixpanel.com/\", category: \"analytics\", domains: [\"*.mixpanel.com\", \"*.mxpnl.com\"], examples: [\"cdn.mxpnl.com\"], totalExecutionTime: 3250547, totalOccurrences: 18817 }, { name: \"FontAwesome CDN\", homepage: \"https://fontawesome.com/\", category: \"cdn\", domains: [\"*.fontawesome.com\"], examples: [\"use.fontawesome.com\"], totalExecutionTime: 73007333, totalOccurrences: 291586 }, { name: \"Hubspot\", homepage: \"https://hubspot.com/\", category: \"marketing\", domains: [\"*.hs-scripts.com\", \"*.hubspot.com\", \"*.leadin.com\", \"*.hs-analytics.net\", \"*.hscollectedforms.net\", \"*.hscta.net\", \"*.hsforms.net\", \"*.hsleadflows.net\", \"*.hsstatic.ne\\\nt\", \"*.hubspot.net\", \"*.hsforms.com\", \"*.hs-banner.com\", \"*.hs-embed-reporting.com\", \"*.hs-growth-metrics.com\", \"*.hs-data.com\", \"*.hsadspixel.net\", \"*.hubapi.com\"], examples: [\"forms.hubspot.com\", \"js.hsforms.net\", \"js.hs-analytics.net\", \"js.leadin.com\"], totalExecutionTime: 92224372, totalOccurrences: 154415 }, { name: \"Mailchimp\", homepage: \"https://mailchimp.com/\", category: \"marketing\", domains: [\"*.chimpstatic.com\", \"*.list-manage.com\", \"*.mailchimp.com\"], examples: [\"downloads.mailchimp.com\"], totalExecutionTime: 21592375, totalOccurrences: 45506 }, { name: \"MGID\", homepage: \"https://www.mgid.com/\", category: \"ad\", domains: [\"*.mgid.com\", \"*.dt07.net\"], examples: [\"servicer.mgid.com\"], totalExecutionTime: 22074076, totalOccurrences: 10437 }, { name: \"Stripe\", homepage: \"https://stripe.com\", category: \"utility\", domains: [\"*.stripe.com\", \"*.stripecdn.com\", \"*.stripe.network\"], examples: [\"m.stripe.network\", \"js.stripe.com\"], totalExecutionTime: 166354648, totalOccurrences: 136440 },\n    { name: \"PayPal\", homepage: \"https://paypal.com\", category: \"utility\", domains: [\"*.paypal.com\", \"*.paypalobjects.com\"], examples: [\"www.paypalobjects.com\"], totalExecutionTime: 64408205, totalOccurrences: 62800 }, { name: \"Market GID\", homepage: \"https://www.marketgid.com/\", category: \"ad\", domains: [\"*.marketgid.com\"], examples: [\"jsc.marketgid.com\"] }, { name: \"Pinterest\", homepage: \"https://pinterest.com/\", category: \"social\", domains: [\"*.pinimg.com\", \"*.pinterest.com\"], examples: [\"assets.pinterest.com\", \"ct.pinterest.com\", \"log.pinterest.com\"], totalExecutionTime: 17602311, totalOccurrences: 131448 }, { name: \"New Relic\", homepage: \"https://newrelic.com/\", category: \"utility\", domains: [\"*.newrelic.com\", \"*.nr-data.net\"], examples: [\"js-agent.newrelic.com\", \"bam.nr-data.net\"], totalExecutionTime: 64592740, totalOccurrences: 227672 }, { name: \"AppDynamics\", homepage: \"https://www.appdynamics.com/\", category: \"utility\", domains: [\"*.appdynamics.com\", \"*.eum-appdynamics.com\", \"\\\nd3tjaysgumg9lf.cloudfront.net\"], examples: [\"cdn.appdynamics.com\"], totalExecutionTime: 2509158, totalOccurrences: 2920 }, { name: \"Parking Crew\", homepage: \"https://parkingcrew.net/\", category: \"other\", domains: [\"d1lxhc4jvstzrp.cloudfront.net\", \"*.parkingcrew.net\"], totalExecutionTime: 9, totalOccurrences: 1 }, { name: \"WordAds\", company: \"Automattic\", homepage: \"https://wordads.co/\", category: \"ad\", domains: [\"*.pubmine.com\"], examples: [\"s.pubmine.com\"], totalExecutionTime: 74286347, totalOccurrences: 100449 }, { name: \"AppNexus\", homepage: \"https://www.appnexus.com/\", category: \"ad\", domains: [\"*.adnxs.com\", \"*.ctasnet.com\", \"*.adrdgt.com\"], examples: [\"acdn.adnxs.com\", \"secure.adnxs.com\", \"ib.adnxs.com\", \"sharethrough.adnxs.com\", \"cdn.adnxs.com\", \"vcdn.adnxs.com\"], totalExecutionTime: 5948505, totalOccurrences: 234133 }, { name: \"Histats\", homepage: \"https://www.histats.com/\", category: \"analytics\", domains: [\"*.histats.com\"], examples: [\"s10.histats.com\"], totalExecutionTime: 5601,\n    totalOccurrences: 92 }, { name: \"DoubleVerify\", homepage: \"https://www.doubleverify.com/\", category: \"ad\", domains: [\"*.doubleverify.com\", \"*.dvtps.com\", \"*.iqfp1.com\"], examples: [\"cdn.doubleverify.com\", \"cdn3.doubleverify.com\", \"tps.doubleverify.com\", \"tps712.doubleverify.com\", \"tps714.doubleverify.com\", \"tps706.doubleverify.com\", \"tps700.doubleverify.com\", \"tps707.doubleverify.com\", \"rtb2.doubleverify.com\", \"rtb0.doubleverify.com\", \"rtbcdn.doubleverify.com\", \"tps11020.doubleverify.com\", \"tm.iqfp1.com\"], totalExecutionTime: 46891028, totalOccurrences: 19453 }, { name: \"Mediavine\", homepage: \"https://www.mediavine.com/\", category: \"ad\", domains: [\"*.mediavine.com\"], examples: [\"scripts.mediavine.com\", \"video.mediavine.com\"], totalExecutionTime: 59009373, totalOccurrences: 12963 }, { name: \"Wix\", homepage: \"https://www.wix.com/\", category: \"hosting\", domains: [\"*.parastorage.com\", \"*.wix.com\", \"*.wixstatic.com\", \"*.wixapps.net\"], examples: [\"static.parastorage.com\", \"static.wixstat\\\nic.com\", \"www.wix.com\", \"instagram.codev.wixapps.net\"], totalExecutionTime: 2112268981, totalOccurrences: 458273 }, { name: \"Webflow\", homepage: \"https://webflow.com/\", category: \"hosting\", domains: [\"*.uploads-ssl.webflow.com\", \"*.assets-global.website-files.com\", \"*.assets.website-files.com\"], examples: [\"uploads-ssl.webflow.com\", \"assets-global.website-files.com\", \"assets.website-files.com\"] }, { name: \"Weebly\", homepage: \"https://www.weebly.com/\", category: \"hosting\", domains: [\"*.editmysite.com\"], totalExecutionTime: 413019e3, totalOccurrences: 67864 }, { name: \"LinkedIn\", homepage: \"https://www.linkedin.com/\", category: \"social\", domains: [\"*.bizographics.com\", \"platform.linkedin.com\", \"*.slideshare.com\", \"*.slidesharecdn.com\", \"*.oribi.io\"], totalExecutionTime: 5776577, totalOccurrences: 16507 }, { name: \"LinkedIn Ads\", category: \"ad\", domains: [\"*.licdn.com\", \"*.ads.linkedin.com\", \"ads.linkedin.com\", \"www.linkedin.com\"], examples: [\"snap.licdn.com\"], totalExecutionTime: 22805542,\n    totalOccurrences: 199088 }, { name: \"Vox Media\", homepage: \"https://www.voxmedia.com/\", category: \"content\", domains: [\"*.vox-cdn.com\", \"*.voxmedia.com\"], examples: [\"cdn.vox-cdn.com\"], totalExecutionTime: 910366, totalOccurrences: 320 }, { name: \"Hotmart\", homepage: \"https://www.hotmart.com/\", category: \"content\", domains: [\"*.hotmart.com\"], examples: [\"launchermodule.hotmart.com\"], totalExecutionTime: 15363016, totalOccurrences: 4554 }, { name: \"SoundCloud\", homepage: \"https://www.soundcloud.com/\", category: \"content\", domains: [\"*.sndcdn.com\", \"*.soundcloud.com\", \"*.stratus.sc\"], examples: [\"widget.sndcdn.com\"], totalExecutionTime: 15888610, totalOccurrences: 5859 }, { name: \"Spotify\", homepage: \"https://www.spotify.com/\", category: \"content\", domains: [\"*.scdn.co\", \"*.spotify.com\"], examples: [\"open.spotify.com\", \"open.scdn.co\", \"i.scdn.co\"], totalExecutionTime: 99924, totalOccurrences: 10992 }, { name: \"AMP\", homepage: \"https://amp.dev/\", category: \"content\", domains: [\"*.ampp\\\nroject.org\"], examples: [\"cdn.ampproject.org\"], totalExecutionTime: 79590738, totalOccurrences: 66265 }, { name: \"Beeketing\", homepage: \"https://beeketing.com/\", category: \"marketing\", domains: [\"*.beeketing.com\"], examples: [\"sdk-cdn.beeketing.com\", \"sdk.beeketing.com\"], totalExecutionTime: 2163106, totalOccurrences: 1971 }, { name: \"Albacross\", homepage: \"https://albacross.com/\", category: \"marketing\", domains: [\"*.albacross.com\"], examples: [\"serve.albacross.com\"], totalExecutionTime: 100459, totalOccurrences: 1503 }, { name: \"TrafficJunky\", homepage: \"https://www.trafficjunky.com/\", category: \"ad\", domains: [\"*.contentabc.com\", \"*.trafficjunky.net\"], examples: [\"ads2.contentabc.com\", \"hw-cdn.contentabc.com\", \"media.trafficjunky.net\", \"ads.trafficjunky.net\", \"hw-cdn.trafficjunky.net\"], totalExecutionTime: 2936, totalOccurrences: 62 }, { name: \"Bootstrap CDN\", homepage: \"https://www.bootstrapcdn.com/\", category: \"cdn\", domains: [\"*.bootstrapcdn.com\"], examples: [\"maxcdn.bootstrapcdn.\\\ncom\", \"stackpath.bootstrapcdn.com\"], totalExecutionTime: 2075388, totalOccurrences: 38731 }, { name: \"Shareaholic\", homepage: \"https://www.shareaholic.com/\", category: \"social\", domains: [\"*.shareaholic.com\", \"dsms0mj1bbhn4.cloudfront.net\"], totalExecutionTime: 122180, totalOccurrences: 1429 }, { name: \"Snowplow\", homepage: \"https://snowplowanalytics.com/\", category: \"analytics\", domains: [\"d32hwlnfiv2gyn.cloudfront.net\"], totalExecutionTime: 7099041, totalOccurrences: 58566 }, { name: \"RD Station\", homepage: \"https://www.rdstation.com/en/\", category: \"marketing\", domains: [\"d335luupugsy2.cloudfront.net\"], totalExecutionTime: 7693701, totalOccurrences: 21846 }, { name: \"Jivochat\", homepage: \"https://www.jivochat.com/\", category: \"customer-success\", domains: [\"*.jivosite.com\"], examples: [\"cdn-ca.jivosite.com\", \"code.jivosite.com\"], totalExecutionTime: 36663932, totalOccurrences: 57540 }, { name: \"Listrak\", homepage: \"https://www.listrak.com/\", category: \"marketing\", domains: [\"*.listra\\\nk.com\", \"*.listrakbi.com\"], examples: [\"cdn.listrakbi.com\", \"s1.listrakbi.com\"], totalExecutionTime: 458776, totalOccurrences: 1045 }, { name: \"Ontame\", homepage: \"https://www.ontame.io\", category: \"analytics\", domains: [\"*.ontame.io\"], examples: [\"cdn.ontame.io\", \"collector.ontame.io\"], totalExecutionTime: 23620, totalOccurrences: 101 }, { name: \"Ipify\", homepage: \"https://www.ipify.org\", category: \"utility\", domains: [\"*.ipify.org\"], examples: [\"api.ipify.org\", \"geo.ipify.org\"], totalExecutionTime: 365905, totalOccurrences: 2753 }, { name: \"Ensighten\", homepage: \"https://www.ensighten.com/\", category: \"tag-manager\", domains: [\"*.ensighten.com\"], examples: [\"nexus.ensighten.com\"], totalExecutionTime: 1774287, totalOccurrences: 3199 }, { name: \"EpiServer\", homepage: \"https://www.episerver.com\", category: \"content\", domains: [\"*.episerver.net\"], examples: [\"dl.episerver.net\"], totalExecutionTime: 9010, totalOccurrences: 80 }, { name: \"mPulse\", homepage: \"https://developer.akamai.com/aka\\\nmai-mpulse\", category: \"analytics\", domains: [\"*.akstat.io\", \"*.go-mpulse.net\", \"*.mpulse.net\", \"*.mpstat.us\"], examples: [\"c.go-mpulse.net\", \"0211c83c.akstat.io\"], totalExecutionTime: 3089821, totalOccurrences: 30624 }, { name: \"Pingdom RUM\", homepage: \"https://www.pingdom.com/product/performance-monitoring/\", category: \"analytics\", domains: [\"*.pingdom.net\"], examples: [\"rum-static.pingdom.net\", \"rum-collector-2.pingdom.net\"], totalExecutionTime: 106679, totalOccurrences: 1825 }, { name: \"SpeedCurve RUM\", company: \"SpeedCurve\", homepage: \"https://www.speedcurve.com/features/performance-monitoring/\", category: \"analytics\", domains: [\"*.speedcurve.com\"], examples: [\"cdn.speedcurve.com\", \"lux.speedcurve.com\"], totalExecutionTime: 323903, totalOccurrences: 5358 }, { name: \"Radar\", company: \"Cedexis\", homepage: \"https://www.cedexis.com/radar/\", category: \"analytics\", domains: [\"*.cedexis-test.com\", \"*.cedexis.com\", \"*.cmdolb.com\", \"cedexis.leasewebcdn.com\", \"*.cedexis-radar.net\", \"*.cedex\\\nis.net\", \"cedexis-test01.insnw.net\", \"cedexisakamaitest.azureedge.net\", \"cedexispub.cdnetworks.net\", \"cs600.wac.alphacdn.net\", \"cs600.wpc.edgecastdns.net\", \"global2.cmdolb.com\", \"img-cedexis.mncdn.com\", \"a-cedexis.msedge.net\", \"zn3vgszfh.fastestcdn.net\"], examples: [\"radar.cedexis.com\", \"rpt.cedexis.com\", \"2-01-49cd-0002.cdx.cedexis.net\", \"bench.cedexis-test.com\"], totalExecutionTime: 290925, totalOccurrences: 1133 }, { name: \"Byside\", homepage: \"https://byside.com\", category: \"analytics\", domains: [\"*.byside.com\"], examples: [\"byce2.byside.com\", \"wce2.byside.com\"], totalExecutionTime: 45270, totalOccurrences: 87 }, { name: \"VWO\", homepage: \"https://vwo.com\", category: \"analytics\", domains: [\"*.vwo.com\", \"*.visualwebsiteoptimizer.com\", \"d5phz18u4wuww.cloudfront.net\", \"*.wingify.com\"], examples: [\"dev.visualwebsiteoptimizer.com\"], totalExecutionTime: 6485310, totalOccurrences: 7903 }, { name: \"Bing Ads\", homepage: \"https://bingads.microsoft.com\", category: \"ad\", domains: [\"*.bing.com\", \"\\\n*.microsoft.com\", \"*.msn.com\", \"*.s-msft.com\", \"*.s-msn.com\", \"*.msads.net\", \"*.msecnd.net\"], examples: [\"bat.bing.com\", \"c.bing.com\", \"bat.r.msn.com\", \"ajax.microsoft.com\"], totalExecutionTime: 14227177, totalOccurrences: 117720 }, { name: \"GoSquared\", homepage: \"https://www.gosquared.com\", category: \"analytics\", domains: [\"*.gosquared.com\", \"d1l6p2sc9645hc.cloudfront.net\"], examples: [\"data.gosquared.com\", \"data2.gosquared.com\"], totalExecutionTime: 56152, totalOccurrences: 613 }, { name: \"Usabilla\", homepage: \"https://usabilla.com\", category: \"analytics\", domains: [\"*.usabilla.com\", \"d6tizftlrpuof.cloudfront.net\"], examples: [\"w.usabilla.com\"], totalExecutionTime: 240166, totalOccurrences: 1354 }, { name: \"Fastly Insights\", homepage: \"https://insights.fastlylabs.com\", category: \"analytics\", domains: [\"*.fastly-insights.com\"], examples: [\"www.fastly-insights.com\"], totalExecutionTime: 541189, totalOccurrences: 4449 }, { name: \"Visual IQ\", homepage: \"https://www.visualiq.com\", category: \"\\\nanalytics\", domains: [\"*.myvisualiq.net\"], examples: [\"t.myvisualiq.net\"] }, { name: \"Snapchat\", homepage: \"https://www.snapchat.com\", category: \"analytics\", domains: [\"*.snapchat.com\", \"*.sc-static.net\"], examples: [\"tr.snapchat.com\"], totalExecutionTime: 177890, totalOccurrences: 1978 }, { name: \"Atlas Solutions\", homepage: \"https://atlassolutions.com\", category: \"analytics\", domains: [\"*.atdmt.com\"], examples: [\"ad.atdmt.com\", \"cx.atdmt.com\"] }, { name: \"Quantcast\", homepage: \"https://www.quantcast.com\", category: \"analytics\", domains: [\"*.brtstats.com\", \"*.quantcount.com\", \"*.quantserve.com\", \"*.semantictec.com\", \"*.ntv.io\"], examples: [\"pixel.quantserve.com\", \"secure.quantserve.com\", \"cms.quantserve.com\", \"rules.quantcount.com\"], totalExecutionTime: 12419392, totalOccurrences: 77646 }, { name: \"Spiceworks\", homepage: \"https://www.spiceworks.com\", category: \"analytics\", domains: [\"*.spiceworks.com\"], examples: [\"px.spiceworks.com\"] }, { name: \"Marketo\", homepage: \"https://www.marke\\\nto.com\", category: \"analytics\", domains: [\"*.marketo.com\", \"*.mktoresp.com\", \"*.marketo.net\"], examples: [\"munchkin.marketo.net\"], totalExecutionTime: 724464, totalOccurrences: 1798 }, { name: \"Intercom\", homepage: \"https://www.intercom.com\", category: \"customer-success\", domains: [\"*.intercomcdn.com\", \"*.intercom.io\"], examples: [\"js.intercomcdn.com\", \"api-iam.intercom.io\", \"widget.intercom.io\", \"nexus-websocket-a.intercom.io\"], products: [{ name: \"Intercom Widget\", urlPatterns: [\"widget.intercom.io\", \"js.intercomcdn.com/shim.latest.js\"], facades: [{ name: \"React Live Chat Loader\", repo: \"https://github.com/calibreapp/react-live-chat-loader\" }, { name: \"Intercom Facade\", repo: \"https://github.com/danielbachhuber/intercom-facade/\" }] }], totalExecutionTime: 44601345, totalOccurrences: 35197 }, { name: \"Unpkg\", homepage: \"https://unpkg.com\", category: \"cdn\", domains: [\"*.unpkg.com\", \"*.npmcdn.com\"], totalExecutionTime: 74666, totalOccurrences: 227 }, { name: \"ReadSpeaker\", homepage: \"ht\\\ntps://www.readspeaker.com\", category: \"other\", domains: [\"*.readspeaker.com\"], examples: [\"sf1-eu.readspeaker.com\"], totalExecutionTime: 727525, totalOccurrences: 6265 }, { name: \"Browsealoud\", homepage: \"https://www.texthelp.com/en-gb/products/browsealoud/\", category: \"other\", domains: [\"*.browsealoud.com\", \"*.texthelp.com\"], examples: [\"www.browsealoud.com\"], totalExecutionTime: 665425, totalOccurrences: 1951 }, { name: \"15gifts\", category: \"customer-success\", domains: [\"*.15gifts.com\", \"*.primefuse.com\"], examples: [\"www.primefuse.com\"] }, { name: \"1xRUN\", category: \"utility\", domains: [\"*.1xrun.com\"] }, { name: \"2AdPro Media Solutions\", category: \"ad\", domains: [\"*.2adpro.com\"] }, { name: \"301 Digital Media\", category: \"content\", domains: [\"*.301ads.com\", \"*.301network.com\"] }, { name: \"360 picnic platform\", company: \"MediaV\", category: \"ad\", domains: [\"*.mediav.com\"], totalExecutionTime: 4893, totalOccurrences: 78 }, { name: \"365 Media Group\", category: \"content\", domains: [\"*.365\\\ndm.com\"] }, { name: \"365 Tech Services\", category: \"hosting\", domains: [\"*.365webservices.co.uk\"] }, { name: \"3D Issue\", category: \"utility\", domains: [\"*.3dissue.com\", \"*.pressjack.com\"], totalExecutionTime: 53823, totalOccurrences: 30 }, { name: \"47Line Technologies\", category: \"other\", domains: [\"*.pejs.net\"] }, { name: \"4finance\", category: \"utility\", domains: [\"*.4finance.com\"] }, { name: \"5miles\", category: \"content\", domains: [\"*.5milesapp.com\"] }, { name: \"77Tool\", company: \"77Agency\", category: \"analytics\", domains: [\"*.77tracking.com\"] }, { name: \"9xb\", category: \"ad\", domains: [\"*.9xb.com\"] }, { name: \"@UK\", category: \"hosting\", domains: [\"*.uk-plc.net\"] }, { name: \"A Perfect Pocket\", category: \"hosting\", domains: [\"*.aperfectpocketdata.com\"] }, { name: \"A-FIS PTE\", category: \"analytics\", domains: [\"*.websta.me\"] }, { name: \"AB Tasty\", homepage: \"https://www.abtasty.com/\", category: \"analytics\", domains: [\"*.abtasty.com\", \"d1447tq2m68ekg.cloudfront.net\"], examples: [\"try.abt\\\nasty.com\"], totalExecutionTime: 1720461, totalOccurrences: 3363 }, { name: \"ABA RESEARCH\", category: \"analytics\", domains: [\"*.abaresearch.uk\", \"qmodal.azurewebsites.net\"] }, { name: \"ADMIZED\", category: \"ad\", domains: [\"*.admized.com\"] }, { name: \"ADNOLOGIES\", category: \"ad\", domains: [\"*.heias.com\"] }, { name: \"ADventori\", category: \"ad\", domains: [\"*.adventori.com\"], totalExecutionTime: 5790, totalOccurrences: 21 }, { name: \"AI Media Group\", category: \"ad\", domains: [\"*.aimediagroup.com\"] }, { name: \"AIR.TV\", category: \"ad\", domains: [\"*.air.tv\"] }, { name: \"AKQA\", category: \"ad\", domains: [\"*.srtk.net\"] }, { name: \"AOL ad\", company: \"AOL\", category: \"ad\", domains: [\"*.atwola.com\"] }, { name: \"AOL On\", company: \"AOL\", category: \"content\", domains: [\"*.5min.com\"] }, { name: \"AOL Sponsored Listiings\", company: \"AOL\", category: \"ad\", domains: [\"*.adsonar.com\"] }, { name: \"APSIS Lead\", company: \"APSIS International AB\", category: \"ad\", domains: [\"*.prospecteye.com\"] }, { name: \"APSIS Pr\\\nofile Cloud\", company: \"APSIS\", category: \"analytics\", domains: [\"*.innomdc.com\"] }, { name: \"APSIS Forms\", company: \"APSIS\", category: \"other\", domains: [\"*.apsisforms.com\"], examples: [\"forms.apsisforms.com\"] }, { name: \"ARENA\", company: \"Altitude\", category: \"ad\", domains: [\"*.altitude-arena.com\"], totalExecutionTime: 1, totalOccurrences: 1 }, { name: \"ARM\", category: \"analytics\", domains: [\"*.tag4arm.com\"], totalExecutionTime: 5847, totalOccurrences: 83 }, { name: \"ASAPP\", category: \"other\", domains: [\"*.asapp.com\"], totalExecutionTime: 37052, totalOccurrences: 31 }, { name: \"ASP\", category: \"hosting\", domains: [\"*.goshowoff.com\"] }, { name: \"AT Internet\", category: \"analytics\", domains: [\"*.ati-host.net\"] }, { name: \"ATTRAQT\", category: \"utility\", domains: [\"*.attraqt.com\", \"*.locayta.com\"] }, { name: \"AVANSER\", category: \"analytics\", domains: [\"*.avanser.com.au\"] }, { name: \"AVG\", company: \"AVG Technologies\", category: \"utility\", domains: [\"*.avg.com\"], examples: [\"omni.avg.com\"] },\n    { name: \"AWeber\", category: \"ad\", domains: [\"*.aweber.com\"], totalExecutionTime: 40945, totalOccurrences: 280 }, { name: \"AXS\", category: \"content\", domains: [\"*.axs.com\"], totalExecutionTime: 49218, totalOccurrences: 8 }, { name: \"Accentuate\", company: \"Accentuate Digital\", category: \"utility\", homepage: \"https://www.accentuate.io/\", domains: [\"*.accentuate.io\"], examples: [\"cdn.accentuate.io\", \"original.accentuate.io\"], totalExecutionTime: 1772, totalOccurrences: 17 }, { name: \"Accenture\", category: \"analytics\", domains: [\"*.tmvtp.com\"] }, { name: \"Accord Holdings\", category: \"ad\", domains: [\"*.agcdn.com\"] }, { name: \"Accordant Media\", category: \"ad\", domains: [\"*.a3cloud.net\"], examples: [\"segment.a3cloud.net\"] }, { name: \"Account Kit\", category: \"other\", domains: [\"*.accountkit.com\"] }, { name: \"Accuen Media (Omnicom Media Group)\", category: \"content\", domains: [\"*.p-td.com\"] }, { name: \"Accuweather\", category: \"content\", domains: [\"*.accuweather.com\"], totalExecutionTime: 291762,\n    totalOccurrences: 1477 }, { name: \"Acquisio\", category: \"ad\", domains: [\"*.acq.io\"], totalExecutionTime: 1692, totalOccurrences: 32 }, { name: \"Act-On Software\", category: \"marketing\", domains: [\"*.actonsoftware.com\"], totalExecutionTime: 98, totalOccurrences: 2 }, { name: \"ActBlue\", category: \"other\", domains: [\"*.actblue.com\"], totalExecutionTime: 62800, totalOccurrences: 73 }, { name: \"Active Agent\", category: \"ad\", domains: [\"*.active-agent.com\"] }, { name: \"ActiveCampaign\", category: \"ad\", domains: [\"*.trackcmp.net\", \"app-us1.com\", \"*.app-us1.com\"], examples: [\"trackcmp.net\", \"prism.app-us1.com\", \"diffuser-cdn.app-us1.com\"], totalExecutionTime: 1605217, totalOccurrences: 19100 }, { name: \"AcuityAds\", category: \"ad\", domains: [\"*.acuityplatform.com\"], totalExecutionTime: 2492, totalOccurrences: 693 }, { name: \"Acxiom\", category: \"ad\", domains: [\"*.acxiom-online.com\", \"*.acxiomapac.com\", \"*.delivery.net\"] }, { name: \"Ad4Screen\", category: \"ad\", domains: [\"*.a4.tl\"] }, { name: \"A\\\nd6Media\", category: \"ad\", domains: [\"*.ad6media.fr\"], totalExecutionTime: 821770, totalOccurrences: 654 }, { name: \"AdCurve\", category: \"ad\", domains: [\"*.shop2market.com\"] }, { name: \"AdEasy\", category: \"ad\", domains: [\"*.adeasy.ru\"] }, { name: \"AdExtent\", category: \"ad\", domains: [\"*.adextent.com\"] }, { name: \"AdForge Edge\", company: \"AdForge\", category: \"ad\", domains: [\"*.adforgeinc.com\"] }, { name: \"AdGear\", company: \"Samsung Electronics\", category: \"ad\", domains: [\"*.adgear.com\", \"*.adgrx.com\"], totalExecutionTime: 19948, totalOccurrences: 42920 }, { name: \"AdInMedia\", category: \"ad\", domains: [\"*.fastapi.net\"] }, { name: \"AdJug\", category: \"ad\", domains: [\"*.adjug.com\"], examples: [\"tracking.adjug.com\", \"uk.view.adjug.com\"] }, { name: \"AdMatic\", category: \"ad\", domains: [\"*.admatic.com.tr\"], totalExecutionTime: 1274496, totalOccurrences: 467 }, { name: \"AdMedia\", category: \"ad\", domains: [\"*.admedia.com\"], examples: [\"pixel.admedia.com\"], totalExecutionTime: 2027, totalOccurrences: 7 },\n    { name: \"AdRecover\", category: \"ad\", domains: [\"*.adrecover.com\"], totalExecutionTime: 5117, totalOccurrences: 46 }, { name: \"AdRiver\", category: \"ad\", domains: [\"*.adriver.ru\"], totalExecutionTime: 1374767, totalOccurrences: 4740 }, { name: \"AdSniper\", category: \"ad\", domains: [\"*.adsniper.ru\", \"*.sniperlog.ru\"], totalExecutionTime: 2366, totalOccurrences: 22 }, { name: \"AdSpeed\", category: \"ad\", domains: [\"*.adspeed.net\"], totalExecutionTime: 4642, totalOccurrences: 16 }, { name: \"AdSpruce\", category: \"ad\", domains: [\"*.adspruce.com\"] }, { name: \"AdSupply\", category: \"ad\", domains: [\"*.doublepimp.com\"], totalExecutionTime: 1436, totalOccurrences: 13 }, { name: \"AdTheorent\", category: \"ad\", domains: [\"*.adentifi.com\"], totalExecutionTime: 108, totalOccurrences: 1 }, { name: \"AdThink AudienceInsights\", company: \"AdThink Media\", category: \"analytics\", domains: [\"*.audienceinsights.net\"] }, { name: \"AdTrue\", company: \"FPT AdTrue\", category: \"ad\", domains: [\"*.adtrue.com\"] }, { name: \"\\\nAdYapper\", category: \"ad\", domains: [\"*.adyapper.com\"] }, { name: \"Adacado\", category: \"ad\", domains: [\"*.adacado.com\"], totalExecutionTime: 1777, totalOccurrences: 18 }, { name: \"Adap.tv\", category: \"ad\", domains: [\"*.adap.tv\"] }, { name: \"Adapt Services\", category: \"hosting\", domains: [\"*.adcmps.com\"] }, { name: \"Adaptive Web\", category: \"hosting\", domains: [\"*.adaptive.co.uk\"] }, { name: \"Adara Media\", category: \"ad\", domains: [\"*.yieldoptimizer.com\"], totalExecutionTime: 1324, totalOccurrences: 23 }, { name: \"Adblade\", category: \"ad\", domains: [\"*.adblade.com\"], totalExecutionTime: 704, totalOccurrences: 7 }, { name: \"Adbrain\", category: \"ad\", domains: [\"*.adbrn.com\"] }, { name: \"AddEvent\", category: \"utility\", domains: [\"*.addevent.com\"], examples: [\"www.addevent.com\"], totalExecutionTime: 73230, totalOccurrences: 203 }, { name: \"AddShoppers\", category: \"social\", domains: [\"*.addshoppers.com\", \"d3rr3d0n31t48m.cloudfront.net\", \"*.shop.pe\"], totalExecutionTime: 31574, totalOccurrences: 451 },\n    { name: \"AddThisEvent\", category: \"hosting\", domains: [\"*.addthisevent.com\"] }, { name: \"Addoox MetaNetwork\", company: \"Addoox\", category: \"ad\", domains: [\"*.metanetwork.net\"] }, { name: \"Addvantage Media\", category: \"ad\", domains: [\"*.addvantagemedia.com\", \"*.simplytechnology.net\"] }, { name: \"AD EBis\", category: \"analytics\", homepage: \"https://www.ebis.ne.jp/\", domains: [\"*.ebis.ne.jp\"], examples: [\"taj1.ebis.ne.jp\"], totalExecutionTime: 55086, totalOccurrences: 608 }, { name: \"Adecs\", category: \"customer-success\", domains: [\"*.adecs.co.uk\"], examples: [\"www.adecs.co.uk\"] }, { name: \"Adelphic\", category: \"ad\", domains: [\"*.ipredictive.com\"], totalExecutionTime: 8196, totalOccurrences: 112 }, { name: \"Adestra\", category: \"ad\", domains: [\"*.adestra.com\", \"*.msgfocus.com\"] }, { name: \"Adform\", category: \"ad\", domains: [\"*.adform.net\", \"*.adformdsp.net\"], totalExecutionTime: 1798751, totalOccurrences: 140125 }, { name: \"Adkontekst\", category: \"ad\", domains: [\"*.adkontekst.pl\"] }, { name: \"\\\nAdlead\", category: \"ad\", domains: [\"*.webelapp.com\"] }, { name: \"Adledge\", category: \"utility\", domains: [\"*.adledge.com\"] }, { name: \"Adloox\", category: \"ad\", domains: [\"*.adlooxtracking.com\"], totalExecutionTime: 103507, totalOccurrences: 112 }, { name: \"Adlux\", category: \"ad\", domains: [\"*.adlux.com\"] }, { name: \"Admedo\", category: \"ad\", domains: [\"*.a8723.com\", \"*.adizio.com\", \"*.admedo.com\"], examples: [\"pool.a8723.com\"], totalExecutionTime: 9586, totalOccurrences: 695 }, { name: \"Admeta\", company: \"Wideorbit\", category: \"ad\", domains: [\"*.atemda.com\"] }, { name: \"Admetrics\", company: \"Next Tuesday\", category: \"analytics\", domains: [\"*.nt.vc\"], examples: [\"metrics.nt.vc\"] }, { name: \"Admiral\", category: \"ad\", domains: [\"*.unknowntray.com\"] }, { name: \"Admitad\", category: \"ad\", domains: [\"*.lenmit.com\"], totalExecutionTime: 2335, totalOccurrences: 31 }, { name: \"Admixer for Publishers\", company: \"Admixer\", category: \"ad\", domains: [\"*.admixer.net\"], totalExecutionTime: 1542643, totalOccurrences: 878 },\n    { name: \"Adnium\", category: \"ad\", domains: [\"*.adnium.com\"] }, { name: \"Adnostic\", company: \"Dennis Publishing\", category: \"ad\", domains: [\"*.adnostic.co.uk\"] }, { name: \"Adobe Marketing Cloud\", company: \"Adobe Systems\", category: \"ad\", domains: [\"*.adobetag.com\"] }, { name: \"Adobe Scene7\", company: \"Adobe Systems\", category: \"content\", domains: [\"wwwimages.adobe.com\", \"*.scene7.com\", \"*.everestads.net\", \"*.everestjs.net\"], totalExecutionTime: 808424, totalOccurrences: 702 }, { name: \"Adobe Systems\", category: \"content\", domains: [\"adobe.com\", \"www.adobe.com\"], totalExecutionTime: 38836, totalOccurrences: 179 }, { name: \"Adobe Business Catalyst\", homepage: \"https://www.businesscatalyst.com/\", category: \"hosting\", domains: [\"*.businesscatalyst.com\"] }, { name: \"Adocean\", company: \"Gemius\", category: \"ad\", domains: [\"*.adocean.pl\"], totalExecutionTime: 1658274, totalOccurrences: 2151 }, { name: \"Adometry\", company: \"Google\", category: \"ad\", domains: [\"*.dmtry.com\"] }, { name: \"Adomik\",\n    category: \"analytics\", domains: [\"*.adomik.com\"] }, { name: \"Adotmob\", category: \"ad\", domains: [\"*.adotmob.com\"] }, { name: \"Adrian Quevedo\", category: \"hosting\", domains: [\"*.adrianquevedo.com\"] }, { name: \"Adroit Digital Solutions\", category: \"ad\", domains: [\"*.imiclk.com\", \"*.abmr.net\"] }, { name: \"AdsNative\", category: \"ad\", domains: [\"*.adsnative.com\"] }, { name: \"AdsWizz\", category: \"ad\", domains: [\"*.adswizz.com\"], totalExecutionTime: 479514, totalOccurrences: 1901 }, { name: \"Adscale\", category: \"ad\", domains: [\"*.adscale.de\"], totalExecutionTime: 106237, totalOccurrences: 960 }, { name: \"Adschoom\", company: \"JSWeb Production\", category: \"ad\", domains: [\"*.adschoom.com\"], totalExecutionTime: 491, totalOccurrences: 2 }, { name: \"Adscience\", category: \"ad\", domains: [\"*.adscience.nl\"] }, { name: \"Adsiduous\", category: \"ad\", domains: [\"*.adsiduous.com\"] }, { name: \"Adsty\", category: \"ad\", domains: [\"*.adx1.com\"], totalExecutionTime: 698, totalOccurrences: 5 }, { name: \"Adtech\\\n (AOL)\", category: \"ad\", domains: [\"*.adtechus.com\"], totalExecutionTime: 176, totalOccurrences: 2 }, { name: \"Adtegrity\", category: \"ad\", domains: [\"*.adtpix.com\"], totalExecutionTime: 1735, totalOccurrences: 20 }, { name: \"Adthink\", company: \"Adthink Media\", category: \"ad\", domains: [\"*.adxcore.com\", \"*.dcoengine.com\"], examples: [\"d.adxcore.com\"] }, { name: \"AdultWebmasterEmpire.Com\", category: \"ad\", domains: [\"*.awempire.com\"], totalExecutionTime: 65091, totalOccurrences: 38 }, { name: \"Adunity\", category: \"ad\", domains: [\"*.adunity.com\"] }, { name: \"Advance Magazine Group\", category: \"content\", domains: [\"*.condenastdigital.com\", \"*.condenet.com\", \"*.condenast.co.uk\"], totalExecutionTime: 2531, totalOccurrences: 8 }, { name: \"Adverline Board\", company: \"Adverline\", category: \"ad\", domains: [\"*.adverline.com\", \"*.adnext.fr\"] }, { name: \"AdvertServe\", category: \"ad\", domains: [\"*.advertserve.com\"], totalExecutionTime: 112685, totalOccurrences: 437 }, { name: \"Advolution\", category: \"\\\nutility\", domains: [\"*.advolution.de\"] }, { name: \"Adwise\", category: \"ad\", domains: [\"*.adwise.bg\"], totalExecutionTime: 144, totalOccurrences: 2 }, { name: \"Adyen\", category: \"utility\", domains: [\"*.adyen.com\"], totalExecutionTime: 6335144, totalOccurrences: 2363 }, { name: \"Adyoulike\", category: \"ad\", domains: [\"*.adyoulike.com\", \"*.omnitagjs.com\", \"*.adyoulike.net\"], totalExecutionTime: 147862, totalOccurrences: 53190 }, { name: \"Adzerk\", category: \"ad\", domains: [\"*.adzerk.net\"], totalExecutionTime: 35184, totalOccurrences: 117 }, { name: \"Adzip\", company: \"Adbox Digital\", category: \"ad\", domains: [\"*.adzip.co\"] }, { name: \"AerServ\", category: \"ad\", domains: [\"*.aerserv.com\"] }, { name: \"Affectv\", category: \"ad\", domains: [\"*.affectv.com\", \"*.affec.tv\"], totalExecutionTime: 1187, totalOccurrences: 12 }, { name: \"Affiliate Window\", company: \"Digital Window\", category: \"ad\", domains: [\"*.dwin1.com\"], totalExecutionTime: 561168, totalOccurrences: 5414 }, { name: \"Affiliatly\", category: \"\\\nad\", domains: [\"*.affiliatly.com\"], examples: [\"www.affiliatly.com\"], totalExecutionTime: 32020, totalOccurrences: 132 }, { name: \"Affino\", category: \"ad\", domains: [\"affino.com\"] }, { name: \"Affirm\", category: \"utility\", domains: [\"*.affirm.com\"], totalExecutionTime: 3997184, totalOccurrences: 6665 }, { name: \"Afterpay\", company: \"Block\", category: \"utility\", homepage: \"https://www.afterpay.com/\", domains: [\"*.afterpay.com\"], examples: [\"static-us.afterpay.com\"], totalExecutionTime: 1270109, totalOccurrences: 8269 }, { name: \"Agenda Media\", category: \"ad\", domains: [\"*.agendamedia.co.uk\"] }, { name: \"Aggregate Knowledge\", company: \"Neustar\", category: \"ad\", domains: [\"*.agkn.com\"], totalExecutionTime: 14828, totalOccurrences: 344 }, { name: \"AgilOne\", category: \"marketing\", domains: [\"*.agilone.com\"], totalExecutionTime: 4190, totalOccurrences: 53 }, { name: \"Agility\", category: \"hosting\", domains: [\"*.agilitycms.com\"], totalExecutionTime: 3079, totalOccurrences: 4 }, { name: \"Ahalogy\",\n    category: \"social\", domains: [\"*.ahalogy.com\"] }, { name: \"Aheadworks\", category: \"utility\", domains: [\"*.aheadworks.com\"] }, { name: \"AirPR\", category: \"analytics\", domains: [\"*.airpr.com\"], totalExecutionTime: 416, totalOccurrences: 5 }, { name: \"Aira\", category: \"ad\", domains: [\"*.aira.net\"], examples: [\"www.aira.net\"] }, { name: \"Airport Parking and Hotels\", category: \"content\", domains: [\"*.aph.com\"], totalExecutionTime: 277, totalOccurrences: 3 }, { name: \"Akanoo\", category: \"analytics\", domains: [\"*.akanoo.com\"] }, { name: \"Alchemy\", company: \"AndBeyond.Media\", category: \"ad\", domains: [\"*.andbeyond.media\"], totalExecutionTime: 456340, totalOccurrences: 164 }, { name: \"AlephD\", company: \"AOL\", category: \"ad\", domains: [\"*.alephd.com\"] }, { name: \"AliveChat\", company: \"AYU Technology Solutions\", category: \"customer-success\", domains: [\"*.websitealive.com\", \"*.websitealive7.com\"] }, { name: \"All Access\", category: \"other\", domains: [\"*.allaccess.com.ph\"] }, { name: \"Alliance f\\\nor Audited Media\", category: \"ad\", domains: [\"*.aamsitecertifier.com\"] }, { name: \"Allyde\", category: \"marketing\", domains: [\"*.mautic.com\"] }, { name: \"AlphaSSL\", category: \"utility\", domains: [\"*.alphassl.com\"], totalExecutionTime: 1146, totalOccurrences: 10 }, { name: \"Altitude\", category: \"ad\", domains: [\"*.altitudeplatform.com\"] }, { name: \"Altocloud\", category: \"analytics\", domains: [\"*.altocloud.com\"] }, { name: \"Amadeus\", category: \"content\", domains: [\"*.e-travel.com\"] }, { name: \"Amazon CloudFront\", company: \"Amazon\", category: \"utility\", domains: [\"cloudfront.net\"] }, { name: \"Ambassador\", category: \"ad\", domains: [\"*.getambassador.com\"], totalExecutionTime: 21042, totalOccurrences: 89 }, { name: \"Ambient\", company: \"Ericcson\", category: \"other\", domains: [\"*.adnetwork.vn\", \"*.ambientplatform.vn\"] }, { name: \"Amelia Communication\", category: \"hosting\", domains: [\"*.sara.media\"] }, { name: \"Amobee\", category: \"marketing\", domains: [\"*.amgdgt.com\", \"*.kontera.com\"] }, { name: \"\\\nAmplience\", category: \"marketing\", domains: [\"*.10cms.com\", \"*.amplience.com\", \"*.amplience.net\", \"*.bigcontent.io\", \"*.adis.ws\"], totalExecutionTime: 4093, totalOccurrences: 17 }, { name: \"Amplitude Mobile Analytics\", company: \"Amplitude\", category: \"analytics\", domains: [\"*.amplitude.com\", \"d24n15hnbwhuhn.cloudfront.net\"], totalExecutionTime: 8703641, totalOccurrences: 46524 }, { name: \"Anametrix\", company: \"Ensighten\", category: \"analytics\", domains: [\"*.anametrix.com\"] }, { name: \"Ancora Platform\", company: \"Ancora Media Solutions\", category: \"ad\", domains: [\"*.ancoraplatform.com\"] }, { name: \"Anedot\", category: \"other\", domains: [\"*.anedot.com\"], totalExecutionTime: 84655, totalOccurrences: 21 }, { name: \"AnimateJS\", category: \"utility\", domains: [\"*.animatedjs.com\"] }, { name: \"AnswerDash\", category: \"customer-success\", domains: [\"*.answerdash.com\"], examples: [\"p1.answerdash.com\"] }, { name: \"Answers\", category: \"analytics\", domains: [\"*.answcdn.com\", \"*.answers.com\", \"*.dsply.c\\\nom\"] }, { name: \"Apester\", category: \"analytics\", domains: [\"*.apester.com\", \"*.qmerce.com\"], totalExecutionTime: 25294, totalOccurrences: 166 }, { name: \"Apligraf SmartWeb\", company: \"Apligraf\", category: \"utility\", domains: [\"*.apligraf.com.br\"] }, { name: \"Appier\", category: \"ad\", domains: [\"*.appier.net\"], totalExecutionTime: 124524, totalOccurrences: 826 }, { name: \"Appsolute\", category: \"utility\", homepage: \"https://appsolute.us/\", domains: [\"dropahint.love\"], examples: [\"dropahint.love\"], totalExecutionTime: 16362, totalOccurrences: 144 }, { name: \"Apptus eSales\", company: \"Apptus\", category: \"analytics\", domains: [\"*.apptus.com\"] }, { name: \"Arbor\", company: \"LiveRamp\", category: \"other\", domains: [\"*.pippio.com\"] }, { name: \"Ardent Creative\", category: \"hosting\", domains: [\"*.ardentcreative.co.uk\"] }, { name: \"Arnold Clark Automobiles\", category: \"content\", domains: [\"*.arnoldclark.com\"] }, { name: \"Atom Content Marketing\", category: \"content\", domains: [\"*.atomvault.net\"], examples: [\n    \"danu.atomvault.net\"] }, { name: \"Atom Data\", category: \"other\", domains: [\"*.atomdata.io\"] }, { name: \"Attribution\", category: \"ad\", domains: [\"*.attributionapp.com\"], totalExecutionTime: 44124, totalOccurrences: 124 }, { name: \"Audience 360\", company: \"Datapoint Media\", category: \"ad\", domains: [\"*.dpmsrv.com\"], totalExecutionTime: 578723, totalOccurrences: 371 }, { name: \"Audience Science\", category: \"ad\", domains: [\"*.revsci.net\"] }, { name: \"AudienceSearch\", company: \"Intimate Merger\", category: \"ad\", domains: [\"*.im-apps.net\"], totalExecutionTime: 9114981, totalOccurrences: 46726 }, { name: \"Auditorius\", category: \"ad\", domains: [\"*.audtd.com\"] }, { name: \"Augur\", category: \"analytics\", domains: [\"*.augur.io\"] }, { name: \"Auto Link Maker\", company: \"Apple\", category: \"ad\", domains: [\"*.apple.com\"], examples: [\"autolinkmaker.itunes.apple.com\"], totalExecutionTime: 657122, totalOccurrences: 2479 }, { name: \"Autopilot\", category: \"ad\", domains: [\"*.autopilothq.com\"], totalExecutionTime: 15490,\n    totalOccurrences: 74 }, { name: \"Avail\", company: \"RichRelevance\", category: \"ad\", domains: [\"*.avail.net\"] }, { name: \"AvantLink\", category: \"ad\", domains: [\"*.avmws.com\"], totalExecutionTime: 417, totalOccurrences: 8 }, { name: \"Avco Systems\", category: \"utility\", domains: [\"*.avcosystems.com\"] }, { name: \"Avid Media\", category: \"customer-success\", domains: [\"*.adspdbl.com\", \"*.metadsp.co.uk\"], totalExecutionTime: 58, totalOccurrences: 1 }, { name: \"Avocet Systems\", category: \"ad\", domains: [\"*.avocet.io\", \"ads.avct.cloud\"] }, { name: \"Avora\", category: \"analytics\", domains: [\"*.truedash.com\"], examples: [\"truetag.truedash.com\"] }, { name: \"Azure Traffic Manager\", company: \"Microsoft\", category: \"other\", domains: [\"*.gateway.net\", \"*.trafficmanager.net\"], examples: [\"analytics.gateway.net\"], totalExecutionTime: 51660, totalOccurrences: 148 }, { name: \"Azure Web Services\", company: \"Microsoft\", category: \"cdn\", domains: [\"*.azurewebsites.net\", \"*.azureedge.net\", \"*.msedge.net\", \"*\\\n.windows.net\"], totalExecutionTime: 35665078, totalOccurrences: 51378 }, { name: \"BAM\", category: \"analytics\", domains: [\"*.bam-x.com\"] }, { name: \"Baifendian Technology\", category: \"marketing\", domains: [\"*.baifendian.com\"] }, { name: \"Bankrate\", category: \"utility\", domains: [\"*.bankrate.com\"] }, { name: \"BannerFlow\", company: \"Nordic Factory Solutions\", category: \"ad\", domains: [\"*.bannerflow.com\"], totalExecutionTime: 50455, totalOccurrences: 42 }, { name: \"Barclaycard SmartPay\", company: \"Barclaycard\", category: \"utility\", domains: [\"*.barclaycardsmartpay.com\"] }, { name: \"Barilliance\", category: \"analytics\", domains: [\"*.barilliance.net\", \"dn3y71tq7jf07.cloudfront.net\"], totalExecutionTime: 7250, totalOccurrences: 26 }, { name: \"Barnebys\", category: \"other\", domains: [\"*.barnebys.com\"], totalExecutionTime: 59682, totalOccurrences: 57 }, { name: \"Basis\", company: \"Basis Technologies\", category: \"ad\", homepage: \"https://basis.net/\", domains: [\"*.basis.net\"], examples: [\"cdn01.basis\\\n.net\"], totalExecutionTime: 215661, totalOccurrences: 2623 }, { name: \"Batch Media\", category: \"ad\", domains: [\"*.t4ft.de\"] }, { name: \"Bauer Consumer Media\", category: \"content\", domains: [\"*.bauercdn.com\", \"*.greatmagazines.co.uk\"], examples: [\"www.greatmagazines.co.uk\"] }, { name: \"Baynote\", category: \"analytics\", domains: [\"*.baynote.net\"] }, { name: \"Bazaarvoice\", category: \"analytics\", domains: [\"*.bazaarvoice.com\", \"*.feedmagnet.com\"], totalExecutionTime: 1664795, totalOccurrences: 3375 }, { name: \"Beachfront Media\", category: \"ad\", domains: [\"*.bfmio.com\"], totalExecutionTime: 7782, totalOccurrences: 771 }, { name: \"BeamPulse\", category: \"analytics\", domains: [\"*.beampulse.com\"] }, { name: \"Beeswax\", category: \"ad\", domains: [\"*.bidr.io\"], totalExecutionTime: 5298, totalOccurrences: 12735 }, { name: \"Beetailer\", category: \"social\", domains: [\"*.beetailer.com\"], examples: [\"www.beetailer.com\"] }, { name: \"Best Of Media S.A.\", category: \"content\", domains: [\"*.servebom.com\"], totalExecutionTime: 29,\n    totalOccurrences: 67 }, { name: \"Bet365\", category: \"ad\", domains: [\"*.bet365affiliates.com\"] }, { name: \"Betfair\", category: \"other\", domains: [\"*.cdnbf.net\"] }, { name: \"Betgenius\", company: \"Genius Sports\", category: \"content\", domains: [\"*.connextra.com\"], totalExecutionTime: 84739, totalOccurrences: 287 }, { name: \"Better Banners\", category: \"ad\", domains: [\"*.betterbannerscloud.com\"] }, { name: \"Better Business Bureau\", category: \"analytics\", domains: [\"*.bbb.org\"], totalExecutionTime: 10819, totalOccurrences: 78 }, { name: \"Between Digital\", category: \"ad\", domains: [\"*.betweendigital.com\"], totalExecutionTime: 88306, totalOccurrences: 787 }, { name: \"BidTheatre\", category: \"ad\", domains: [\"*.bidtheatre.com\"], totalExecutionTime: 23106, totalOccurrences: 252 }, { name: \"Bidtellect\", category: \"ad\", domains: [\"*.bttrack.com\"], totalExecutionTime: 2834, totalOccurrences: 19 }, { name: \"Bigcommerce\", category: \"marketing\", domains: [\"*.bigcommerce.com\"], totalExecutionTime: 45747978,\n    totalOccurrences: 19595 }, { name: \"BitGravity\", company: \"Tata Communications\", category: \"content\", domains: [\"*.bitgravity.com\"] }, { name: \"Bitly\", category: \"utility\", domains: [\"*.bitly.com\", \"*.lemde.fr\", \"*.bit.ly\"], totalExecutionTime: 2977, totalOccurrences: 8 }, { name: \"Bizible\", category: \"ad\", domains: [\"*.bizible.com\", \"*.bizibly.com\"], totalExecutionTime: 435247, totalOccurrences: 1186 }, { name: \"Bizrate\", category: \"analytics\", domains: [\"*.bizrate.com\"], totalExecutionTime: 11197, totalOccurrences: 57 }, { name: \"BlastCasta\", category: \"social\", domains: [\"*.poweringnews.com\"], examples: [\"www.poweringnews.com\"] }, { name: \"Blindado\", category: \"utility\", domains: [\"*.siteblindado.com\"], totalExecutionTime: 41, totalOccurrences: 1 }, { name: \"Blis\", category: \"ad\", domains: [\"*.blismedia.com\"] }, { name: \"Blogg.se\", category: \"hosting\", domains: [\"*.cdnme.se\", \"*.publishme.se\"] }, { name: \"BloomReach\", category: \"ad\", domains: [\"*.brcdn.com\", \"*.brsrvr.com\", \"*.b\\\nrsvr.com\"], totalExecutionTime: 2695, totalOccurrences: 47 }, { name: \"Bloomberg\", category: \"content\", domains: [\"*.gotraffic.net\"] }, { name: \"Shop Logic\", company: \"BloomReach\", category: \"marketing\", domains: [\"*.goshoplogic.com\"] }, { name: \"Blue State Digital\", category: \"ad\", domains: [\"*.bsd.net\"] }, { name: \"Blue Triangle Technologies\", category: \"analytics\", domains: [\"*.btttag.com\"], totalExecutionTime: 102966, totalOccurrences: 182 }, { name: \"BlueCava\", category: \"ad\", domains: [\"*.bluecava.com\"], totalExecutionTime: 466075, totalOccurrences: 5165 }, { name: \"BlueKai\", company: \"Oracle\", category: \"ad\", domains: [\"*.bkrtx.com\", \"*.bluekai.com\"], totalExecutionTime: 4, totalOccurrences: 6 }, { name: \"Bluecore\", category: \"analytics\", domains: [\"*.bluecore.com\"], examples: [\"www.bluecore.com\"], totalExecutionTime: 83612, totalOccurrences: 225 }, { name: \"Bluegg\", category: \"hosting\", domains: [\"d1va5oqn59yrvt.cloudfront.net\"] }, { name: \"Bold Commerce\", category: \"utility\", domains: [\n    \"*.shappify-cdn.com\", \"*.shappify.com\", \"*.boldapps.net\"], totalExecutionTime: 5072681, totalOccurrences: 9886 }, { name: \"BoldChat\", company: \"LogMeIn\", category: \"customer-success\", domains: [\"*.boldchat.com\"] }, { name: \"Bombora\", category: \"ad\", domains: [\"*.mlno6.com\"] }, { name: \"Bonnier\", category: \"content\", domains: [\"*.bonniercorp.com\"] }, { name: \"Bookatable\", category: \"content\", domains: [\"*.bookatable.com\", \"*.livebookings.com\"] }, { name: \"Booking.com\", category: \"content\", domains: [\"*.bstatic.com\"], totalExecutionTime: 1652677, totalOccurrences: 2448 }, { name: \"Boomtrain\", category: \"ad\", domains: [\"*.boomtrain.com\", \"*.boomtrain.net\"], totalExecutionTime: 360072, totalOccurrences: 2169 }, { name: \"BoostSuite\", category: \"ad\", domains: [\"*.poweredbyeden.com\"] }, { name: \"Boostable\", category: \"ad\", domains: [\"*.boostable.com\"] }, { name: \"Bootstrap Chinese network\", category: \"cdn\", domains: [\"*.bootcss.com\"], totalExecutionTime: 427117, totalOccurrences: 881 }, {\n    name: \"Booxscale\", category: \"ad\", domains: [\"*.booxscale.com\"] }, { name: \"Borderfree\", company: \"pitney bowes\", category: \"utility\", domains: [\"*.borderfree.com\", \"*.fiftyone.com\"] }, { name: \"BowNow\", category: \"analytics\", homepage: \"https://bow-now.jp/\", domains: [\"*.bownow.jp\"], examples: [\"contents.bownow.jp\"], totalExecutionTime: 1298132, totalOccurrences: 2410 }, { name: \"Box\", category: \"hosting\", domains: [\"*.box.com\"], totalExecutionTime: 15191, totalOccurrences: 223 }, { name: \"Boxever\", category: \"analytics\", domains: [\"*.boxever.com\"] }, { name: \"Braintree Payments\", company: \"Paypal\", category: \"utility\", domains: [\"*.braintreegateway.com\"], totalExecutionTime: 171291, totalOccurrences: 1141 }, { name: \"Branch Metrics\", category: \"ad\", domains: [\"*.branch.io\", \"*.app.link\"], totalExecutionTime: 441792, totalOccurrences: 8288 }, { name: \"Brand Finance\", category: \"other\", domains: [\"*.brandirectory.com\"] }, { name: \"Brand View\", category: \"analytics\", domains: [\"*.br\\\nandview.com\"] }, { name: \"Brandscreen\", category: \"ad\", domains: [\"*.rtbidder.net\"], examples: [\"match.rtbidder.net\"] }, { name: \"BridgeTrack\", company: \"Sapient\", category: \"ad\", domains: [\"*.bridgetrack.com\"] }, { name: \"BrightRoll\", company: \"Yahoo!\", category: \"ad\", domains: [\"*.btrll.com\"] }, { name: \"BrightTag / Signal\", company: \"Signal\", homepage: \"https://www.signal.co\", category: \"tag-manager\", domains: [\"*.btstatic.com\", \"*.thebrighttag.com\"] }, { name: \"Brightcove ZenCoder\", company: \"Brightcove\", category: \"other\", domains: [\"*.zencoder.net\"] }, { name: \"Bronto Software\", category: \"marketing\", domains: [\"*.bm23.com\", \"*.bronto.com\", \"*.brontops.com\"] }, { name: \"Browser-Update.org\", category: \"other\", domains: [\"*.browser-update.org\"] }, { name: \"Buffer\", category: \"social\", domains: [\"*.bufferapp.com\"], totalExecutionTime: 535, totalOccurrences: 7 }, { name: \"Bugsnag\", category: \"utility\", domains: [\"*.bugsnag.com\", \"d2wy8f7a9ursnm.cloudfront.net\"], examples: [\"notify.bu\\\ngsnag.com\"], totalExecutionTime: 6197502, totalOccurrences: 15069 }, { name: \"Burst Media\", category: \"ad\", domains: [\"*.burstnet.com\", \"*.1rx.io\"], examples: [\"usermatch.burstnet.com\"], totalExecutionTime: 1618, totalOccurrences: 52 }, { name: \"Burt\", category: \"analytics\", domains: [\"*.richmetrics.com\", \"*.burt.io\"] }, { name: \"Business Message\", category: \"ad\", domains: [\"*.message-business.com\"], totalExecutionTime: 7310, totalOccurrences: 21 }, { name: \"Business Week\", company: \"Bloomberg\", category: \"social\", domains: [\"*.bwbx.io\"], totalExecutionTime: 67737, totalOccurrences: 9 }, { name: \"Buto\", company: \"Big Button\", category: \"ad\", domains: [\"*.buto.tv\"] }, { name: \"Button\", category: \"ad\", domains: [\"*.btncdn.com\"] }, { name: \"BuySellAds\", category: \"ad\", domains: [\"*.buysellads.com\", \"*.buysellads.net\"], totalExecutionTime: 179225, totalOccurrences: 170 }, { name: \"BuySight (AOL)\", category: \"ad\", domains: [\"*.pulsemgr.com\"] }, { name: \"Buyapowa\", category: \"ad\", domains: [\n    \"*.co-buying.com\"], totalExecutionTime: 3038, totalOccurrences: 37 }, { name: \"BuzzFeed\", category: \"social\", domains: [\"*.buzzfed.com\", \"*.buzzfeed.com\"], totalExecutionTime: 14608, totalOccurrences: 2 }, { name: \"C1X\", category: \"ad\", domains: [\"*.c1exchange.com\"] }, { name: \"C3 Metrics\", category: \"analytics\", domains: [\"*.c3tag.com\"], totalExecutionTime: 18122, totalOccurrences: 153 }, { name: \"CANDDi\", company: \"Campaign and Digital Intelligence\", category: \"ad\", domains: [\"*.canddi.com\"], totalExecutionTime: 84756, totalOccurrences: 150 }, { name: \"CCM benchmark Group\", category: \"social\", domains: [\"*.ccm2.net\"] }, { name: \"CD Networks\", category: \"utility\", domains: [\"*.gccdn.net\"] }, { name: \"CDN Planet\", category: \"analytics\", domains: [\"*.cdnplanet.com\"] }, { name: \"InAuth\", category: \"utility\", homepage: \"https://www.inauth.com/\", domains: [\"*.cdn-net.com\"], examples: [\"uk.cdn-net.com\"], totalExecutionTime: 306346, totalOccurrences: 298 }, { name: \"CJ Affiliate\", company: \"\\\nConversant\", category: \"ad\", domains: [\"*.cj.com\", \"*.dpbolvw.net\"], totalExecutionTime: 7725, totalOccurrences: 17 }, { name: \"CJ Affiliate by Conversant\", company: \"Conversant\", category: \"ad\", domains: [\"*.ftjcfx.com\"], totalExecutionTime: 8, totalOccurrences: 4 }, { name: \"CNBC\", category: \"content\", domains: [\"*.cnbc.com\"], totalExecutionTime: 11468, totalOccurrences: 12 }, { name: \"CNET Content Solutions\", company: \"CBS Interactive\", category: \"content\", domains: [\"*.cnetcontent.com\"], examples: [\"cdn.cnetcontent.com\", \"ws.cnetcontent.com\"] }, { name: \"CPEx\", category: \"content\", domains: [\"*.cpex.cz\"], totalExecutionTime: 763356, totalOccurrences: 1104 }, { name: \"CPXi\", category: \"ad\", domains: [\"*.cpxinteractive.com\"] }, { name: \"CUBED Attribution\", company: \"CUBED\", category: \"ad\", domains: [\"*.withcubed.com\"], examples: [\"data.withcubed.com\"] }, { name: \"Cachefly\", category: \"utility\", domains: [\"*.cachefly.net\"], totalExecutionTime: 128046, totalOccurrences: 258 }, { name: \"\\\nCalendly\", category: \"other\", domains: [\"*.calendly.com\"], totalExecutionTime: 8622733, totalOccurrences: 4604 }, { name: \"CallRail\", category: \"analytics\", domains: [\"*.callrail.com\"], totalExecutionTime: 8080185, totalOccurrences: 29537 }, { name: \"CallTrackingMetrics\", category: \"analytics\", domains: [\"*.tctm.co\"], totalExecutionTime: 1981698, totalOccurrences: 7503 }, { name: \"Canned Banners\", category: \"ad\", domains: [\"*.cannedbanners.com\"] }, { name: \"Canopy Labs\", category: \"analytics\", domains: [\"*.canopylabs.com\"] }, { name: \"Capita\", category: \"utility\", domains: [\"*.crcom.co.uk\"], examples: [\"emmsrep.crcom.co.uk\"] }, { name: \"Captify Media\", category: \"ad\", domains: [\"*.cpx.to\"], totalExecutionTime: 1519, totalOccurrences: 31 }, { name: \"Captiify\", category: \"ad\", domains: [\"*.captifymedia.com\"] }, { name: \"Captivate Ai\", category: \"ad\", domains: [\"*.captivate.ai\"] }, { name: \"Captora\", category: \"marketing\", domains: [\"*.captora.com\"] }, { name: \"Carcloud\", category: \"other\",\n    domains: [\"*.carcloud.co.uk\"] }, { name: \"Cardlytics\", category: \"ad\", domains: [\"*.cardlytics.com\"] }, { name: \"Cardosa Enterprises\", category: \"analytics\", domains: [\"*.y-track.com\"], totalExecutionTime: 778, totalOccurrences: 17 }, { name: \"Caspian Media\", category: \"ad\", domains: [\"*.caspianmedia.com\"] }, { name: \"Cast\", category: \"utility\", domains: [\"*.cast.rocks\"] }, { name: \"Catch\", category: \"other\", domains: [\"*.getcatch.com\"], examples: [\"app.getcatch.com\", \"assets.getcatch.com\", \"js.getcatch.com\"], totalExecutionTime: 18282, totalOccurrences: 40 }, { name: \"Cavisson\", category: \"analytics\", domains: [\"*.cavisson.com\"] }, { name: \"Cedato\", category: \"ad\", domains: [\"*.algovid.com\", \"*.vdoserv.com\"] }, { name: \"Celebrus Technologies\", category: \"analytics\", domains: [\"*.celebrus.com\"] }, { name: \"Celtra\", category: \"ad\", domains: [\"*.celtra.com\"], totalExecutionTime: 369517, totalOccurrences: 427 }, { name: \"Centro\", category: \"ad\", domains: [\"*.brand-server.com\"] }, { name: \"\\\nCeros\", category: \"other\", domains: [\"ceros.com\", \"view.ceros.com\"], totalExecutionTime: 64139, totalOccurrences: 149 }, { name: \"Ceros Analytics\", company: \"Ceros\", category: \"analytics\", domains: [\"api.ceros.com\"] }, { name: \"Certona\", category: \"analytics\", domains: [\"*.certona.net\"], totalExecutionTime: 376, totalOccurrences: 4 }, { name: \"Certum\", category: \"utility\", domains: [\"*.ocsp-certum.com\", \"*.certum.pl\"], totalExecutionTime: 8544, totalOccurrences: 3 }, { name: \"Cgrdirect\", category: \"other\", domains: [\"*.cgrdirect.co.uk\"] }, { name: \"Channel 5 Media\", category: \"ad\", domains: [\"*.five.tv\"] }, { name: \"Channel.me\", category: \"customer-success\", domains: [\"*.channel.me\"] }, { name: \"ChannelAdvisor\", category: \"ad\", domains: [\"*.channeladvisor.com\", \"*.searchmarketing.com\"], totalExecutionTime: 3385, totalOccurrences: 25 }, { name: \"ChannelApe\", company: \"ChannelApe\", category: \"other\", homepage: \"https://www.channelape.com/\", domains: [\"*.channelape.com\"], examples: [\"call\\\nbacks.channelape.com\"] }, { name: \"Chargeads Oscar\", company: \"Chargeads\", category: \"ad\", domains: [\"*.chargeads.com\"] }, { name: \"Charities Aid Foundation\", category: \"utility\", domains: [\"*.cafonline.org\"], totalExecutionTime: 4368, totalOccurrences: 7 }, { name: \"Chartbeat\", category: \"analytics\", domains: [\"*.chartbeat.com\", \"*.chartbeat.net\"], totalExecutionTime: 1270560, totalOccurrences: 6246 }, { name: \"Cheapflights Media\", company: \"Momondo\", category: \"content\", domains: [\"*.momondo.net\"] }, { name: \"CheckM8\", category: \"ad\", domains: [\"*.checkm8.com\"] }, { name: \"CheckRate\", company: \"FreeStart\", category: \"utility\", domains: [\"*.checkrate.co.uk\"] }, { name: \"Checkfront\", category: \"other\", domains: [\"*.checkfront.com\", \"dcg3jth5savst.cloudfront.net\"], totalExecutionTime: 279282, totalOccurrences: 152 }, { name: \"CheetahMail\", company: \"Experian\", category: \"ad\", domains: [\"*.chtah.com\"] }, { name: \"Chitika\", category: \"ad\", domains: [\"*.chitika.net\"] }, { name: \"ChoiceStre\\\nam\", category: \"ad\", domains: [\"*.choicestream.com\"] }, { name: \"Cint\", category: \"social\", domains: [\"*.cint.com\"], totalExecutionTime: 111659, totalOccurrences: 33 }, { name: \"Civic\", category: \"hosting\", domains: [\"*.civiccomputing.com\"], totalExecutionTime: 2815742, totalOccurrences: 7253 }, { name: \"ClearRise\", category: \"customer-success\", domains: [\"*.clearrise.com\"] }, { name: \"Clearstream\", category: \"ad\", domains: [\"*.clrstm.com\"] }, { name: \"Clerk.io ApS\", category: \"analytics\", domains: [\"*.clerk.io\"], totalExecutionTime: 1196778, totalOccurrences: 1915 }, { name: \"CleverDATA\", category: \"ad\", domains: [\"*.1dmp.io\"] }, { name: \"CleverTap\", category: \"analytics\", domains: [\"d2r1yp2w7bby2u.cloudfront.net\"], totalExecutionTime: 163519, totalOccurrences: 1321 }, { name: \"Click Density\", category: \"analytics\", domains: [\"*.clickdensity.com\"] }, { name: \"Click4Assistance\", category: \"customer-success\", domains: [\"*.click4assistance.co.uk\"], totalExecutionTime: 22710, totalOccurrences: 178 },\n    { name: \"ClickDesk\", category: \"customer-success\", domains: [\"*.clickdesk.com\", \"d1gwclp1pmzk26.cloudfront.net\"], totalExecutionTime: 74975, totalOccurrences: 595 }, { name: \"ClickDimensions\", category: \"ad\", domains: [\"*.clickdimensions.com\"], totalExecutionTime: 125295, totalOccurrences: 262 }, { name: \"Clickadu (Winner Solutions)\", category: \"ad\", domains: [\"*.clickadu.com\"], totalExecutionTime: 10740, totalOccurrences: 4 }, { name: \"Clickagy Audience Lab\", company: \"Clickagy\", category: \"ad\", domains: [\"*.clickagy.com\"], examples: [\"aorta.clickagy.com\"], totalExecutionTime: 44558, totalOccurrences: 667 }, { name: \"Clickio\", category: \"ad\", domains: [] }, { name: \"Clicktale\", category: \"analytics\", domains: [\"*.cdngc.net\", \"*.clicktale.net\"], examples: [\"clicktalecdn.sslcs.cdngc.net\"], totalExecutionTime: 288716, totalOccurrences: 256 }, { name: \"Clicktripz\", category: \"content\", domains: [\"*.clicktripz.com\"], examples: [\"static.clicktripz.com\", \"www.clicktripz.com\"], totalExecutionTime: 502041,\n    totalOccurrences: 354 }, { name: \"Clik.com Websites\", category: \"content\", domains: [\"*.clikpic.com\"] }, { name: \"Cloud Technologies\", category: \"ad\", domains: [\"*.behavioralengine.com\", \"*.behavioralmailing.com\"] }, { name: \"Cloud-A\", category: \"other\", domains: [\"*.bulkstorage.ca\"] }, { name: \"Cloud.typography\", company: \"Hoefler &amp; Co\", category: \"cdn\", domains: [\"*.typography.com\"], totalExecutionTime: 3308, totalOccurrences: 364 }, { name: \"CloudSponge\", category: \"ad\", domains: [\"*.cloudsponge.com\"] }, { name: \"CloudVPS\", category: \"other\", domains: [\"*.adoftheyear.com\", \"*.objectstore.eu\"] }, { name: \"Cloudinary\", category: \"content\", domains: [\"*.cloudinary.com\"], totalExecutionTime: 1188126, totalOccurrences: 2129 }, { name: \"Cloudqp\", company: \"Cloudwp\", category: \"other\", domains: [\"*.cloudwp.io\"] }, { name: \"Cludo\", category: \"utility\", domains: [\"*.cludo.com\"], totalExecutionTime: 25376, totalOccurrences: 249 }, { name: \"Cognesia\", category: \"marketing\", domains: [\"\\\n*.intelli-direct.com\"] }, { name: \"CogoCast\", company: \"Cogo Labs\", category: \"ad\", domains: [\"*.cogocast.net\"] }, { name: \"Colbenson\", category: \"utility\", domains: [\"*.colbenson.com\"] }, { name: \"Collective\", category: \"ad\", domains: [\"*.collective-media.net\"] }, { name: \"Com Laude\", category: \"other\", domains: [\"*.gdimg.net\"] }, { name: \"Comm100\", category: \"customer-success\", domains: [\"*.comm100.com\"], totalExecutionTime: 469389, totalOccurrences: 1045 }, { name: \"CommerceHub\", category: \"marketing\", domains: [\"*.mercent.com\"] }, { name: \"Commission Factory\", category: \"ad\", domains: [\"*.cfjump.com\"], totalExecutionTime: 961, totalOccurrences: 12 }, { name: \"Communicator\", category: \"ad\", domains: [\"*.communicatorcorp.com\", \"*.communicatoremail.com\"] }, { name: \"Comodo\", category: \"utility\", domains: [\"*.comodo.com\", \"*.trust-provider.com\", \"*.trustlogo.com\", \"*.usertrust.com\", \"*.comodo.net\"], examples: [\"ocsp.trust-provider.com\"], totalExecutionTime: 41752, totalOccurrences: 34 },\n    { name: \"Comodo Certificate Authority\", company: \"Comodo\", category: \"utility\", domains: [\"crt.comodoca.com\", \"*.comodoca4.com\", \"ocsp.comodoca.com\", \"ocsp.usertrust.com\", \"crt.usertrust.com\"], examples: [\"ocsp.comodoca4.com\"] }, { name: \"Compete\", company: \"Millwood Brown Digital\", category: \"analytics\", domains: [\"*.c-col.com\", \"*.compete.com\"] }, { name: \"Compuware\", category: \"analytics\", domains: [\"*.axf8.net\"] }, { name: \"Conductrics\", category: \"analytics\", domains: [\"*.conductrics.com\"], examples: [\"cdn-v3.conductrics.com\"], totalExecutionTime: 12705, totalOccurrences: 61 }, { name: \"Confirmit\", category: \"analytics\", domains: [\"*.confirmit.com\"], totalExecutionTime: 32100, totalOccurrences: 195 }, { name: \"Connatix\", category: \"ad\", domains: [\"*.connatix.com\"], totalExecutionTime: 6751327, totalOccurrences: 1195 }, { name: \"Connect Events\", category: \"hosting\", domains: [\"*.connectevents.com.au\"] }, { name: \"Constant Contact\", category: \"ad\", domains: [\"*.ctctcdn.com\"], totalExecutionTime: 604932,\n    totalOccurrences: 17528 }, { name: \"Constructor.io\", category: \"utility\", domains: [\"*.cnstrc.com\"] }, { name: \"Contabo\", category: \"hosting\", domains: [\"185.2.100.179\"] }, { name: \"Content Media Corporation\", category: \"content\", domains: [\"*.contentmedia.eu\"] }, { name: \"ContentSquare\", category: \"analytics\", domains: [\"d1m6l9dfulcyw7.cloudfront.net\", \"*.content-square.net\", \"*.contentsquare.net\"], totalExecutionTime: 3626830, totalOccurrences: 2948 }, { name: \"ContextWeb\", category: \"ad\", domains: [\"*.contextweb.com\"], totalExecutionTime: 32437, totalOccurrences: 1909 }, { name: \"Continental Exchange Solutions\", category: \"utility\", domains: [\"*.hifx.com\"] }, { name: \"Converge-Digital\", category: \"ad\", domains: [\"*.converge-digital.com\"], examples: [\"ads.converge-digital.com\"] }, { name: \"Conversant\", category: \"analytics\", domains: [\"*.dotomi.com\", \"*.dtmpub.com\", \"*.emjcd.com\", \"mediaplex.com\", \"*.tqlkg.com\", \"*.fastclick.net\"], examples: [\"www.tqlkg.com\"], totalExecutionTime: 6531550,\n    totalOccurrences: 54802 }, { name: \"Conversant Ad Server\", company: \"Conversant\", category: \"ad\", domains: [\"adfarm.mediaplex.com\", \"*.mediaplex.com\"] }, { name: \"Conversant Tag Manager\", company: \"Conversant\", category: \"tag-manager\", domains: [\"*.mplxtms.com\"], totalExecutionTime: 14146, totalOccurrences: 58 }, { name: \"Conversio\", category: \"ad\", domains: [\"*.conversio.com\"] }, { name: \"Conversion Labs\", category: \"ad\", domains: [\"*.net.pl\"], examples: [\"conversionlabs.net.pl\"], totalExecutionTime: 3243395, totalOccurrences: 1898 }, { name: \"Conversion Logic\", category: \"ad\", domains: [\"*.conversionlogic.net\"] }, { name: \"Convert Insights\", category: \"analytics\", domains: [\"*.convertexperiments.com\"], totalExecutionTime: 2575826, totalOccurrences: 4385 }, { name: \"ConvertMedia\", category: \"ad\", domains: [\"*.admailtiser.com\", \"*.basebanner.com\", \"*.cmbestsrv.com\", \"*.vidfuture.com\", \"*.zorosrv.com\"], examples: [\"www.cmbestsrv.com\"] }, { name: \"Convertro\", category: \"ad\", domains: [\n    \"*.convertro.com\"] }, { name: \"Conviva\", category: \"content\", domains: [\"*.conviva.com\"], totalExecutionTime: 2955, totalOccurrences: 2 }, { name: \"Cookie Reports\", category: \"utility\", domains: [\"*.cookiereports.com\"], totalExecutionTime: 280810, totalOccurrences: 671 }, { name: \"Cookie-Script.com\", category: \"utility\", domains: [\"*.cookie-script.com\"], totalExecutionTime: 15051619, totalOccurrences: 58095 }, { name: \"CookieQ\", company: \"Baycloud Systems\", category: \"utility\", domains: [\"*.cookieq.com\"] }, { name: \"CoolaData\", category: \"analytics\", domains: [\"*.cooladata.com\"], totalExecutionTime: 1165, totalOccurrences: 15 }, { name: \"CopperEgg\", category: \"analytics\", domains: [\"*.copperegg.com\", \"d2vig74li2resi.cloudfront.net\"] }, { name: \"Council ad Network\", category: \"ad\", domains: [\"*.counciladvertising.net\"], totalExecutionTime: 18621, totalOccurrences: 94 }, { name: \"Covert Pics\", category: \"content\", domains: [\"*.covet.pics\"], totalExecutionTime: 4496, totalOccurrences: 55 },\n    { name: \"Cox Digital Solutions\", category: \"ad\", domains: [\"*.afy11.net\"] }, { name: \"Creafi Online Media\", category: \"ad\", domains: [\"*.creafi-online-media.com\"] }, { name: \"Creators\", category: \"content\", domains: [\"*.creators.co\"] }, { name: \"Crimson Hexagon Analytics\", company: \"Crimson Hexagon\", category: \"analytics\", domains: [\"*.hexagon-analytics.com\"] }, { name: \"Crimtan\", category: \"ad\", domains: [\"*.ctnsnet.com\"], totalExecutionTime: 59150, totalOccurrences: 74818 }, { name: \"Cross Pixel Media\", category: \"ad\", domains: [\"*.crsspxl.com\"], totalExecutionTime: 493, totalOccurrences: 8 }, { name: \"Crosswise\", category: \"ad\", domains: [\"*.univide.com\"], examples: [\"p.univide.com\"] }, { name: \"Crowd Control\", company: \"Lotame\", category: \"ad\", domains: [\"*.crwdcntrl.net\"], totalExecutionTime: 16298725, totalOccurrences: 101196 }, { name: \"Crowd Ignite\", category: \"ad\", domains: [\"*.crowdignite.com\"] }, { name: \"CrowdTwist\", category: \"ad\", domains: [\"*.crowdtwist.com\"] }, { name: \"\\\nCrowdskout\", category: \"ad\", domains: [\"*.crowdskout.com\"] }, { name: \"Crowdynews\", category: \"social\", domains: [\"*.breakingburner.com\"] }, { name: \"Curalate\", category: \"marketing\", domains: [\"*.curalate.com\", \"d116tqlcqfmz3v.cloudfront.net\"], totalExecutionTime: 628884, totalOccurrences: 683 }, { name: \"Customer Acquisition Cloud\", company: \"[24]7\", category: \"ad\", domains: [\"*.campanja.com\"] }, { name: \"Customer.io\", category: \"ad\", domains: [\"*.customer.io\"], totalExecutionTime: 210609, totalOccurrences: 1268 }, { name: \"Custora\", category: \"analytics\", domains: [\"*.custora.com\"] }, { name: \"Cxense\", category: \"ad\", domains: [\"*.cxense.com\", \"*.cxpublic.com\", \"*.emediate.dk\", \"*.emediate.eu\"], totalExecutionTime: 2218364, totalOccurrences: 3708 }, { name: \"CyberKnight\", company: \"Namogoo\", category: \"utility\", domains: [\"*.namogoo.com\"] }, { name: \"CyberSource (Visa)\", category: \"utility\", domains: [\"*.authorize.net\"], totalExecutionTime: 339030, totalOccurrences: 2682 }, { name: \"\\\nCybernet Quest\", category: \"analytics\", domains: [\"*.cqcounter.com\"] }, { name: \"D.A. Consortium\", category: \"ad\", domains: [\"*.eff1.net\"] }, { name: \"D4t4 Solutions\", category: \"analytics\", domains: [\"*.u5e.com\"] }, { name: \"DCSL Software\", category: \"hosting\", domains: [\"*.dcslsoftware.com\"] }, { name: \"DMG Media\", category: \"content\", domains: [\"*.mol.im\", \"*.and.co.uk\", \"*.anm.co.uk\", \"*.dailymail.co.uk\"], totalExecutionTime: 37855, totalOccurrences: 15 }, { name: \"DTSCOUT\", category: \"ad\", domains: [\"*.dtscout.com\"], totalExecutionTime: 645362, totalOccurrences: 8311 }, { name: \"Dailykarma\", category: \"utility\", homepage: \"https://www.dailykarma.com/\", domains: [\"*.dailykarma.io\"], examples: [\"assets.dailykarma.io\"], totalExecutionTime: 122378, totalOccurrences: 477 }, { name: \"Dailymotion\", category: \"content\", domains: [\"*.dailymotion.com\", \"*.dmxleo.com\", \"*.dm.gg\", \"*.pxlad.io\", \"*.dmcdn.net\", \"*.sublimevideo.net\"], examples: [\"ad.pxlad.io\", \"www.dailymotion.com\"], totalExecutionTime: 56076026,\n    totalOccurrences: 5142 }, { name: \"Dash Hudson\", company: \"Dash Hudson\", category: \"content\", domains: [\"*.dashhudson.com\"], examples: [\"cdn.dashhudson.com\"], totalExecutionTime: 154963, totalOccurrences: 91 }, { name: \"Datacamp\", category: \"utility\", domains: [\"*.cdn77.org\"], totalExecutionTime: 3303608, totalOccurrences: 1181 }, { name: \"Datalicious\", category: \"tag-manager\", domains: [\"*.supert.ag\", \"*.optimahub.com\"] }, { name: \"Datalogix\", category: \"ad\", domains: [\"*.nexac.com\"] }, { name: \"Datawrapper\", category: \"utility\", domains: [\"*.datawrapper.de\", \"*.dwcdn.net\"], examples: [\"www.datawrapper.de\"], totalExecutionTime: 951486, totalOccurrences: 249 }, { name: \"Dataxu\", category: \"marketing\", domains: [\"*.w55c.net\"], totalExecutionTime: 10, totalOccurrences: 5 }, { name: \"DatoCMS\", homepage: \"https://www.datocms.com/\", category: \"content\", domains: [\"*.datocms-assets.com\"], examples: [\"www.datocms-assets.com\"] }, { name: \"Datonics\", category: \"ad\", domains: [\"*.pro-market.\\\nnet\"], examples: [\"pbid.pro-market.net\"], totalExecutionTime: 16955, totalOccurrences: 254 }, { name: \"Dealtime\", category: \"content\", domains: [\"*.dealtime.com\"] }, { name: \"Debenhams Geo Location\", company: \"Debenhams\", category: \"utility\", domains: [\"176.74.183.134\"] }, { name: \"Decibel Insight\", category: \"analytics\", domains: [\"*.decibelinsight.net\"], totalExecutionTime: 995190, totalOccurrences: 691 }, { name: \"Deep Forest Media\", company: \"Rakuten\", category: \"ad\", domains: [\"*.dpclk.com\"] }, { name: \"DeepIntent\", category: \"ad\", domains: [\"*.deepintent.com\"], totalExecutionTime: 3875, totalOccurrences: 206 }, { name: \"Delicious Media\", category: \"social\", domains: [\"*.delicious.com\"] }, { name: \"Delineo\", category: \"ad\", domains: [\"*.delineo.com\"], examples: [\"www.delineo.com\"] }, { name: \"Delta Projects AB\", category: \"ad\", domains: [\"*.de17a.com\"], totalExecutionTime: 90548, totalOccurrences: 382 }, { name: \"Demand Media\", category: \"content\", domains: [\"*.dmtracker.com\"] }, {\n    name: \"DemandBase\", category: \"marketing\", domains: [\"*.demandbase.com\"], totalExecutionTime: 393206, totalOccurrences: 2552 }, { name: \"DemandJump\", category: \"analytics\", domains: [\"*.demandjump.com\"] }, { name: \"Dennis Publishing\", category: \"content\", domains: [\"*.alphr.com\"] }, { name: \"Devatics\", category: \"analytics\", domains: [\"*.devatics.com\", \"*.devatics.io\"] }, { name: \"Developer Media\", category: \"ad\", domains: [\"*.developermedia.com\"], totalExecutionTime: 4416, totalOccurrences: 17 }, { name: \"DialogTech\", category: \"ad\", domains: [\"*.dialogtech.com\"] }, { name: \"DialogTech SourceTrak\", company: \"DialogTech\", category: \"ad\", domains: [\"d31y97ze264gaa.cloudfront.net\"] }, { name: \"DigiCert\", category: \"utility\", domains: [\"*.digicert.com\"], examples: [\"ocsp.digicert.com\"], totalExecutionTime: 26560, totalOccurrences: 83 }, { name: \"Digioh\", category: \"ad\", domains: [\"*.lightboxcdn.com\"], totalExecutionTime: 1347082, totalOccurrences: 1303 }, { name: \"Digital Look\", category: \"\\\ncontent\", domains: [\"*.digitallook.com\"] }, { name: \"Digital Media Exchange\", company: \"NDN\", category: \"content\", domains: [\"*.newsinc.com\"] }, { name: \"Digital Millennium Copyright Act Services\", category: \"utility\", domains: [\"*.dmca.com\"], totalExecutionTime: 8820, totalOccurrences: 70 }, { name: \"Digital Ocean\", category: \"other\", domains: [\"95.85.62.56\"] }, { name: \"Digital Remedy\", category: \"ad\", domains: [\"*.consumedmedia.com\"] }, { name: \"Digital Window\", category: \"ad\", domains: [\"*.awin1.com\", \"*.zenaps.com\"], totalExecutionTime: 195, totalOccurrences: 4 }, { name: \"DigitalScirocco\", category: \"analytics\", domains: [\"*.digitalscirocco.net\"] }, { name: \"Digitial Point\", category: \"utility\", domains: [\"*.dpstatic.com\"] }, { name: \"Diligent (Adnetik)\", category: \"ad\", domains: [\"*.wtp101.com\"] }, { name: \"Directed Edge\", category: \"social\", domains: [\"*.directededge.com\"], examples: [\"shopify.directededge.com\"], totalExecutionTime: 8371, totalOccurrences: 81 }, { name: \"Distri\\\nbute Travel\", category: \"ad\", domains: [\"*.dtrck.net\"] }, { name: \"District M\", category: \"ad\", domains: [\"*.districtm.io\"] }, { name: \"DistroScale\", category: \"ad\", domains: [\"*.jsrdn.com\"], totalExecutionTime: 186009, totalOccurrences: 198 }, { name: \"Divido\", category: \"utility\", domains: [\"*.divido.com\"] }, { name: \"Dow Jones\", category: \"content\", domains: [\"*.dowjones.com\", \"*.dowjoneson.com\"] }, { name: \"Drifty Co\", category: \"utility\", domains: [\"*.onicframework.com\"] }, { name: \"Drip\", company: \"The Numa Group\", category: \"ad\", domains: [\"*.getdrip.com\"], totalExecutionTime: 120918, totalOccurrences: 1350 }, { name: \"Dropbox\", category: \"utility\", domains: [\"*.dropboxusercontent.com\"], totalExecutionTime: 142552, totalOccurrences: 145 }, { name: \"Dyn Real User Monitoring\", company: \"Dyn\", category: \"analytics\", domains: [\"*.jisusaiche.biz\", \"*.dynapis.com\", \"*.jisusaiche.com\", \"*.dynapis.info\"], examples: [\"beacon.rum.dynapis.com\"] }, { name: \"DynAdmic\", category: \"ad\", domains: [\n    \"*.dyntrk.com\"] }, { name: \"Dynamic Converter\", category: \"utility\", domains: [\"*.dynamicconverter.com\"], totalExecutionTime: 58723, totalOccurrences: 96 }, { name: \"Dynamic Dummy Image Generator\", company: \"Open Source\", category: \"utility\", domains: [\"*.dummyimage.com\"] }, { name: \"Dynamic Logic\", category: \"ad\", domains: [\"*.dl-rms.com\", \"*.questionmarket.com\"] }, { name: \"Dynamic Yield\", category: \"customer-success\", domains: [\"*.dynamicyield.com\"], totalExecutionTime: 3580074, totalOccurrences: 1843 }, { name: \"Dynatrace\", category: \"analytics\", domains: [\"*.ruxit.com\", \"js-cdn.dynatrace.com\"], totalExecutionTime: 4106731, totalOccurrences: 3221 }, { name: \"ec-concier\", homepage: \"https://ec-concier.com/\", category: \"marketing\", domains: [\"*.ec-concier.com\"], examples: [\"s.ec-concier.com\", \"gsync.ec-concier.com\"] }, { name: \"ECT News Network\", category: \"content\", domains: [\"*.ectnews.com\"] }, { name: \"ELITechGroup\", category: \"analytics\", domains: [\"*.elitechnology.com\"] }, {\n    name: \"EMAP\", category: \"content\", domains: [\"*.emap.com\"] }, { name: \"EMedia Solutions\", category: \"ad\", domains: [\"*.e-shots.eu\"], examples: [\"www.e-shots.eu\"] }, { name: \"EQ works\", category: \"ad\", domains: [\"*.eqads.com\"] }, { name: \"ESV Digital\", category: \"analytics\", domains: [\"*.esearchvision.com\"] }, { name: \"Ebiquity\", category: \"analytics\", domains: [\"*.ebiquitymedia.com\"] }, { name: \"Eco Rebates\", category: \"ad\", domains: [\"*.ecorebates.com\"] }, { name: \"Ecwid\", category: \"hosting\", domains: [\"*.ecwid.com\", \"*.shopsettings.com\", \"d3fi9i0jj23cau.cloudfront.net\", \"d3j0zfs7paavns.cloudfront.net\"], totalExecutionTime: 3757012, totalOccurrences: 4362 }, { name: \"Edge Web Fonts\", company: \"Adobe Systems\", category: \"cdn\", domains: [\"*.edgefonts.net\"], examples: [\"use.edgefonts.net\"] }, { name: \"Edition Digital\", category: \"ad\", domains: [\"*.editiondigital.com\"] }, { name: \"Edot Web Technologies\", category: \"hosting\", domains: [\"*.edot.co.za\"] }, { name: \"Effective Measure\", category: \"\\\nad\", domains: [\"*.effectivemeasure.net\"], totalExecutionTime: 17, totalOccurrences: 1 }, { name: \"Effiliation sa\", category: \"ad\", domains: [\"*.effiliation.com\"], totalExecutionTime: 108, totalOccurrences: 3 }, { name: \"Ekm Systems\", category: \"analytics\", domains: [\"*.ekmsecure.com\", \"*.ekmpinpoint.co.uk\"], examples: [\"globalstats.ekmsecure.com\"], totalExecutionTime: 67875, totalOccurrences: 789 }, { name: \"Elastera\", category: \"hosting\", domains: [\"*.elastera.net\"] }, { name: \"Elastic Ad\", category: \"ad\", domains: [\"*.elasticad.net\"], totalExecutionTime: 30225, totalOccurrences: 137 }, { name: \"Elastic Load Balancing\", company: \"Amazon Web Services\", category: \"hosting\", domains: [\"*.105app.com\"], examples: [\"rhpury.105app.com\", \"rhxtd.105app.com\"] }, { name: \"Elecard StreamEye\", company: \"Elecard\", category: \"other\", domains: [\"*.streameye.net\"] }, { name: \"Elevate\", company: \"Elevate Technology Solutions\", category: \"utility\", domains: [\"*.elevaate.technology\"] }, { name: \"Elicit\",\n    category: \"utility\", domains: [\"*.elicitapp.com\"] }, { name: \"Elogia\", category: \"ad\", domains: [\"*.elogia.net\"] }, { name: \"Email Attitude\", company: \"1000mercis\", category: \"ad\", domains: [\"*.email-attitude.com\"] }, { name: \"EmailCenter\", category: \"ad\", domains: [\"*.emailcenteruk.com\"] }, { name: \"Embedly\", category: \"content\", domains: [\"*.embedly.com\", \"*.embed.ly\"], totalExecutionTime: 5014487, totalOccurrences: 10836 }, { name: \"EmpathyBroker Site Search\", company: \"EmpathyBroker\", category: \"utility\", domains: [\"*.empathybroker.com\"] }, { name: \"Enfusen\", category: \"analytics\", domains: [\"*.enfusen.com\"] }, { name: \"Engadget\", company: \"Engadget (AOL)\", category: \"content\", domains: [\"*.gdgt.com\"], examples: [\"media.gdgt.com\"] }, { name: \"Engagio\", category: \"marketing\", domains: [\"*.engagio.com\"] }, { name: \"Ensighten Manage\", company: \"Ensighten\", category: \"tag-manager\", domains: [\"*.levexis.com\"] }, { name: \"EntityLink\", category: \"other\", domains: [\"*.entitytag.co.uk\"] },\n    { name: \"Entrust Datacard\", category: \"utility\", domains: [\"*.entrust.com\", \"*.entrust.net\"], examples: [\"ocsp.entrust.com\", \"ocsp.entrust.net\"], totalExecutionTime: 14041, totalOccurrences: 3 }, { name: \"Equiniti\", category: \"utility\", domains: [\"*.equiniti.com\"] }, { name: \"Errorception\", category: \"utility\", domains: [\"*.errorception.com\"] }, { name: \"Esri ArcGIS\", company: \"Esri\", category: \"utility\", domains: [\"*.arcgis.com\", \"*.arcgisonline.com\"], totalExecutionTime: 21967746, totalOccurrences: 3432 }, { name: \"Ethnio\", category: \"analytics\", domains: [\"*.ethn.io\"] }, { name: \"Eulerian Technologies\", category: \"ad\", domains: [\"*.eolcdn.com\"] }, { name: \"Euroland\", category: \"utility\", domains: [\"*.euroland.com\"], totalExecutionTime: 1, totalOccurrences: 3 }, { name: \"European Interactive Digital ad Alli\", category: \"utility\", domains: [\"*.edaa.eu\"] }, { name: \"Eventbrite\", category: \"hosting\", domains: [\"*.evbuc.com\", \"*.eventbrite.co.uk\"], totalExecutionTime: 4667, totalOccurrences: 33 },\n    { name: \"Everflow\", category: \"analytics\", domains: [\"*.tp88trk.com\"], examples: [\"www.tp88trk.com\"], totalExecutionTime: 110842, totalOccurrences: 185 }, { name: \"Evergage\", category: \"analytics\", domains: [\"*.evergage.com\", \"*.evgnet.com\"], examples: [\"cdn.evgnet.com\"], totalExecutionTime: 1095634, totalOccurrences: 2491 }, { name: \"Everquote\", category: \"content\", domains: [\"*.evq1.com\"] }, { name: \"Everyday Health\", category: \"ad\", domains: [\"*.agoramedia.com\"] }, { name: \"Evidon\", category: \"analytics\", domains: [\"*.evidon.com\"], totalExecutionTime: 1260409, totalOccurrences: 2482 }, { name: \"Evolve Media\", category: \"content\", domains: [\"*.evolvemediallc.com\"] }, { name: \"Exactag\", category: \"ad\", domains: [\"*.exactag.com\"], totalExecutionTime: 662, totalOccurrences: 6 }, { name: \"ExoClick\", category: \"ad\", domains: [\"*.exoclick.com\"], totalExecutionTime: 69348, totalOccurrences: 568 }, { name: \"Expedia\", category: \"content\", domains: [\"*.travel-assets.com\", \"*.trvl-media.com\",\n    \"*.trvl-px.com\", \"*.uciservice.com\"], examples: [\"www.trvl-px.com\", \"www.uciservice.com\"], totalExecutionTime: 15443, totalOccurrences: 15 }, { name: \"Expedia Australia\", company: \"Expedia\", category: \"content\", domains: [\"*.expedia.com.au\"], examples: [\"www.expedia.com.au\"] }, { name: \"Expedia Canada\", company: \"Expedia\", category: \"content\", domains: [\"*.expedia.ca\"], examples: [\"www.expedia.ca\"] }, { name: \"Expedia France\", company: \"Expedia\", category: \"content\", domains: [\"*.expedia.fr\"], examples: [\"www.expedia.fr\"] }, { name: \"Expedia Germany\", company: \"Expedia\", category: \"content\", domains: [\"*.expedia.de\"], examples: [\"www.expedia.de\"] }, { name: \"Expedia Italy\", company: \"Expedia\", category: \"content\", domains: [\"*.expedia.it\"], examples: [\"www.expedia.it\"] }, { name: \"Expedia Japan\", company: \"Expedia\", category: \"content\", domains: [\"*.expedia.co.jp\"], examples: [\"www.expedia.co.jp\"] }, { name: \"Expedia USA\", company: \"Expedia\", category: \"content\", domains: [\"*.exped\\\nia.com\"], examples: [\"www.expedia.com\"], totalExecutionTime: 40062, totalOccurrences: 19 }, { name: \"Expedia United Kingdom\", company: \"Expedia\", category: \"content\", domains: [\"*.expedia.co.uk\"], examples: [\"www.expedia.co.uk\"] }, { name: \"Experian\", category: \"utility\", domains: [\"*.audienceiq.com\", \"*.experian.com\", \"*.experianmarketingservices.digital\"] }, { name: \"Experian Cross-Channel Marketing Platform\", company: \"Experian\", category: \"marketing\", domains: [\"*.eccmp.com\", \"*.ccmp.eu\"], totalExecutionTime: 1268, totalOccurrences: 24 }, { name: \"Exponea\", category: \"analytics\", domains: [\"*.exponea.com\"], totalExecutionTime: 154832, totalOccurrences: 1303 }, { name: \"Exponential Interactive\", category: \"ad\", domains: [\"*.exponential.com\"], totalExecutionTime: 5179, totalOccurrences: 120 }, { name: \"Extensis WebInk\", category: \"cdn\", domains: [\"*.webink.com\"] }, { name: \"Extole\", category: \"ad\", domains: [\"*.extole.com\", \"*.extole.io\"], examples: [\"origin.extole.io\"], totalExecutionTime: 21067,\n    totalOccurrences: 44 }, { name: \"Ey-Seren\", category: \"analytics\", domains: [\"*.webabacus.com\"] }, { name: \"EyeView\", category: \"ad\", domains: [\"*.eyeviewads.com\"] }, { name: \"Eyeota\", category: \"ad\", domains: [\"*.eyeota.net\"], totalExecutionTime: 152570, totalOccurrences: 1827 }, { name: \"Ezakus Pretargeting\", company: \"Ezakus\", category: \"ad\", domains: [\"*.ezakus.net\"] }, { name: \"Ezoic\", category: \"analytics\", domains: [\"*.ezoic.net\"], totalExecutionTime: 93024, totalOccurrences: 173 }, { name: \"FLXone\", company: \"Teradata\", category: \"ad\", domains: [\"*.pangolin.blue\", \"*.flx1.com\", \"d2hlpp31teaww3.cloudfront.net\", \"*.flxpxl.com\"], totalExecutionTime: 25037, totalOccurrences: 67 }, { name: \"Fairfax Media\", category: \"content\", domains: [\"ads.fairfax.com.au\", \"resources.fairfax.com.au\"] }, { name: \"Fairfax Media Analtics\", company: \"Fairfax Media\", category: \"analytics\", domains: [\"analytics.fairfax.com.au\"] }, { name: \"Falk Technologies\", category: \"ad\", domains: [\"*.angsrvr.com\"] },\n    { name: \"Fanplayr\", category: \"analytics\", domains: [\"*.fanplayr.com\", \"d38nbbai6u794i.cloudfront.net\"], totalExecutionTime: 69669, totalOccurrences: 154 }, { name: \"Fast Thinking\", company: \"NE Marketing\", category: \"marketing\", domains: [\"*.fast-thinking.co.uk\"] }, { name: \"Fastest Forward\", category: \"analytics\", domains: [\"*.gaug.es\"], totalExecutionTime: 13583, totalOccurrences: 261 }, { name: \"Fastly\", category: \"utility\", domains: [\"*.fastly.net\"], totalExecutionTime: 21362072, totalOccurrences: 9582 }, { name: \"Feedbackify\", company: \"InsideMetrics\", category: \"analytics\", domains: [\"*.feedbackify.com\"], totalExecutionTime: 42808, totalOccurrences: 173 }, { name: \"Feefo.com\", company: \"Feefo\", category: \"analytics\", domains: [\"*.feefo.com\"], totalExecutionTime: 1362284, totalOccurrences: 2025 }, { name: \"Fidelity Media\", category: \"ad\", domains: [\"*.fidelity-media.com\"], examples: [\"x.fidelity-media.com\"] }, { name: \"Filestack\", category: \"content\", domains: [\"*.filepicker.\\\nio\"], examples: [\"api.filepicker.io\", \"dialog.filepicker.io\", \"www.filepicker.io\"], totalExecutionTime: 27297, totalOccurrences: 200 }, { name: \"Finsbury Media\", category: \"ad\", domains: [\"*.finsburymedia.com\"], totalExecutionTime: 3470, totalOccurrences: 12 }, { name: \"Firepush\", category: \"utility\", domains: [\"*.firepush.io\"] }, { name: \"FirstImpression\", category: \"ad\", domains: [\"*.firstimpression.io\"], totalExecutionTime: 141056, totalOccurrences: 107 }, { name: \"Fit Analytics\", category: \"other\", domains: [\"*.fitanalytics.com\"], examples: [\"integrations.fitanalytics.com\", \"widget.fitanalytics.com\", \"metrics.fitanalytics.com\"] }, { name: \"Fits Me\", category: \"analytics\", domains: [\"*.fits.me\"] }, { name: \"Fivetran\", category: \"analytics\", domains: [\"*.fivetran.com\"], totalExecutionTime: 2922, totalOccurrences: 3 }, { name: \"FlexShopper\", category: \"utility\", domains: [\"*.flexshopper.com\"] }, { name: \"Flickr\", category: \"content\", domains: [\"*.flickr.com\", \"*.staticflickr.com\"], totalExecutionTime: 262262,\n    totalOccurrences: 524 }, { name: \"Flipboard\", category: \"social\", domains: [\"*.flipboard.com\"], totalExecutionTime: 50049, totalOccurrences: 41 }, { name: \"Flipdesk\", category: \"customer-success\", homepage: \"https://flipdesk.jp/\", domains: [\"*.flipdesk.jp\"], examples: [\"api.flipdesk.jp\"], totalExecutionTime: 322297, totalOccurrences: 411 }, { name: \"Flipp\", category: \"analytics\", domains: [\"*.wishabi.com\", \"d2e0sxz09bo7k2.cloudfront.net\", \"*.wishabi.net\"] }, { name: \"Flite\", category: \"ad\", domains: [\"*.flite.com\"] }, { name: \"Flixmedia\", category: \"analytics\", domains: [\"*.flix360.com\", \"*.flixcar.com\", \"*.flixfacts.com\", \"*.flixsyndication.net\", \"*.flixfacts.co.uk\"], totalExecutionTime: 32827, totalOccurrences: 19 }, { name: \"Flockler\", category: \"ad\", domains: [\"*.flockler.com\"], totalExecutionTime: 504051, totalOccurrences: 1297 }, { name: \"Flowplayer\", category: \"content\", domains: [\"*.flowplayer.org\"], totalExecutionTime: 218859, totalOccurrences: 862 }, { name: \"Flowzymes Ky\",\n    category: \"cdn\", domains: [\"*.jquerytools.org\"] }, { name: \"Fomo\", category: \"ad\", domains: [\"*.notifyapp.io\"] }, { name: \"Fonecall\", category: \"analytics\", domains: [\"*.web-call-analytics.com\"] }, { name: \"Fontdeck\", category: \"cdn\", domains: [\"*.fontdeck.com\"] }, { name: \"Foodity Technologies\", category: \"ad\", domains: [\"*.foodity.com\"] }, { name: \"Force24\", category: \"ad\", domains: [\"*.force24.co.uk\"], totalExecutionTime: 10225, totalOccurrences: 112 }, { name: \"ForeSee\", company: \"Answers\", category: \"analytics\", domains: [\"*.4seeresults.com\", \"*.answerscloud.com\", \"*.foresee.com\", \"*.foreseeresults.com\"], totalExecutionTime: 179704, totalOccurrences: 266 }, { name: \"Forensiq\", category: \"utility\", domains: [\"*.fqtag.com\"], totalExecutionTime: 21937, totalOccurrences: 171 }, { name: \"Fort Awesome\", category: \"cdn\", domains: [\"*.fortawesome.com\"], totalExecutionTime: 652365, totalOccurrences: 3635 }, { name: \"Forter\", category: \"utility\", domains: [\"*.forter.com\"], totalExecutionTime: 6578955,\n    totalOccurrences: 6930 }, { name: \"Forward Internet Group\", category: \"hosting\", domains: [\"*.f3d.io\"] }, { name: \"Forward3D\", category: \"ad\", domains: [\"*.forward3d.com\"] }, { name: \"Fospha\", category: \"analytics\", domains: [\"*.fospha.com\"], examples: [\"router.fospha.com\"] }, { name: \"Foursixty\", category: \"customer-success\", domains: [\"*.foursixty.com\"] }, { name: \"FoxyCart\", category: \"utility\", domains: [\"*.foxycart.com\"], totalExecutionTime: 361777, totalOccurrences: 669 }, { name: \"Fraudlogix\", category: \"utility\", domains: [\"*.yabidos.com\"], totalExecutionTime: 47637, totalOccurrences: 357 }, { name: \"FreakOut\", category: \"ad\", domains: [\"*.fout.jp\"], totalExecutionTime: 114328, totalOccurrences: 2036 }, { name: \"Freespee\", category: \"customer-success\", domains: [\"*.freespee.com\"], examples: [\"analytics.freespee.com\"], totalExecutionTime: 67626, totalOccurrences: 484 }, { name: \"Freetobook\", category: \"content\", domains: [\"*.freetobook.com\"], examples: [\"www.freetobook.com\"],\n    totalExecutionTime: 297146, totalOccurrences: 649 }, { name: \"Fresh 8 Gaming\", category: \"ad\", domains: [\"*.fresh8.co\"], totalExecutionTime: 319849, totalOccurrences: 76 }, { name: \"Fresh Relevance\", category: \"analytics\", domains: [\"*.freshrelevance.com\", \"*.cloudfront.ne\", \"d1y9qtn9cuc3xw.cloudfront.net\", \"d81mfvml8p5ml.cloudfront.net\", \"dkpklk99llpj0.cloudfront.net\"], examples: [\"d1y9qtn9cuc3xw.cloudfront.ne\"], totalExecutionTime: 91181, totalOccurrences: 300 }, { name: \"Friendbuy\", category: \"ad\", domains: [\"*.friendbuy.com\", \"djnf6e5yyirys.cloudfront.net\"], totalExecutionTime: 17783, totalOccurrences: 150 }, { name: \"Frienefit\", category: \"ad\", domains: [\"*.frienefit.com\"] }, { name: \"FuelX\", category: \"ad\", domains: [\"*.fuelx.com\"] }, { name: \"Full Circle Studies\", category: \"analytics\", domains: [\"*.securestudies.com\"] }, { name: \"FullStory\", category: \"analytics\", domains: [\"*.fullstory.com\"], examples: [\"rs.fullstory.com\"], totalExecutionTime: 11575233, totalOccurrences: 14687 },\n    { name: \"Fyber\", category: \"ad\", domains: [\"*.fyber.com\"] }, { name: \"G-Forces Web Management\", category: \"hosting\", domains: [\"*.gforcesinternal.co.uk\"] }, { name: \"G4 Native\", company: \"Gravity4\", category: \"ad\", domains: [\"*.triggit.com\"] }, { name: \"GET ME IN!  (TicketMaster)\", category: \"content\", domains: [\"*.getmein.com\"] }, { name: \"GIPHY\", category: \"content\", domains: [\"*.giphy.com\"], totalExecutionTime: 4831, totalOccurrences: 6 }, { name: \"GainCloud\", company: \"GainCloud Systems\", category: \"other\", domains: [\"*.egaincloud.net\"] }, { name: \"Gath Adams\", category: \"content\", domains: [\"*.iwantthatflight.com.au\"] }, { name: \"Gecko Tribe\", category: \"social\", domains: [\"*.geckotribe.com\"] }, { name: \"Gemius\", category: \"ad\", domains: [\"*.gemius.pl\"], totalExecutionTime: 2964756, totalOccurrences: 15596 }, { name: \"Genesis Media\", category: \"ad\", domains: [\"*.bzgint.com\", \"*.genesismedia.com\", \"*.genesismediaus.com\"] }, { name: \"Genie Ventures\", category: \"ad\", domains: [\"*\\\n.genieventures.co.uk\"] }, { name: \"Geniee\", category: \"ad\", domains: [\"*.href.asia\", \"*.genieessp.jp\", \"*.genieesspv.jp\", \"*.gssprt.jp\"], examples: [\"cs.gssprt.jp\"], totalExecutionTime: 16956055, totalOccurrences: 16354 }, { name: \"Geniuslink\", category: \"analytics\", domains: [\"*.geni.us\"], totalExecutionTime: 897, totalOccurrences: 3 }, { name: \"GeoRiot\", category: \"other\", domains: [\"*.georiot.com\"] }, { name: \"GeoTrust\", category: \"utility\", domains: [\"*.geotrust.com\"], totalExecutionTime: 3300, totalOccurrences: 2 }, { name: \"Geoplugin\", category: \"utility\", domains: [\"*.geoplugin.com\", \"*.geoplugin.net\"], totalExecutionTime: 119, totalOccurrences: 3 }, { name: \"Georeferencer\", company: \"Klokan Technologies\", category: \"utility\", domains: [\"*.georeferencer.com\"] }, { name: \"GetIntent RTBSuite\", company: \"GetIntent\", category: \"ad\", domains: [\"*.adhigh.net\"], totalExecutionTime: 2768, totalOccurrences: 356 }, { name: \"GetResponse\", category: \"ad\", domains: [\"*.getresponse.com\"], totalExecutionTime: 209076,\n    totalOccurrences: 1019 }, { name: \"GetSiteControl\", company: \"GetWebCraft\", category: \"utility\", domains: [\"*.getsitecontrol.com\"], totalExecutionTime: 1739288, totalOccurrences: 3146 }, { name: \"GetSocial\", category: \"social\", domains: [\"*.getsocial.io\"], totalExecutionTime: 1204, totalOccurrences: 11 }, { name: \"Getty Images\", category: \"content\", domains: [\"*.gettyimages.com\", \"*.gettyimages.co.uk\"], examples: [\"www.gettyimages.com\"], totalExecutionTime: 17939, totalOccurrences: 65 }, { name: \"Gfycat\", company: \"Gycat\", category: \"utility\", domains: [\"*.gfycat.com\"] }, { name: \"Ghostery Enterprise\", company: \"Ghostery\", category: \"marketing\", domains: [\"*.betrad.com\"], totalExecutionTime: 1129, totalOccurrences: 26 }, { name: \"Giant Media\", category: \"ad\", domains: [\"*.videostat.com\"] }, { name: \"Gigya\", category: \"analytics\", domains: [\"*.gigya.com\"], totalExecutionTime: 2692493, totalOccurrences: 1995 }, { name: \"GitHub\", category: \"utility\", domains: [\"*.github.com\", \"*.githu\\\nbusercontent.com\", \"*.github.io\", \"*.rawgit.com\"], examples: [\"raw.githubusercontent.com\", \"cdn.rawgit.com\"], totalExecutionTime: 7126491, totalOccurrences: 14675 }, { name: \"Gladly\", company: \"Gladly\", homepage: \"https://www.gladly.com/\", category: \"customer-success\", domains: [\"*.gladly.com\"], examples: [\"cdn.gladly.com\"], totalExecutionTime: 240417, totalOccurrences: 381 }, { name: \"Glassdoor\", category: \"content\", domains: [\"*.glassdoor.com\"], totalExecutionTime: 68877, totalOccurrences: 19 }, { name: \"Gleam\", category: \"marketing\", domains: [\"*.gleam.io\"], totalExecutionTime: 43249, totalOccurrences: 221 }, { name: \"Global Digital Markets\", category: \"ad\", domains: [\"*.gdmdigital.com\"] }, { name: \"Global-e\", category: \"hosting\", domains: [\"*.global-e.com\"], totalExecutionTime: 706185, totalOccurrences: 1314 }, { name: \"GlobalSign\", category: \"utility\", domains: [\"*.globalsign.com\", \"*.globalsign.net\"], totalExecutionTime: 11228, totalOccurrences: 48 }, { name: \"GlobalWebIndex\", category: \"\\\nanalytics\", domains: [\"*.globalwebindex.net\"] }, { name: \"Globase International\", category: \"ad\", domains: [\"*.globase.com\"] }, { name: \"GoDataFeed\", category: \"other\", domains: [\"*.godatafeed.com\"] }, { name: \"Google APIs\", company: \"Google\", category: \"utility\", domains: [\"googleapis.com\"] }, { name: \"Google Ad Block Detection\", company: \"Google\", category: \"ad\", domains: [\"*.0emn.com\", \"*.0fmm.com\"] }, { name: \"Google Analytics Experiments\", company: \"Google\", category: \"analytics\", domains: [\"*.gexperiments1.com\"] }, { name: \"Google DoubleClick Ad Exchange\", company: \"Google\", category: \"ad\", domains: [\"*.admeld.com\"] }, { name: \"Google IPV6 Metrics\", company: \"Google\", category: \"analytics\", domains: [\"*.ipv6test.net\"] }, { name: \"Google Plus\", company: \"Google\", category: \"social\", domains: [\"plus.google.com\"], totalExecutionTime: 49945, totalOccurrences: 442 }, { name: \"Google Trusted Stores\", company: \"Google\", category: \"utility\", domains: [\"*.googlecommerce.com\"], totalExecutionTime: 218,\n    totalOccurrences: 5 }, { name: \"Google Video\", company: \"Google\", category: \"content\", domains: [\"*.googlevideo.com\"], totalExecutionTime: 4, totalOccurrences: 3 }, { name: \"Google reCAPTCHA\", company: \"Google\", category: \"utility\", domains: [\"*.recaptcha.net\"], examples: [\"api.recaptcha.net\"], totalExecutionTime: 8694396, totalOccurrences: 25662 }, { name: \"GovMetric\", company: \"ROL Solutions\", category: \"analytics\", domains: [\"*.govmetric.com\"], totalExecutionTime: 233, totalOccurrences: 6 }, { name: \"Granify\", category: \"analytics\", domains: [\"*.granify.com\"], totalExecutionTime: 19211, totalOccurrences: 24 }, { name: \"Grapeshot\", category: \"ad\", domains: [\"*.gscontxt.net\", \"*.grapeshot.co.uk\"], totalExecutionTime: 4945, totalOccurrences: 4 }, { name: \"Gravity (AOL)\", category: \"analytics\", domains: [\"*.grvcdn.com\"] }, { name: \"Groovy Gecko\", category: \"content\", domains: [\"*.ggwebcast.com\", \"*.groovygecko.net\"] }, { name: \"GroupM\", category: \"ad\", domains: [\"*.qservz.com\"] }, {\n    name: \"Guardian Media\", category: \"ad\", domains: [\"*.theguardian.com\", \"*.guardian.co.uk\"], examples: [\"oas.theguardian.com\"] }, { name: \"GumGum\", category: \"ad\", domains: [\"*.gumgum.com\"], totalExecutionTime: 3440651, totalOccurrences: 167535 }, { name: \"Gumtree\", category: \"content\", domains: [\"*.gumtree.com\"] }, { name: \"H264 Codec\", company: \"Cisco\", category: \"other\", domains: [\"*.openh264.org\"] }, { name: \"HERE\", category: \"analytics\", domains: [\"*.medio.com\"] }, { name: \"HP Optimost\", company: \"Hewlett-Packard Development Company\", category: \"marketing\", domains: [\"*.hp.com\", \"d2uncb19xzxhzx.cloudfront.net\"], examples: [\"by.marketinghub.hp.com\", \"marketinghub.hp.com\"], totalExecutionTime: 420577, totalOccurrences: 100 }, { name: \"Has Offers\", company: \"TUNE\", category: \"ad\", domains: [\"*.go2cloud.org\"], totalExecutionTime: 0, totalOccurrences: 3 }, { name: \"Hawk Search\", category: \"utility\", domains: [\"*.hawksearch.com\"], totalExecutionTime: 15097, totalOccurrences: 132 }, {\n    name: \"Haymarket Media Group\", category: \"content\", domains: [\"*.brandrepublic.com\", \"*.hbpl.co.uk\"] }, { name: \"Heap\", category: \"analytics\", domains: [\"*.heapanalytics.com\"], totalExecutionTime: 5187800, totalOccurrences: 12078 }, { name: \"Hearst Communications\", category: \"content\", domains: [\"*.h-cdn.co\", \"*.hearstdigital.com\", \"*.hearstlabs.com\", \"*.hearst.io\", \"*.cdnds.net\"] }, { name: \"Heatmap\", category: \"analytics\", domains: [\"*.heatmap.it\"], totalExecutionTime: 7337, totalOccurrences: 141 }, { name: \"Heroku\", category: \"other\", domains: [\"*.herokuapp.com\"], totalExecutionTime: 12602535, totalOccurrences: 14119 }, { name: \"Hexton\", category: \"utility\", domains: [\"*.hextom.com\"], totalExecutionTime: 10806589, totalOccurrences: 24738 }, { name: \"Hibernia Networks\", category: \"utility\", domains: [\"*.hiberniacdn.com\"] }, { name: \"High Impact Media\", category: \"ad\", domains: [\"*.reactx.com\"] }, { name: \"Highcharts\", category: \"utility\", domains: [\"*.highcharts.com\"], totalExecutionTime: 746540,\n    totalOccurrences: 3181 }, { name: \"Highwinds\", category: \"utility\", domains: [\"*.hwcdn.net\"] }, { name: \"HitsLink\", category: \"analytics\", domains: [\"*.hitslink.com\"], totalExecutionTime: 1452, totalOccurrences: 29 }, { name: \"Hola Networks\", category: \"other\", domains: [\"*.h-cdn.com\"], totalExecutionTime: 83024, totalOccurrences: 42 }, { name: \"Hootsuite\", category: \"analytics\", domains: [\"*.hootsuite.com\"] }, { name: \"HotUKDeals\", category: \"analytics\", domains: [\"*.hotukdeals.com\"] }, { name: \"HotWords\", company: \"Media Response Group\", category: \"ad\", domains: [\"*.hotwords.com.br\"] }, { name: \"HotelsCombined\", category: \"content\", domains: [\"*.datahc.com\"], totalExecutionTime: 81, totalOccurrences: 2 }, { name: \"Hoverr\", category: \"ad\", domains: [\"*.hoverr.media\"] }, { name: \"Hull.js\", category: \"utility\", domains: [\"*.hull.io\", \"*.hullapp.io\"] }, { name: \"Hupso Website Analyzer\", company: \"Hupso\", category: \"analytics\", domains: [\"*.hupso.com\"], totalExecutionTime: 20892, totalOccurrences: 248 },\n    { name: \"I-Behavior\", company: \"WPP\", category: \"ad\", domains: [\"*.ib-ibi.com\"], totalExecutionTime: 23, totalOccurrences: 35 }, { name: \"i-mobile\", company: \"i-mobile\", category: \"ad\", domains: [\"*.i-mobile.co.jp\"], examples: [\"ssp-sync.i-mobile.co.jp\"], totalExecutionTime: 3701005, totalOccurrences: 16595 }, { name: \"IBM Digital Analytics\", company: \"IBM\", category: \"analytics\", domains: [\"*.cmcore.com\", \"coremetrics.com\", \"data.coremetrics.com\", \"data.de.coremetrics.com\", \"libs.de.coremetrics.com\", \"tmscdn.de.coremetrics.com\", \"iocdn.coremetrics.com\", \"libs.coremetrics.com\", \"tmscdn.coremetrics.com\", \"*.s81c.com\", \"*.unica.com\", \"*.coremetrics.eu\"], examples: [\"data.coremetrics.eu\"], totalExecutionTime: 126790, totalOccurrences: 169 }, { name: \"IBM Digital Data Exchange\", company: \"IBM\", category: \"tag-manager\", domains: [\"tagmanager.coremetrics.com\"] }, { name: \"IBM Tealeaf\", company: \"IBM\", category: \"analytics\", domains: [\"*.ibmcloud.com\"], examples: [\"uscollector.tealeaf.ibm\\\ncloud.com\"] }, { name: \"IBM Acoustic Campaign\", company: \"IBM\", category: \"analytics\", domains: [\"www.sc.pages01.net\", \"www.sc.pages02.net\", \"www.sc.pages03.net\", \"www.sc.pages04.net\", \"www.sc.pages05.net\", \"www.sc.pages06.net\", \"www.sc.pages07.net\", \"www.sc.pages08.net\", \"www.sc.pages09.net\", \"www.sc.pagesA.net\"], examples: [\"https://www.sc.pages01.net/lp/static/js/iMAWebCookie.js\"], totalExecutionTime: 51361, totalOccurrences: 417 }, { name: \"ICF Technology\", category: \"content\", domains: [\"*.camads.net\"] }, { name: \"IFDNRG\", category: \"hosting\", domains: [\"*.ifdnrg.com\"] }, { name: \"IMRG\", category: \"analytics\", domains: [\"*.peermap.com\", \"*.imrg.org\"], examples: [\"benchmarking.imrg.org\"] }, { name: \"IPONWEB\", category: \"ad\", domains: [\"*.company-target.com\", \"*.liadm.com\", \"*.iponweb.net\", \"*.p161.net\"], examples: [\"pool.udsp.iponweb.net\"], totalExecutionTime: 8924906, totalOccurrences: 39154 }, { name: \"IQ Mobile\", category: \"utility\", domains: [\"*.iqm.cc\"] }, { name: \"IS Group\", category: \"\\\nhosting\", domains: [\"*.creative-serving.com\"], totalExecutionTime: 2127, totalOccurrences: 29 }, { name: \"IT Dienstleistungen Tim Prinzkosky\", category: \"utility\", domains: [\"*.flaticons.net\"] }, { name: \"IXI Digital\", company: \"Equifax\", category: \"ad\", domains: [\"*.ixiaa.com\"] }, { name: \"IcoMoon\", category: \"cdn\", domains: [\"d19ayerf5ehaab.cloudfront.net\", \"d1azc1qln24ryf.cloudfront.net\"], totalExecutionTime: 54286, totalOccurrences: 180 }, { name: \"IdenTrust\", category: \"utility\", domains: [\"*.identrust.com\"], totalExecutionTime: 2334, totalOccurrences: 1 }, { name: \"Ido\", category: \"customer-success\", domains: [\"*.idio.co\"], totalExecutionTime: 2222, totalOccurrences: 12 }, { name: \"Ignition One\", category: \"marketing\", domains: [\"*.searchignite.com\"] }, { name: \"ImageShack\", category: \"content\", domains: [\"*.yfrog.com\"] }, { name: \"Imagen Studio\", category: \"utility\", domains: [\"*.telephonesky.com\"] }, { name: \"Imagini Holdings\", category: \"ad\", domains: [\"*.vdna-assets.com\"] }, {\n    name: \"Img Safe\", category: \"content\", domains: [\"*.imgsafe.org\"] }, { name: \"Imgur\", category: \"utility\", domains: [\"*.imgur.com\"], totalExecutionTime: 3538, totalOccurrences: 30 }, { name: \"Impact Radius\", category: \"ad\", domains: [\"*.impactradius-event.com\", \"*.impactradius-go.com\", \"*.7eer.net\", \"d3cxv97fi8q177.cloudfront.net\", \"*.evyy.net\", \"*.ojrq.net\", \"utt.impactcdn.com\", \"*.sjv.io\"], examples: [\"a.impactradius-go.com\", \"microsoft-uk.evyy.net\"], totalExecutionTime: 612310, totalOccurrences: 4274 }, { name: \"Improve Digital\", category: \"ad\", domains: [\"*.360yield.com\"], totalExecutionTime: 28784, totalOccurrences: 732 }, { name: \"Improvely\", category: \"analytics\", domains: [\"*.iljmp.com\"], totalExecutionTime: 129, totalOccurrences: 3 }, { name: \"InMobi\", category: \"ad\", domains: [\"*.inmobi.com\"], totalExecutionTime: 24607375, totalOccurrences: 126087 }, { name: \"InSkin Media\", category: \"ad\", domains: [\"*.inskinad.com\", \"*.inskinmedia.com\"] }, { name: \"Inbenta\", category: \"c\\\nustomer-success\", domains: [\"*.inbenta.com\"], totalExecutionTime: 3923, totalOccurrences: 7 }, { name: \"Incisive Media\", category: \"content\", domains: [\"*.incisivemedia.com\"] }, { name: \"Indeed\", category: \"content\", domains: [\"*.indeed.com\"], totalExecutionTime: 81347, totalOccurrences: 55 }, { name: \"Index Exchange\", company: \"WPP\", category: \"ad\", domains: [\"*.casalemedia.com\", \"*.indexww.com\"], totalExecutionTime: 892351, totalOccurrences: 32324 }, { name: \"Indoona\", category: \"other\", domains: [\"*.indoona.com\"] }, { name: \"Infectious Media\", category: \"ad\", domains: [\"*.impdesk.com\", \"*.impressiondesk.com\", \"*.inmz.net\"] }, { name: \"Inference Mobile\", category: \"ad\", domains: [\"*.inferencemobile.com\"] }, { name: \"Infinity Tracking\", category: \"analytics\", domains: [\"*.infinity-tracking.net\"], totalExecutionTime: 24308, totalOccurrences: 250 }, { name: \"Infoline\", category: \"analytics\", domains: [\"*.ioam.de\"], totalExecutionTime: 8983, totalOccurrences: 95 }, { name: \"Infolinks\", category: \"\\\nad\", domains: [\"*.infolinks.com\"], totalExecutionTime: 7995389, totalOccurrences: 5950 }, { name: \"Infopark\", category: \"hosting\", domains: [\"*.scrvt.com\"] }, { name: \"Infusionsoft\", category: \"ad\", domains: [\"*.infusionsoft.com\"], totalExecutionTime: 345182, totalOccurrences: 723 }, { name: \"Ink\", category: \"ad\", domains: [\"*.inktad.com\"] }, { name: \"Inktel Contact Center Solutions\", company: \"Inktel\", category: \"customer-success\", domains: [\"*.inktel.com\"] }, { name: \"Inneractive\", category: \"ad\", domains: [\"*.inner-active.mobi\"] }, { name: \"Innovid\", category: \"ad\", homepage: \"https://www.innovid.com/\", domains: [\"*.innovid.com\"], examples: [\"ag.innovid.com\", \"rtr.innovid.com\"], totalExecutionTime: 115267, totalOccurrences: 1363 }, { name: \"Insight Express\", category: \"analytics\", domains: [\"*.insightexpressai.com\"], totalExecutionTime: 1, totalOccurrences: 2 }, { name: \"Insipio\", category: \"other\", domains: [\"*.insipio.com\"] }, { name: \"Inspectlet\", category: \"analytics\", domains: [\n    \"*.inspectlet.com\"], totalExecutionTime: 7622183, totalOccurrences: 5346 }, { name: \"Instansive\", category: \"utility\", domains: [\"*.instansive.com\"] }, { name: \"Instart\", homepage: \"https://www.instart.com/\", category: \"utility\", domains: [\"*.insnw.net\"] }, { name: \"Instembedder\", category: \"content\", domains: [\"*.instaembedder.com\"] }, { name: \"Instinctive\", category: \"ad\", domains: [\"*.instinctiveads.com\"] }, { name: \"Intelligent Reach\", category: \"ad\", domains: [\"*.ist-track.com\"] }, { name: \"Intent HQ\", category: \"analytics\", domains: [\"*.intenthq.com\"] }, { name: \"Intent IQ\", category: \"ad\", domains: [\"*.intentiq.com\"], totalExecutionTime: 48447, totalOccurrences: 1146 }, { name: \"Intercept Interactive\", category: \"ad\", domains: [\"*.undertone.com\"], totalExecutionTime: 2293921, totalOccurrences: 21012 }, { name: \"Interest Graph\", company: \"AOL\", category: \"ad\", domains: [\"*.gravity.com\"] }, { name: \"Internet Brands\", category: \"content\", domains: [\"*.ibpxl.com\"] }, { name: \"In\\\nterpublic Group\", category: \"ad\", domains: [\"*.mbww.com\"] }, { name: \"Interstate\", category: \"analytics\", domains: [\"*.interstateanalytics.com\"] }, { name: \"Interview\", category: \"analytics\", domains: [\"*.efm.me\"] }, { name: \"Intilery\", category: \"customer-success\", domains: [\"*.intilery-analytics.com\"] }, { name: \"Investis\", category: \"utility\", domains: [\"*.investis.com\"], totalExecutionTime: 244162, totalOccurrences: 282 }, { name: \"Investis Flife\", category: \"hosting\", domains: [\"*.quartalflife.com\"] }, { name: \"Invodo\", category: \"ad\", domains: [\"*.invodo.com\"], examples: [\"e.invodo.com\"] }, { name: \"iSite\", category: \"analytics\", domains: [\"*.isitetv.com\"], examples: [\"static.isitetv.com\", \"events.isitetv.com\"] }, { name: \"Issue\", category: \"content\", domains: [\"*.issue.by\"] }, { name: \"J.D. Williams & Co\", category: \"content\", domains: [\"*.drct2u.com\"] }, { name: \"Janrain\", category: \"analytics\", domains: [\"*.janrain.com\", \"*.janrainbackplane.com\", \"*.rpxnow.com\", \"d3hmp0045zy3c\\\ns.cloudfront.net\"], totalExecutionTime: 4006, totalOccurrences: 21 }, { name: \"Jellyfish\", category: \"ad\", domains: [\"*.jellyfish.net\"] }, { name: \"JetStream\", category: \"content\", domains: [\"*.xlcdn.com\"] }, { name: \"JingDong\", category: \"content\", domains: [\"*.3.com\", \"*.jd.com\"], totalExecutionTime: 119043, totalOccurrences: 84 }, { name: \"Jivox\", category: \"ad\", domains: [\"*.jivox.com\"], totalExecutionTime: 31166, totalOccurrences: 65 }, { name: \"Jobvite\", category: \"content\", domains: [\"*.jobvite.com\"], totalExecutionTime: 6667, totalOccurrences: 4 }, { name: \"Johnston Press\", category: \"content\", domains: [\"*.johnstonpress.co.uk\", \"*.jpress.co.uk\"] }, { name: \"Join the Dots (Research)\", category: \"social\", domains: [\"*.jtdiscuss.com\"] }, { name: \"JotForm\", category: \"utility\", domains: [\"*.jotformpro.com\"] }, { name: \"JuicyAds\", category: \"ad\", domains: [\"*.juicyads.com\"], totalExecutionTime: 543292, totalOccurrences: 2092 }, { name: \"JustPremium\", category: \"ad\", domains: [\"*.ne\\\nt.net\"], examples: [\"d2nvliyzbo36lk.cloudfrontd2nvliyzbo36lk.cloudfront.net.net\"] }, { name: \"JustPremium Ads\", company: \"JustPremium\", category: \"ad\", domains: [\"*.justpremium.com\"], totalExecutionTime: 1061, totalOccurrences: 35 }, { name: \"JustUno\", category: \"ad\", domains: [\"*.justuno.com\", \"d2j3qa5nc37287.cloudfront.net\"], totalExecutionTime: 773949, totalOccurrences: 1448 }, { name: \"KINX (Korea Internet Neutral eXchange)\", category: \"other\", domains: [\"*.kinxcdn.com\"], totalExecutionTime: 1433, totalOccurrences: 4 }, { name: \"KISSmetrics\", category: \"analytics\", domains: [\"*.kissmetrics.com\", \"doug1izaerwt3.cloudfront.net\", \"dsyszv14g9ymi.cloudfront.net\"], totalExecutionTime: 3896, totalOccurrences: 46 }, { name: \"Kaizen Platform\", category: \"analytics\", domains: [\"*.kaizenplatform.net\"], examples: [\"cdn.kaizenplatform.net\", \"log-v4.kaizenplatform.net\"], totalExecutionTime: 85284, totalOccurrences: 183 }, { name: \"Kakao\", category: \"social\", domains: [\"*.daum.net\", \"*.daumcdn.ne\\\nt\"], totalExecutionTime: 38351047, totalOccurrences: 62730 }, { name: \"Kaltura Video Platform\", company: \"Kaltura\", category: \"content\", domains: [\"*.kaltura.com\"], examples: [\"cdnsecakmi.kaltura.com\"], totalExecutionTime: 2164237, totalOccurrences: 1017 }, { name: \"Kameleoon\", homepage: \"https://www.kameleoon.com/\", category: \"analytics\", domains: [\"*.kameleoon.com\", \"*.kameleoon.eu\", \"*.kameleoon.io\"], examples: [\"data.kameleoon.io\", \"kdm3fpv6il.kameleoon.eu\"], totalExecutionTime: 2217218, totalOccurrences: 2337 }, { name: \"Kampyle\", category: \"analytics\", domains: [\"*.kampyle.com\"], totalExecutionTime: 413304, totalOccurrences: 702 }, { name: \"Kantar\", category: \"analytics\", domains: [\"*.sesamestats.com\"] }, { name: \"Kargo\", category: \"marketing\", domains: [\"*.kargo.com\"], totalExecutionTime: 48285, totalOccurrences: 1135 }, { name: \"KARTE\", company: \"Plaid\", homepage: \"https://karte.io/\", category: \"marketing\", domains: [\"*.karte.io\"], examples: [\"static.karte.io\", \"t.karte.io\"], totalExecutionTime: 1712123,\n    totalOccurrences: 1729 }, { name: \"Kauli\", category: \"ad\", domains: [\"*.kau.li\"] }, { name: \"Keen\", company: \"Keen\", homepage: \"https://keen.io/\", category: \"analytics\", domains: [\"*.keen.io\", \"d26b395fwzu5fz.cloudfront.net\"], totalExecutionTime: 24210, totalOccurrences: 416 }, { name: \"Kelkoo\", category: \"hosting\", domains: [\"*.kelkoo.com\"] }, { name: \"Kenshoo\", category: \"marketing\", domains: [\"*.xg4ken.com\"], totalExecutionTime: 710, totalOccurrences: 18 }, { name: \"Key CDN\", category: \"utility\", domains: [\"*.kxcdn.com\"], totalExecutionTime: 4814875, totalOccurrences: 10025 }, { name: \"Keynote\", company: \"Dynatrace\", category: \"analytics\", domains: [\"*.keynote.com\"] }, { name: \"Keywee\", category: \"ad\", domains: [\"*.keywee.co\"], totalExecutionTime: 44984, totalOccurrences: 259 }, { name: \"Kiosked\", category: \"ad\", domains: [\"*.kiosked.com\"], totalExecutionTime: 343355, totalOccurrences: 173 }, { name: \"Klarna\", category: \"utility\", domains: [\"*.klarna.com\"], totalExecutionTime: 1374032,\n    totalOccurrences: 10759 }, { name: \"Klaviyo\", category: \"ad\", domains: [\"*.klaviyo.com\"], totalExecutionTime: 113130218, totalOccurrences: 161289 }, { name: \"Klevu Search\", company: \"Klevu\", category: \"utility\", domains: [\"*.klevu.com\"], totalExecutionTime: 1124647, totalOccurrences: 1463 }, { name: \"Klick2Contact\", category: \"customer-success\", domains: [\"*.klick2contact.com\"] }, { name: \"Knight Lab\", company: \"Northwestern University\", category: \"utility\", domains: [\"*.knightlab.com\"], totalExecutionTime: 350550, totalOccurrences: 448 }, { name: \"Kodajo\", category: \"other\", domains: [\"*.kodajo.com\"] }, { name: \"Komoona\", category: \"ad\", domains: [\"*.komoona.com\"] }, { name: \"Korrelate\", company: \"JD Power\", category: \"analytics\", domains: [\"*.korrelate.net\"] }, { name: \"LKQD\", category: \"ad\", domains: [\"*.lkqd.net\"] }, { name: \"Layer0\", category: \"cdn\", domains: [\"*.layer0.co\"], examples: [\"rum.layer0.co\"] }, { name: \"Layershift\", category: \"hosting\", domains: [\"109.109.138.174\"] },\n    { name: \"Lead Forensics\", category: \"ad\", domains: [\"*.200summit.com\", \"*.baw5tracker.com\", \"*.business-path-55.com\", \"*.bux1le001.com\", \"*.central-core-7.com\", \"*.direct-azr-78.com\", \"*.explore-123.com\", \"*.forensics1000.com\", \"*.gldsta-02-or.com\", \"*.green-bloc9.com\", \"*.lansrv040.com\", \"*.lead-123.com\", \"*.leadforensics.com\", \"*.mavic852.com\", \"*.mon-com-net.com\", \"*.peak-ip-54.com\", \"*.snta0034.com\", \"*.svr-prc-01.com\", \"*.syntace-094.com\", \"*.tghbn12.com\", \"*.trail-web.com\", \"*.web-01-gbl.com\", \"*.web-cntr-07.com\", \"*.trackdiscovery.net\"], examples: [\"www.baw5tracker.com\", \"www.lansrv040.com\", \"www.mon-com-net.com\", \"www.peak-ip-54.com\", \"www.tghbn12.com\", \"www.web-01-gbl.com\"], totalExecutionTime: 45938, totalOccurrences: 307 }, { name: \"Lead Intelligence\", company: \"Magnetise Solutions\", category: \"ad\", domains: [\"*.leadintelligence.co.uk\"] }, { name: \"LeadLander\", category: \"analytics\", domains: [\"*.formalyzer.com\", \"*.trackalyzer.com\"] }, { name: \"Leaflet\", category: \"util\\\nity\", domains: [\"*.leafletjs.com\"], totalExecutionTime: 3668, totalOccurrences: 69 }, { name: \"LeasdBoxer\", company: \"LeadBoxer\", category: \"ad\", domains: [\"*.leadboxer.com\"], totalExecutionTime: 15328, totalOccurrences: 118 }, { name: \"LeaseWeb\", homepage: \"https://www.leaseweb.com/\", category: \"cdn\", domains: [\"*.lswcdn.net\", \"*.leasewebcdn.com\"] }, { name: \"Leboncoin\", category: \"content\", domains: [\"*.leboncoin.fr\"] }, { name: \"Lengow\", category: \"hosting\", domains: [\"*.lengow.com\"] }, { name: \"Lessbuttons\", category: \"social\", domains: [\"*.lessbuttons.com\"] }, { name: \"Letter Press\", category: \"ad\", domains: [\"*.getletterpress.com\"] }, { name: \"Level 3 Communications\", category: \"utility\", domains: [\"footprint.net\"] }, { name: \"Level3\", category: \"other\", domains: [\"secure.footprint.net\"] }, { name: \"Lifestreet Media\", category: \"social\", domains: [\"*.lfstmedia.com\"] }, { name: \"LiftSuggest\", category: \"analytics\", domains: [\"d2blwevgjs7yom.cloudfront.net\"] }, { name: \"Ligatus\", category: \"\\\nad\", domains: [\"*.ligadx.com\"] }, { name: \"LightStep\", category: \"analytics\", domains: [\"*.lightstep.com\"] }, { name: \"LightWidget\", category: \"utility\", domains: [\"*.lightwidget.com\"], totalExecutionTime: 1825559, totalOccurrences: 9383 }, { name: \"Likelihood\", company: \"LIkeihood\", category: \"hosting\", domains: [\"*.likelihood.com\"], examples: [\"client.likelihood.com\"] }, { name: \"LikeShop\", company: \"Dash Hudson\", category: \"content\", domains: [\"likeshop.me\"], examples: [\"likeshop.me\"] }, { name: \"LINE Corporation\", category: \"ad\", domains: [\"*.line-scdn.net\", \"*.line.me\"], examples: [\"d.line-scdn.net\", \"tr.line.me\"], totalExecutionTime: 3858282, totalOccurrences: 26881 }, { name: \"Linkcious\", category: \"analytics\", domains: [\"*.linkcious.com\"] }, { name: \"Linking Mobile\", category: \"ad\", domains: [\"*.linkingmobile.com\"] }, { name: \"LittleData\", category: \"analytics\", homepage: \"https://www.littledata.io/\", domains: [\"*.littledata.io\"], examples: [\"transactions.littledata.io\"], totalExecutionTime: 832,\n    totalOccurrences: 1 }, { name: \"LiveBurst\", category: \"ad\", domains: [\"*.liveburst.com\"] }, { name: \"LiveClicker\", category: \"ad\", domains: [\"*.liveclicker.net\"] }, { name: \"LiveHelpNow\", category: \"customer-success\", domains: [\"*.livehelpnow.net\"], totalExecutionTime: 284671, totalOccurrences: 819 }, { name: \"LiveInternet\", category: \"analytics\", domains: [\"*.yadro.ru\"] }, { name: \"LiveJournal\", category: \"social\", domains: [\"*.livejournal.com\", \"*.livejournal.net\"], totalExecutionTime: 63532309, totalOccurrences: 9109 }, { name: \"LivePerson\", category: \"customer-success\", homepage: \"https://www.liveperson.com/\", domains: [\"*.liveperson.com\", \"*.look.io\", \"*.liveperson.net\", \"*.lpsnmedia.net\"], totalExecutionTime: 1930619, totalOccurrences: 2544 }, { name: \"LiveRail\", company: \"Facebook\", category: \"ad\", domains: [\"*.liverail.com\", \"*.lrcdn.net\"], examples: [\"scontent.lrcdn.net\"] }, { name: \"LiveTex\", category: \"customer-success\", domains: [\"*.livetex.ru\"], totalExecutionTime: 476954,\n    totalOccurrences: 1911 }, { name: \"Livefyre\", category: \"content\", domains: [\"*.fyre.co\", \"*.livefyre.com\"] }, { name: \"Living Map Company\", category: \"utility\", domains: [\"*.livingmap.com\"] }, { name: \"Local World\", category: \"content\", domains: [\"*.thelocalpeople.co.uk\"] }, { name: \"LockerDome\", category: \"analytics\", domains: [\"*.lockerdome.com\"], totalExecutionTime: 244, totalOccurrences: 3 }, { name: \"Logentries\", company: \"Rapid\", category: \"utility\", domains: [\"*.logentries.com\"], examples: [\"js.logentries.com\"] }, { name: \"Logicalis\", category: \"analytics\", domains: [\"*.trovus.co.uk\"] }, { name: \"LoginRadius\", company: \"LoginRadius\", homepage: \"https://www.loginradius.com/\", category: \"ad\", domains: [\"*.loginradius.com\", \"*.lrcontent.com\"], examples: [\"config.lrcontent.com\"], totalExecutionTime: 15746, totalOccurrences: 131 }, { name: \"LongTail Ad Solutions\", category: \"ad\", domains: [\"*.jwpcdn.com\", \"*.jwplatform.com\", \"*.jwplayer.com\", \"*.jwpltx.com\", \"*.jwpsrv.com\", \"*.l\\\nongtailvideo.com\"], totalExecutionTime: 4531393, totalOccurrences: 5572 }, { name: \"Loop Commerce\", category: \"other\", domains: [\"*.loopassets.net\"] }, { name: \"Loop11\", category: \"analytics\", domains: [\"*.loop11.com\"], totalExecutionTime: 22278, totalOccurrences: 28 }, { name: \"LoopMe\", category: \"ad\", domains: [\"*.loopme.biz\", \"*.loopme.com\", \"*.vntsm.com\", \"*.loopme.me\"], totalExecutionTime: 2112781, totalOccurrences: 11752 }, { name: \"Looper\", category: \"content\", domains: [\"*.looper.com\"] }, { name: \"Loyalty Point\", category: \"ad\", domains: [\"*.loyaltypoint.pl\"] }, { name: \"LoyaltyLion\", category: \"ad\", domains: [\"*.loyaltylion.com\", \"*.loyaltylion.net\", \"dg1f2pfrgjxdq.cloudfront.net\"], totalExecutionTime: 2971522, totalOccurrences: 4114 }, { name: \"Luma Tag\", category: \"analytics\", domains: [\"*.lumatag.co.uk\"] }, { name: \"Lumesse\", category: \"content\", domains: [\"*.recruitmentplatform.com\"] }, { name: \"Luminate\", category: \"ad\", domains: [\"*.luminate.com\"] }, { name: \"Lynchpin An\\\nalytics\", category: \"analytics\", domains: [\"*.lypn.net\"] }, { name: \"Lyris\", category: \"ad\", domains: [\"*.clicktracks.com\"] }, { name: \"Lytics\", category: \"ad\", domains: [\"*.lytics.io\"], totalExecutionTime: 272463, totalOccurrences: 857 }, { name: \"MEC WebTrack\", company: \"MEC\", category: \"ad\", domains: [\"*.e-webtrack.net\"] }, { name: \"MECLABS Institute\", category: \"analytics\", domains: [\"*.meclabs.com\", \"*.meclabsdata.com\"] }, { name: \"MLveda\", category: \"utility\", domains: [\"*.mlveda.com\"], examples: [\"www.mlveda.com\"], totalExecutionTime: 109345, totalOccurrences: 229 }, { name: \"Macromill\", company: \"Macromill\", category: \"analytics\", homepage: \"https://group.macromill.com/\", domains: [\"*.macromill.com\"], examples: [\"img.macromill.com/js/us000131vfg/4000000570-56/lognos.js\"], totalExecutionTime: 5731, totalOccurrences: 9 }, { name: \"Macropod BugHerd\", company: \"Macropod\", category: \"utility\", domains: [\"*.bugherd.com\"], examples: [\"www.bugherd.com\"], totalExecutionTime: 512091, totalOccurrences: 3523 },\n    { name: \"Madison Logic\", category: \"marketing\", domains: [\"*.ml314.com\"], totalExecutionTime: 101, totalOccurrences: 3 }, { name: \"Madmetrics\", company: \"Keyade\", category: \"analytics\", domains: [\"*.keyade.com\"] }, { name: \"Magnetic\", category: \"ad\", domains: [\"*.domdex.com\", \"d3ezl4ajpp2zy8.cloudfront.net\"] }, { name: \"Magnetic Platform\", company: \"Magnetic\", category: \"ad\", domains: [\"*.magnetic.is\"] }, { name: \"MailMunch\", category: \"ad\", domains: [\"*.mailmunch.co\"], totalExecutionTime: 1414543, totalOccurrences: 19969 }, { name: \"MailPlus\", category: \"ad\", domains: [\"*.mailplus.nl\"], totalExecutionTime: 83524, totalOccurrences: 304 }, { name: \"Mapbox\", category: \"utility\", domains: [\"*.mapbox.com\"], totalExecutionTime: 13815633, totalOccurrences: 19555 }, { name: \"Maptive\", category: \"utility\", domains: [\"*.maptive.com\"] }, { name: \"Marcaria.com\", category: \"other\", domains: [\"*.gooo.al\"] }, { name: \"Marchex\", category: \"analytics\", domains: [\"*.voicestar.com\", \"*.marchex.io\"],\n    totalExecutionTime: 1378181, totalOccurrences: 7390 }, { name: \"Mark and Mini\", category: \"ad\", domains: [\"*.markandmini.com\"], examples: [\"www.markandmini.com\"] }, { name: \"Marker\", category: \"utility\", domains: [\"*.marker.io\"], examples: [\"edge.marker.io\"], totalExecutionTime: 2331726, totalOccurrences: 1722 }, { name: \"Marketing Dashboards\", company: \"GroupM\", category: \"analytics\", domains: [\"*.m-decision.com\"] }, { name: \"Marketizator\", category: \"analytics\", domains: [\"*.marketizator.com\"] }, { name: \"Marketplace Web Service\", company: \"Amazon\", category: \"other\", domains: [\"*.ssl-images-amazon.com\"], totalExecutionTime: 234709, totalOccurrences: 451 }, { name: \"Mashable\", category: \"social\", domains: [\"*.mshcdn.com\"] }, { name: \"MatchWork\", category: \"utility\", domains: [\"*.matchwork.com\"] }, { name: \"MathJax\", category: \"utility\", domains: [\"*.mathjax.org\"], totalExecutionTime: 84751, totalOccurrences: 743 }, { name: \"Mather Economics\", category: \"analytics\", domains: [\"*.m\\\natheranalytics.com\"], totalExecutionTime: 262501, totalOccurrences: 507 }, { name: \"MaxCDN Enterprise\", company: \"MaxCDN\", category: \"utility\", domains: [\"*.netdna-cdn.com\", \"*.netdna-ssl.com\"] }, { name: \"MaxMind\", category: \"utility\", domains: [\"*.maxmind.com\"], totalExecutionTime: 855332, totalOccurrences: 831 }, { name: \"MaxPoint Interactive\", category: \"ad\", domains: [\"*.mxptint.net\"], totalExecutionTime: 20140, totalOccurrences: 23834 }, { name: \"Maxsi\", category: \"analytics\", domains: [\"*.evisitanalyst.com\"] }, { name: \"Maxymiser\", category: \"analytics\", domains: [\"*.maxymiser.net, maxymiser.hs.llnwd.net\"] }, { name: \"McAffee\", category: \"utility\", domains: [\"*.mcafeesecure.com\", \"*.scanalert.com\"] }, { name: \"Measured\", category: \"analytics\", domains: [\"*.measured.com\"], examples: [\"tag.measured.com\"], homepage: \"https://www.measured.com/\" }, { name: \"Media IQ\", category: \"analytics\", domains: [\"*.mediaiqdigital.com\"] }, { name: \"Media Management Technologies\", category: \"ad\", domains: [\n    \"*.speedshiftmedia.com\"], totalExecutionTime: 27147, totalOccurrences: 161 }, { name: \"Media Temple\", category: \"hosting\", domains: [\"*.goodlayers2.com\"] }, { name: \"Mediabong\", category: \"ad\", domains: [\"*.mediabong.net\"] }, { name: \"Mediahawk\", category: \"analytics\", domains: [\"*.mediahawk.co.uk\"], totalExecutionTime: 51393, totalOccurrences: 239 }, { name: \"Mediahub\", category: \"ad\", domains: [\"*.hubverifyandoptimize.com\", \"*.projectwatchtower.com\"] }, { name: \"Mediasyndicator\", category: \"ad\", domains: [\"*.creativesyndicator.com\"] }, { name: \"Medium\", category: \"content\", domains: [\"*.medium.com\"], totalExecutionTime: 216923262, totalOccurrences: 17027 }, { name: \"Meetrics\", category: \"ad\", domains: [\"*.de.com\", \"*.meetrics.net\", \"*.mxcdn.net\"], examples: [\"research.de.com\"], totalExecutionTime: 102809, totalOccurrences: 63 }, { name: \"Mega\", company: \"Mega Information Technology\", category: \"other\", domains: [\"*.mgcdn.com\"] }, { name: \"Melt\", category: \"ad\", domains: [\"*.meltd\\\nsp.com\", \"*.mesp.com\"] }, { name: \"Meltwater Group\", category: \"customer-success\", domains: [\"*.meltwaternews.com\"] }, { name: \"Meme\", category: \"ad\", domains: [\"*.viewwonder.com\"] }, { name: \"MentAd\", category: \"ad\", domains: [\"*.mentad.com\"] }, { name: \"Mention Me\", category: \"ad\", domains: [\"*.mention-me.com\"], examples: [\"tag.mention-me.com\"], totalExecutionTime: 15233, totalOccurrences: 44 }, { name: \"Merchant Equipment Store\", category: \"utility\", domains: [\"*.merchantequip.com\"], totalExecutionTime: 268, totalOccurrences: 1 }, { name: \"Merchenta\", category: \"customer-success\", domains: [\"*.merchenta.com\"] }, { name: \"Merkle Digital Data Exchange\", company: \"Merkle\", category: \"ad\", domains: [\"*.brilig.com\"] }, { name: \"Merkle Paid Search\", company: \"Merkle\", category: \"ad\", domains: [\"*.rkdms.com\"], totalExecutionTime: 69291, totalOccurrences: 407 }, { name: \"Met Office\", category: \"content\", domains: [\"*.metoffice.gov.uk\"], totalExecutionTime: 15029, totalOccurrences: 19 }, { name: \"\\\nMeta Broadcast\", category: \"social\", domains: [\"*.metabroadcast.com\"], examples: [\"voila.metabroadcast.com\"] }, { name: \"Michael Associates\", category: \"ad\", domains: [\"*.checktestsite.com\"], examples: [\"www.checktestsite.com\"] }, { name: \"Michelin\", category: \"content\", domains: [\"*.viamichelin.com\"], totalExecutionTime: 8087, totalOccurrences: 7 }, { name: \"Microad\", category: \"ad\", domains: [\"*.microad.jp\"], totalExecutionTime: 14626755, totalOccurrences: 23909 }, { name: \"Microsoft Certificate Services\", company: \"Microsoft\", category: \"utility\", domains: [\"*.msocsp.com\"] }, { name: \"Microsoft Hosted Libs\", company: \"Microsoft\", category: \"cdn\", domains: [\"*.aspnetcdn.com\"], examples: [\"ajax.aspnetcdn.com\"], totalExecutionTime: 4562478, totalOccurrences: 20042 }, { name: \"Microsoft XBox Live\", company: \"Microsoft\", category: \"marketing\", domains: [\"*.xboxlive.com\"] }, { name: \"Mightypop\", category: \"ad\", domains: [\"*.mightypop.ca\"] }, { name: \"Mika Tuupola\", category: \"utility\", domains: [\n    \"*.appelsiini.net\"] }, { name: \"Millennial Media\", category: \"ad\", domains: [\"*.jumptap.com\"] }, { name: \"Mirror Image Internet\", category: \"utility\", domains: [\"*.miisolutions.net\"] }, { name: \"Mobify\", category: \"utility\", domains: [\"*.mobify.com\", \"*.mobify.net\"] }, { name: \"Mobile Nations\", category: \"social\", domains: [\"*.mobilenations.com\"] }, { name: \"Mobivate\", category: \"ad\", domains: [\"*.mobivatebulksms.com\"] }, { name: \"Momondo\", category: \"content\", domains: [\"*.momondo.dk\"] }, { name: \"Momondo Group\", category: \"content\", domains: [\"*.momondogrouo.com\", \"*.momondogroup.com\"] }, { name: \"Monarch Ads\", category: \"ad\", domains: [\"*.monarchads.com\"] }, { name: \"Monetate\", category: \"analytics\", domains: [\"*.monetate.net\"], totalExecutionTime: 260345, totalOccurrences: 599 }, { name: \"MonetizeMore\", category: \"ad\", domains: [\"*.m2.ai\"], totalExecutionTime: 8896, totalOccurrences: 47 }, { name: \"Monitor\", company: \"Econda\", category: \"analytics\", domains: [\"*.econda-monitor.\\\nde\"], examples: [\"www.econda-monitor.de\"] }, { name: \"Monkey Frog Media\", category: \"content\", domains: [\"*.monkeyfrogmedia.com\"] }, { name: \"Monotype\", category: \"cdn\", domains: [\"*.fonts.com\", \"*.fonts.net\"], totalExecutionTime: 729465, totalOccurrences: 3185 }, { name: \"Moore-Wilson\", category: \"ad\", domains: [\"*.mwdev.co.uk\"] }, { name: \"Moovweb\", category: \"utility\", domains: [\"*.moovweb.net\"] }, { name: \"Mopinion\", category: \"analytics\", domains: [\"*.mopinion.com\"], totalExecutionTime: 171681, totalOccurrences: 177 }, { name: \"MotionPoint\", category: \"other\", domains: [\"*.convertlanguage.com\"], totalExecutionTime: 1843, totalOccurrences: 35 }, { name: \"Mouse3K\", category: \"analytics\", domains: [\"*.mouse3k.com\"] }, { name: \"MouseStats\", category: \"analytics\", domains: [\"*.mousestats.com\"] }, { name: \"Mouseflow\", homepage: \"https://mouseflow.com/\", category: \"analytics\", domains: [\"*.mouseflow.com\"], totalExecutionTime: 331345, totalOccurrences: 6786 }, { name: \"Movable Ink\", category: \"\\\nanalytics\", domains: [\"*.micpn.com\"], totalExecutionTime: 439979, totalOccurrences: 4949 }, { name: \"MovingIMAGE24\", category: \"content\", domains: [\"*.edge-cdn.net\"] }, { name: \"Moxielinks\", category: \"ad\", domains: [\"*.moxielinks.com\"] }, { name: \"Moz Recommended Companies\", company: \"Moz\", category: \"analytics\", domains: [\"d2eeipcrcdle6.cloudfront.net\"] }, { name: \"Mozilla\", category: \"utility\", domains: [\"*.mozilla.org\"], examples: [\"aus5.mozilla.org\"], totalExecutionTime: 21085, totalOccurrences: 32 }, { name: \"Multiview\", category: \"content\", domains: [\"*.multiview.com\", \"*.track-mv.com\"], totalExecutionTime: 8831, totalOccurrences: 58 }, { name: \"Mux\", category: \"analytics\", domains: [\"*.litix.io\"], totalExecutionTime: 91580, totalOccurrences: 249 }, { name: \"MyAds\", company: \"MyBuys\", category: \"analytics\", domains: [\"*.veruta.com\"] }, { name: \"MyBuys\", category: \"analytics\", domains: [\"*.mybuys.com\"] }, { name: \"MyFonts\", category: \"cdn\", domains: [\"*.myfonts.net\"], totalExecutionTime: 78,\n    totalOccurrences: 4 }, { name: \"MyRegistry\", category: \"other\", domains: [\"*.myregistry.com\"], totalExecutionTime: 164086, totalOccurrences: 621 }, { name: \"MySpace\", company: \"Specific Media\", category: \"social\", domains: [\"*.myspace.com\"] }, { name: \"Mynewsdesk\", category: \"utility\", domains: [\"*.mynewsdesk.com\"], totalExecutionTime: 564, totalOccurrences: 31 }, { name: \"NAVIS\", category: \"content\", domains: [\"*.navistechnologies.info\"] }, { name: \"NCC Group Real User Monitoring\", company: \"NCC Group\", category: \"analytics\", domains: [\"*.nccgroup-webperf.com\"], examples: [\"beacon-rumlive.rum.nccgroup-webperf.com\", \"config-rumlive.rum.nccgroup-webperf.com\", \"script-rumlive.rum.nccgroup-webperf.com\"] }, { name: \"NEORY Marketing Cloud\", company: \"NEORY\", category: \"marketing\", domains: [\"*.ad-srv.net\"], totalExecutionTime: 10976, totalOccurrences: 240 }, { name: \"Nanigans\", category: \"ad\", domains: [\"*.nanigans.com\"] }, { name: \"Nano Interactive\", category: \"ad\", domains: [\"*.audien\\\ncemanager.de\"], totalExecutionTime: 780, totalOccurrences: 10 }, { name: \"Nanorep\", company: \"Nanorep Technologies\", category: \"customer-success\", domains: [\"*.nanorep.com\"] }, { name: \"Narrative\", category: \"ad\", domains: [\"*.narrative.io\"], totalExecutionTime: 1228, totalOccurrences: 2 }, { name: \"Native Ads\", category: \"ad\", domains: [\"*.nativeads.com\"] }, { name: \"Nativo\", category: \"ad\", domains: [\"*.postrelease.com\"], totalExecutionTime: 28260, totalOccurrences: 35852 }, { name: \"Navegg\", category: \"ad\", domains: [\"*.navdmp.com\"], totalExecutionTime: 51915, totalOccurrences: 805 }, { name: \"NaviStone\", category: \"ad\", domains: [\"*.murdoog.com\"] }, { name: \"Naytev\", category: \"analytics\", domains: [\"*.naytev.com\"] }, { name: \"Needle\", category: \"analytics\", domains: [\"*.needle.com\"] }, { name: \"Neiman Marcus\", category: \"content\", domains: [\"*.ctscdn.com\"] }, { name: \"Nend\", category: \"ad\", domains: [\"*.nend.net\"] }, { name: \"Neodata\", category: \"ad\", domains: [\"*.neodatagroup.com\"],\n    totalExecutionTime: 12827, totalOccurrences: 86 }, { name: \"Net Applications\", category: \"analytics\", domains: [\"*.hitsprocessor.com\"] }, { name: \"Net Reviews\", category: \"analytics\", domains: [\"*.avis-verifies.com\"], examples: [\"www.avis-verifies.com\"], totalExecutionTime: 1143140, totalOccurrences: 2442 }, { name: \"NetAffiliation\", company: \"Kwanco\", category: \"ad\", domains: [\"*.metaffiliation.com\"], totalExecutionTime: 18519, totalOccurrences: 127 }, { name: \"NetDirector\", company: \"G-Forces Web Management\", category: \"other\", domains: [\"*.netdirector.co.uk\"], totalExecutionTime: 3931, totalOccurrences: 1 }, { name: \"NetFlix\", category: \"content\", domains: [\"*.nflxext.com\", \"*.nflximg.net\"], totalExecutionTime: 4364, totalOccurrences: 5 }, { name: \"Nielsen NetRatings SiteCensus\", company: \"The Nielsen Company\", homepage: \"http://www.nielsen-online.com/intlpage.html\", category: \"analytics\", domains: [\"*.imrworldwide.com\"], totalExecutionTime: 6840006, totalOccurrences: 19525 }, {\n    name: \"NetSeer\", category: \"ad\", domains: [\"*.netseer.com\", \"*.ns-cdn.com\"] }, { name: \"NetShelter\", company: \"Ziff Davis Tech\", category: \"ad\", domains: [\"*.netshelter.net\"] }, { name: \"Netmining\", company: \"Ignition One\", category: \"ad\", domains: [\"*.netmng.com\"], totalExecutionTime: 7746, totalOccurrences: 92 }, { name: \"Netop\", category: \"customer-success\", domains: [\"*.netop.com\"] }, { name: \"Network Solutions\", category: \"utility\", domains: [\"*.netsolssl.com\", \"*.networksolutions.com\"], examples: [\"ocsp.netsolssl.com\"], totalExecutionTime: 2415, totalOccurrences: 2 }, { name: \"Neustar AdAdvisor\", company: \"Neustar\", category: \"ad\", domains: [\"*.adadvisor.net\"] }, { name: \"New Approach Media\", category: \"ad\", domains: [\"*.newapproachmedia.co.uk\"] }, { name: \"NewShareCounts\", category: \"social\", domains: [\"*.newsharecounts.com\"] }, { name: \"News\", category: \"social\", domains: [\"*.news.com.au\", \"*.newsanalytics.com.au\", \"*.newsapi.com.au\", \"*.newscdn.com.au\", \"*.newsdata.com.au\",\n    \"*.newsdiscover.com.au\", \"*.news-static.com\"], totalExecutionTime: 69261, totalOccurrences: 46 }, { name: \"Newsquest\", category: \"content\", domains: [\"*.newsquestdigital.co.uk\"] }, { name: \"Newzulu\", category: \"content\", domains: [\"*.filemobile.com\", \"*.projects.fm\"] }, { name: \"Nexcess.Net\", category: \"hosting\", domains: [\"*.nexcesscdn.net\"] }, { name: \"Nexstar Media Group\", category: \"ad\", domains: [\"*.yashi.com\"] }, { name: \"NextPerf\", company: \"Rakuten Marketing\", category: \"ad\", domains: [\"*.nxtck.com\"] }, { name: \"Nine.com.au\", company: \"Nine Digital\", category: \"content\", domains: [\"*.9msn.com.au\"] }, { name: \"NitroSell\", category: \"hosting\", domains: [\"*.nitrosell.com\"] }, { name: \"Nochex\", category: \"utility\", domains: [\"*.nochex.com\"] }, { name: \"Northern &amp; Shell Media Group\", category: \"content\", domains: [\"*.northernandshell.co.uk\"] }, { name: \"Nosto\", category: \"analytics\", domains: [\"*.nosto.com\"], totalExecutionTime: 703736, totalOccurrences: 1189 }, { name: \"Now\\\n Interact\", category: \"analytics\", domains: [\"*.nowinteract.com\"] }, { name: \"Numberly\", company: \"1000mercis\", category: \"ad\", domains: [\"*.mmtro.com\", \"*.nzaza.com\"], totalExecutionTime: 1827, totalOccurrences: 19 }, { name: \"NyaConcepts\", category: \"analytics\", domains: [\"*.xclusive.ly\"] }, { name: \"O2\", category: \"other\", domains: [\"*.o2.co.uk\"], examples: [\"servedby.o2.co.uk\"] }, { name: \"GoDaddy\", homepage: \"https://www.godaddy.com/\", category: \"utility\", domains: [\"*.godaddy.com\", \"*.wsimg.com\"], examples: [\"ocsp.godaddy.com\", \"seal.godaddy.com\"], totalExecutionTime: 94698135, totalOccurrences: 110342 }, { name: \"ObjectPlanet\", category: \"analytics\", domains: [\"*.easypolls.net\"], totalExecutionTime: 28470, totalOccurrences: 70 }, { name: \"OhMyAd\", category: \"ad\", domains: [\"*.ohmyad.co\"], examples: [\"pr.ohmyad.co\"] }, { name: \"Okas Concepts\", category: \"utility\", domains: [\"*.okasconcepts.com\"], totalExecutionTime: 1483515, totalOccurrences: 661 }, { name: \"Okta\", category: \"ana\\\nlytics\", domains: [\"*.okta.com\"], totalExecutionTime: 1464920, totalOccurrences: 3542 }, { name: \"Olapic\", category: \"content\", domains: [\"*.photorank.me\"], totalExecutionTime: 115, totalOccurrences: 2 }, { name: \"Ometria\", category: \"analytics\", domains: [\"*.ometria.com\"], totalExecutionTime: 16630, totalOccurrences: 204 }, { name: \"Omniconvert\", category: \"analytics\", domains: [\"*.omniconvert.com\", \"d2tgfbvjf3q6hn.cloudfront.net\", \"d3vbj265bmdenw.cloudfront.net\"], totalExecutionTime: 85855, totalOccurrences: 381 }, { name: \"Omniroot\", company: \"Verizon\", category: \"utility\", domains: [\"*.omniroot.com\"], examples: [\"ocsp.omniroot.com\", \"vassg142.ocsp.omniroot.com\"] }, { name: \"OnAudience\", company: \"Cloud Technologies\", category: \"ad\", domains: [\"*.onaudience.com\"] }, { name: \"OnScroll\", category: \"ad\", domains: [\"*.onscroll.com\"] }, { name: \"OnState\", category: \"ad\", domains: [\"*.onstate.co.uk\"] }, { name: \"OnYourMap\", category: \"utility\", domains: [\"*.onyourmap.com\"] }, { name: \"One\\\n by AOL\", company: \"AOL\", category: \"ad\", domains: [\"*.adtechjp.com\", \"*.adtech.de\"], totalExecutionTime: 1140, totalOccurrences: 17 }, { name: \"One by AOL:Mobile\", company: \"AOL\", category: \"ad\", domains: [\"*.nexage.com\"], examples: [\"ads.nexage.com\", \"hb.nexage.com\"] }, { name: \"OneAll\", category: \"analytics\", domains: [\"*.oneall.com\"], totalExecutionTime: 104501, totalOccurrences: 623 }, { name: \"OneSoon\", category: \"analytics\", domains: [\"*.adalyser.com\"], totalExecutionTime: 33037, totalOccurrences: 437 }, { name: \"OneTag\", category: \"ad\", domains: [\"*.onetag-sys.com\"] }, { name: \"Onet\", category: \"ad\", domains: [\"*.onet.pl\"], totalExecutionTime: 531334, totalOccurrences: 760 }, { name: \"Online Rewards\", company: \"Mastercard\", category: \"ad\", domains: [\"*.loyaltygateway.com\"] }, { name: \"Online republic\", category: \"content\", domains: [\"*.imallcdn.net\"], totalExecutionTime: 67122, totalOccurrences: 58 }, { name: \"Ooyala\", category: \"ad\", domains: [\"*.ooyala.com\"] }, { name: \"OpenT\\\nable\", company: \"Priceline Group\", category: \"content\", domains: [\"*.opentable.com\", \"*.opentable.co.uk\", \"*.toptable.co.uk\"], examples: [\"www.toptable.co.uk\"], totalExecutionTime: 412090, totalOccurrences: 4314 }, { name: \"OpenX Ad Exchange\", company: \"OpenX Technologies\", category: \"ad\", domains: [\"*.liftdna.com\"] }, { name: \"Opinion Stage\", category: \"analytics\", domains: [\"*.opinionstage.com\"], examples: [\"www.opinionstage.com\"], totalExecutionTime: 113206, totalOccurrences: 145 }, { name: \"OpinionBar\", category: \"analytics\", domains: [\"*.opinionbar.com\"] }, { name: \"Opta\", company: \"Perform Group\", category: \"content\", domains: [\"*.opta.net\"], totalExecutionTime: 302785, totalOccurrences: 272 }, { name: \"OptiMonk\", category: \"ad\", domains: [\"*.optimonk.com\"], totalExecutionTime: 10318415, totalOccurrences: 10615 }, { name: \"Optilead\", category: \"analytics\", domains: [\"*.dyn-img.com\", \"*.leadcall.co.uk\", \"*.optilead.co.uk\"] }, { name: \"Optimatic\", category: \"ad\", domains: [\"*.optim\\\natic.com\"], examples: [\"synch.optimatic.com\"] }, { name: \"Optimise Media Group\", category: \"utility\", domains: [\"*.omguk.com\"], totalExecutionTime: 6691, totalOccurrences: 41 }, { name: \"Optimost\", company: \"OpenText\", category: \"ad\", domains: [\"*.optimost.com\"] }, { name: \"Optimove\", company: \"Mobius Solutions\", category: \"analytics\", domains: [\"*.optimove.net\"], totalExecutionTime: 22679, totalOccurrences: 293 }, { name: \"Optorb\", category: \"ad\", domains: [\"*.optorb.com\"] }, { name: \"Oracle\", category: \"marketing\", domains: [\"*.custhelp.com\", \"*.eloqua.com\", \"*.en25.com\", \"*.estara.com\", \"*.instantservice.com\"], totalExecutionTime: 684920, totalOccurrences: 569 }, { name: \"Oracle Recommendations On Demand\", company: \"Oracle\", category: \"analytics\", domains: [\"*.atgsvcs.com\"], totalExecutionTime: 8696, totalOccurrences: 96 }, { name: \"Oracle Responsys\", company: \"Oracle\", category: \"marketing\", domains: [\"*.adrsp.net\", \"*.responsys.net\"] }, { name: \"Order Security-VOID\", company: \"Ord\\\ner Security\", category: \"analytics\", domains: [\"*.order-security.com\"] }, { name: \"Oriel\", category: \"ad\", domains: [\"*.oriel.io\"] }, { name: \"Outbrain\", homepage: \"https://www.outbrain.com/\", category: \"ad\", domains: [\"*.outbrain.com\", \"*.outbrainimg.com\", \"*.visualrevenue.com\"], totalExecutionTime: 3373858, totalOccurrences: 13287 }, { name: \"OverStream\", company: \"Coull\", category: \"ad\", domains: [\"*.coull.com\"], examples: [\"ex1.coull.com\"] }, { name: \"Overdrive\", category: \"content\", domains: [\"*.contentreserve.com\"] }, { name: \"Overstock\", category: \"utility\", domains: [\"*.ostkcdn.com\"] }, { name: \"OwnerIQ\", category: \"ad\", domains: [\"*.owneriq.net\"], totalExecutionTime: 305561, totalOccurrences: 2173 }, { name: \"OzCart\", category: \"utility\", domains: [\"*.ozcart.com.au\"] }, { name: \"Ozone Media\", category: \"ad\", domains: [\"*.adadyn.com\"] }, { name: \"Loqate\", company: \"Loqate\", category: \"other\", domains: [\"*.pcapredict.com\", \"*.postcodeanywhere.co.uk\"], totalExecutionTime: 136866,\n    totalOccurrences: 777 }, { name: \"PEER 1 Hosting\", category: \"hosting\", domains: [\"*.peer1.com\"] }, { name: \"PERFORM\", category: \"content\", domains: [\"*.performgroup.com\"] }, { name: \"PICnet\", category: \"hosting\", domains: [\"*.nonprofitsoapbox.com\"] }, { name: \"Pacnet\", company: \"Telstra\", category: \"other\", domains: [\"*.cdndelivery.net\"], examples: [\"682968324.r.cdndelivery.net\"] }, { name: \"Pagefair\", category: \"ad\", domains: [\"*.pagefair.com\", \"*.pagefair.net\"] }, { name: \"Pagely\", category: \"other\", domains: [\"*.optnmstr.com\"], totalExecutionTime: 99314, totalOccurrences: 487 }, { name: \"Pagesuite\", category: \"ad\", domains: [\"*.pagesuite-professional.co.uk\"], totalExecutionTime: 12, totalOccurrences: 1 }, { name: \"Pardot\", category: \"marketing\", domains: [\"*.pardot.com\"], totalExecutionTime: 73880, totalOccurrences: 550 }, { name: \"Parse.ly\", category: \"analytics\", domains: [\"*.parsely.com\", \"d1z2jf7jlzjs58.cloudfront.net\"], totalExecutionTime: 1122662, totalOccurrences: 5204 },\n    { name: \"Pay per Click\", company: \"Eysys\", category: \"ad\", domains: [\"*.eysys.com\"], examples: [\"pla27.eysys.com\"] }, { name: \"PayPal Ads\", category: \"ad\", domains: [\"*.where.com\"] }, { name: \"Peaks & Pies\", category: \"analytics\", domains: [\"*.bunchbox.co\"] }, { name: \"PebblePost\", category: \"ad\", domains: [\"*.pbbl.co\"], totalExecutionTime: 147945, totalOccurrences: 725 }, { name: \"Peerius\", category: \"analytics\", domains: [\"*.peerius.com\"] }, { name: \"Peermap\", company: \"IMRG\", category: \"analytics\", domains: [\"peermapcontent.affino.com\"] }, { name: \"Penske Media\", category: \"content\", domains: [\"*.pmc.com\"] }, { name: \"Penton\", category: \"utility\", domains: [\"*.pisces-penton.com\"] }, { name: \"Pepper\", category: \"ad\", domains: [\"*.peppercorp.com\"] }, { name: \"Perfect Audience\", company: \"Marin Software\", category: \"ad\", domains: [\"*.prfct.co\", \"*.marinsm.com\", \"*.perfectaudience.com\"], totalExecutionTime: 405, totalOccurrences: 7 }, { name: \"Perfect Market\", category: \"ad\", domains: [\n    \"*.perfectmarket.com\"] }, { name: \"Perfect Privacy\", category: \"other\", domains: [\"*.suitesmart.com\"] }, { name: \"Perform Group\", category: \"content\", domains: [\"*.performfeeds.com\", \"*.premiumtv.co.uk\"] }, { name: \"Performio\", category: \"ad\", domains: [\"*.performax.cz\"], examples: [\"ut.performax.cz\"], totalExecutionTime: 117591, totalOccurrences: 337 }, { name: \"PerimeterX Bot Defender\", company: \"PerimeterX\", category: \"utility\", domains: [\"*.perimeterx.net\", \"*.pxi.pub\"], totalExecutionTime: 172605, totalOccurrences: 68 }, { name: \"Periscope\", category: \"content\", domains: [\"*.periscope.tv\"] }, { name: \"Permutive\", category: \"ad\", domains: [\"*.permutive.com\", \"d3alqb8vzo7fun.cloudfront.net\"], totalExecutionTime: 1406714, totalOccurrences: 1124 }, { name: \"Petametrics\", category: \"analytics\", domains: [\"*.petametrics.com\"] }, { name: \"PhotoBucket\", category: \"content\", domains: [\"*.photobucket.com\"], totalExecutionTime: 2383529, totalOccurrences: 338 }, { name: \"Picreel\", category: \"\\\nanalytics\", domains: [\"*.pcrl.co\", \"*.picreel.com\"], totalExecutionTime: 45437, totalOccurrences: 300 }, { name: \"Pictela (AOL)\", category: \"analytics\", domains: [\"*.pictela.net\"] }, { name: \"PistonHeads\", category: \"social\", domains: [\"*.pistonheads.com\"] }, { name: \"Piwik\", category: \"analytics\", domains: [\"*.drtvtracker.com\", \"*.piwikpro.com\", \"*.raac33.net\"], totalExecutionTime: 2813, totalOccurrences: 32 }, { name: \"Pixalate\", category: \"utility\", domains: [\"*.adrta.com\"], totalExecutionTime: 4187, totalOccurrences: 13 }, { name: \"Pixlee\", category: \"social\", domains: [\"*.pixlee.com\"], totalExecutionTime: 137281, totalOccurrences: 341 }, { name: \"Placed\", category: \"analytics\", domains: [\"*.placed.com\"], totalExecutionTime: 691, totalOccurrences: 1 }, { name: \"Planning-inc\", category: \"analytics\", domains: [\"*.planning-inc.co.uk\"] }, { name: \"PlayAd Media Group\", category: \"ad\", domains: [\"*.youplay.se\"] }, { name: \"Playbuzz\", category: \"hosting\", domains: [\"*.playbuzz.com\"], totalExecutionTime: 58184,\n    totalOccurrences: 89 }, { name: \"Pleenq\", category: \"ad\", domains: [\"*.pleenq.com\"] }, { name: \"Plentific\", category: \"content\", domains: [\"*.plentific.com\"] }, { name: \"PluginDetect\", category: \"other\", domains: [\"dtlilztwypawv.cloudfront.net\"] }, { name: \"Po.st\", company: \"RadiumOne\", category: \"utility\", domains: [\"*.po.st\"], totalExecutionTime: 178, totalOccurrences: 3 }, { name: \"Pointpin\", category: \"utility\", domains: [\"*.pointp.in\"] }, { name: \"Pointroll (Garnett)\", category: \"ad\", domains: [\"*.pointroll.com\"] }, { name: \"Polar\", homepage: \"https://polar.me/\", category: \"ad\", domains: [\"*.polarmobile.ca\", \"*.mediaeverywhere.com\", \"*.mediavoice.com\", \"*.plrsrvcs.com\", \"*.polarcdn-engine.com\", \"*.polarcdn-meraxes.com\", \"*.polarcdn-pentos.com\", \"*.polarcdn-static.com\", \"*.polarcdn-terrax.com\", \"*.polarcdn.com\", \"*.polarmobile.com\", \"*.poweredbypolar.com\", \"*.mediaconductor.me\", \"*.polaracademy.me\"], totalExecutionTime: 66280, totalOccurrences: 223 }, { name: \"PollDaddy (Automa\\\nttic)\", category: \"ad\", domains: [\"static.polldaddy.com\", \"*.poll.fm\"], totalExecutionTime: 4752, totalOccurrences: 37 }, { name: \"Polldaddy\", company: \"Automattic\", category: \"analytics\", domains: [\"polldaddy.com\", \"*.polldaddy.com\"], totalExecutionTime: 294207, totalOccurrences: 2715 }, { name: \"Polyfill service\", company: \"Polyfill.io\", category: \"other\", domains: [\"*.polyfill.io\"] }, { name: \"MegaPopAds\", category: \"ad\", domains: [\"*.megapopads.com\"] }, { name: \"Populis\", category: \"ad\", domains: [\"*.populisengage.com\"] }, { name: \"Postimage.org\", category: \"content\", domains: [\"*.postimg.org\"] }, { name: \"PowerFront\", category: \"hosting\", domains: [\"*.inside-graph.com\"], totalExecutionTime: 220331, totalOccurrences: 370 }, { name: \"PowerReviews\", category: \"analytics\", domains: [\"*.powerreviews.com\"], totalExecutionTime: 1208993, totalOccurrences: 1324 }, { name: \"Powerlinks.com\", category: \"ad\", domains: [\"*.powerlinks.com\"] }, { name: \"Press+\", category: \"ad\", domains: [\"*.pipol\\\n.com\", \"*.ppjol.com\", \"*.ppjol.net\"] }, { name: \"PressArea\", category: \"utility\", domains: [\"*.pressarea.com\"], examples: [\"www.pressarea.com\"] }, { name: \"Pretio Interactive\", category: \"ad\", domains: [\"*.pretio.in\"] }, { name: \"Prezi\", category: \"utility\", domains: [\"*.prezi.com\"], totalExecutionTime: 72394, totalOccurrences: 79 }, { name: \"PriceGrabber\", category: \"content\", domains: [\"*.pgcdn.com\", \"*.pricegrabber.com\"] }, { name: \"PriceRunner\", category: \"content\", domains: [\"*.pricerunner.com\"], totalExecutionTime: 200, totalOccurrences: 6 }, { name: \"PrintFriendly\", category: \"utility\", domains: [\"*.printfriendly.com\"], totalExecutionTime: 39464, totalOccurrences: 381 }, { name: \"Privy\", category: \"ad\", domains: [\"*.privy.com\", \"*.privymktg.com\"], totalExecutionTime: 14992809, totalOccurrences: 18961 }, { name: \"Proclivity Media\", category: \"analytics\", domains: [\"*.pswec.com\"] }, { name: \"Profitshare\", category: \"ad\", domains: [\"*.profitshare.ro\"], totalExecutionTime: 60087, totalOccurrences: 194 },\n    { name: \"Programattik\", category: \"ad\", domains: [\"*.programattik.com\"], totalExecutionTime: 95, totalOccurrences: 9 }, { name: \"Proper Media\", category: \"content\", domains: [\"*.proper.io\"], totalExecutionTime: 253672, totalOccurrences: 109 }, { name: \"Property Week\", category: \"content\", domains: [\"*.propertyweek.com\"], examples: [\"www.propertyweek.com\"] }, { name: \"Provide Support\", category: \"customer-success\", domains: [\"*.providesupport.com\"], totalExecutionTime: 79281, totalOccurrences: 989 }, { name: \"Proweb Uk\", category: \"hosting\", domains: [\"*.proweb.net\"] }, { name: \"Proximic (ComScore)\", category: \"ad\", domains: [\"*.proximic.com\"] }, { name: \"Psyma\", category: \"ad\", domains: [\"*.psyma.com\"], totalExecutionTime: 2496, totalOccurrences: 5 }, { name: \"PubFactory\", company: \"Safari Books Online\", category: \"content\", domains: [\"*.pubfactory.com\"] }, { name: \"PubNation\", category: \"ad\", domains: [\"*.pubnation.com\"], totalExecutionTime: 625439, totalOccurrences: 132 }, { name: \"\\\nPublicidad.net\", category: \"ad\", domains: [\"*.publicidad.tv\"] }, { name: \"PublishThis\", company: \"Ultra Unlimited\", category: \"ad\", domains: [\"*.publishthis.com\"] }, { name: \"Pulse Insights\", category: \"analytics\", domains: [\"*.pulseinsights.com\"], totalExecutionTime: 5757, totalOccurrences: 53 }, { name: \"Pulsepoint\", category: \"marketing\", domains: [\"*.displaymarketplace.com\"] }, { name: \"Purch\", category: \"ad\", domains: [\"*.bestofmedia.com\", \"*.purch.com\"], examples: [\"ramp.purch.com\"] }, { name: \"Pure Chat\", category: \"customer-success\", domains: [\"*.purechat.com\"], totalExecutionTime: 1129392, totalOccurrences: 3105 }, { name: \"PushCrew\", category: \"ad\", domains: [\"*.pushcrew.com\"], totalExecutionTime: 170011, totalOccurrences: 823 }, { name: \"Q1Media\", category: \"ad\", domains: [\"*.q1media.com\", \"*.q1mediahydraplatform.com\"] }, { name: \"Qbase Software Development\", category: \"hosting\", domains: [\"*.smartwebportal.co.uk\"] }, { name: \"Qeryz\", category: \"analytics\", domains: [\"*.qery\\\nz.com\"] }, { name: \"Qode Interactive\", category: \"hosting\", domains: [\"*.qodeinteractive.com\"], totalExecutionTime: 2503828, totalOccurrences: 147 }, { name: \"Qrius\", category: \"social\", domains: [\"*.qrius.me\"] }, { name: \"Qualaroo\", category: \"analytics\", domains: [\"*.qualaroo.com\"], totalExecutionTime: 54960, totalOccurrences: 347 }, { name: \"Qualtrics\", category: \"analytics\", domains: [\"*.qualtrics.com\"], totalExecutionTime: 4907219, totalOccurrences: 7134 }, { name: \"Qubit\", company: \"Qubit\", category: \"analytics\", domains: [\"*.qubit.com\", \"*.qutics.com\", \"d3c3cq33003psk.cloudfront.net\", \"*.goqubit.com\", \"*.qubitproducts.com\"], totalExecutionTime: 50060, totalOccurrences: 43 }, { name: \"Qubit Deliver\", company: \"Qubit\", category: \"analytics\", domains: [\"d1m54pdnjzjnhe.cloudfront.net\", \"d22rutvoghj3db.cloudfront.net\", \"dd6zx4ibq538k.cloudfront.net\"] }, { name: \"QuestionPro\", category: \"analytics\", domains: [\"*.questionpro.com\"], totalExecutionTime: 60868, totalOccurrences: 152 }, { name: \"\\\nQueue-it\", category: \"other\", domains: [\"*.queue-it.net\"], totalExecutionTime: 60031, totalOccurrences: 143 }, { name: \"QuinStreet\", category: \"ad\", domains: [\"*.Quinstreet.com\", \"*.b2btechleadform.com\", \"*.qnsr.com\", \"*.qsstats.com\"], examples: [\"www.qsstats.com\"] }, { name: \"QuoVadis\", category: \"utility\", domains: [\"*.quovadisglobal.com\"] }, { name: \"Qzzr\", category: \"analytics\", domains: [\"*.movementventures.com\", \"*.qzzr.com\"], examples: [\"www.qzzr.com\"] }, { name: \"RapidAPI\", category: \"utility\", domains: [\"*.rapidapi.com\"], examples: [\"telize-v1.p.rapidapi.com\"], totalExecutionTime: 4218, totalOccurrences: 2 }, { name: \"RCS Media Group\", category: \"ad\", domains: [\"*.rcsadv.it\"] }, { name: \"REVIVVE\", category: \"ad\", domains: [\"*.revivve.com\"] }, { name: \"RSSinclude\", category: \"social\", domains: [\"*.rssinclude.com\"] }, { name: \"RTB House AdPilot\", company: \"RTB House\", category: \"ad\", domains: [\"*.erne.co\", \"*.creativecdn.com\"], totalExecutionTime: 1677125, totalOccurrences: 13287 },\n    { name: \"RTB Media\", category: \"ad\", domains: [\"*.rtb-media.me\"] }, { name: \"RUN\", category: \"ad\", domains: [\"*.runadtag.com\", \"*.rundsp.com\"] }, { name: \"Rackspace\", category: \"hosting\", domains: [\"*.rackcdn.com\", \"*.rackspacecloud.com\", \"*.raxcdn.com\", \"*.websitetestlink.com\"], totalExecutionTime: 3573460, totalOccurrences: 2624 }, { name: \"RadiumOne\", category: \"ad\", domains: [\"*.gwallet.com\", \"*.r1-cdn.net\"] }, { name: \"Rakuten DC Storm\", company: \"Rakuten\", category: \"analytics\", domains: [\"*.dc-storm.com\", \"*.h4k5.com\", \"*.stormiq.com\"] }, { name: \"Rakuten LinkShare\", company: \"Rakuten\", category: \"ad\", domains: [\"*.linksynergy.com\"], totalExecutionTime: 23285, totalOccurrences: 151 }, { name: \"Rakuten Marketing\", company: \"Rakuten\", category: \"ad\", domains: [\"*.rakuten-static.com\", \"*.rmtag.com\", \"tag.rmp.rakuten.com\"], totalExecutionTime: 462276, totalOccurrences: 3399 }, { name: \"Rakuten MediaForge\", company: \"Rakuten\", category: \"ad\", domains: [\"*.mediaforge.com\"], totalExecutionTime: 1650,\n    totalOccurrences: 20 }, { name: \"Rambler\", company: \"Rambler & Co\", category: \"utility\", domains: [\"*.rambler.ru\"], totalExecutionTime: 54521084, totalOccurrences: 15831 }, { name: \"Ranker\", category: \"content\", domains: [\"*.ranker.com\", \"*.rnkr-static.com\"] }, { name: \"Ravelin\", category: \"utility\", domains: [\"*.ravelin.com\"] }, { name: \"Raygun\", category: \"utility\", domains: [\"*.raygun.io\", \"*.rapidzebra.io\"], totalExecutionTime: 245714, totalOccurrences: 2539 }, { name: \"ReCollect\", category: \"utility\", domains: [\"*.recollect.net\"], totalExecutionTime: 229879, totalOccurrences: 135 }, { name: \"ReSRC\", category: \"utility\", domains: [\"*.resrc.it\"] }, { name: \"ReTargeter\", category: \"ad\", domains: [\"*.retargeter.com\"] }, { name: \"Reach Group\", category: \"ad\", domains: [\"*.redintelligence.net\"], totalExecutionTime: 1449, totalOccurrences: 199 }, { name: \"ReachDynamics\", category: \"ad\", domains: [\"*.rdcdn.com\"] }, { name: \"ReachForce\", category: \"ad\", domains: [\"*.reachforce.com\"] },\n    { name: \"ReachLocal\", category: \"ad\", domains: [\"*.rtrk.co.nz\"], examples: [\"rtsys.rtrk.co.nz\"] }, { name: \"ReachMee\", category: \"content\", domains: [\"*.reachmee.com\"], totalExecutionTime: 133135, totalOccurrences: 40 }, { name: \"Reactful\", category: \"analytics\", domains: [\"*.reactful.com\"], totalExecutionTime: 12497, totalOccurrences: 42 }, { name: \"Realtime\", company: \"internet business technologies\", category: \"utility\", domains: [\"*.realtime.co\"] }, { name: \"Realtime Media (Brian Communications)\", category: \"ad\", domains: [\"*.rtm.com\"] }, { name: \"Realtime Targeting\", category: \"ad\", domains: [\"*.idtargeting.com\"] }, { name: \"Realytics\", category: \"analytics\", domains: [\"dcniko1cv0rz.cloudfront.net\", \"*.realytics.net\"], totalExecutionTime: 38343, totalOccurrences: 276 }, { name: \"RebelMouse\", category: \"ad\", domains: [\"*.rebelmouse.com\", \"*.rbl.ms\"], examples: [\"www.rebelmouse.com\"], totalExecutionTime: 3876, totalOccurrences: 22 }, { name: \"Receiptful\", category: \"utility\", domains: [\n    \"*.receiptful.com\"], totalExecutionTime: 58254, totalOccurrences: 361 }, { name: \"Recite Me\", category: \"other\", domains: [\"*.reciteme.com\"], totalExecutionTime: 22320, totalOccurrences: 142 }, { name: \"RecoBell\", category: \"analytics\", domains: [\"*.recobell.io\"] }, { name: \"Recommend\", category: \"analytics\", domains: [\"*.recommend.pro\"] }, { name: \"Red Eye International\", category: \"ad\", domains: [\"*.pajmc.com\"] }, { name: \"Redfish Group\", category: \"ad\", domains: [\"*.wmps.com\"] }, { name: \"Reevoo\", category: \"analytics\", domains: [\"*.reevoo.com\"], totalExecutionTime: 87323, totalOccurrences: 133 }, { name: \"Refersion\", category: \"ad\", domains: [\"*.refersion.com\"], totalExecutionTime: 564360, totalOccurrences: 2170 }, { name: \"Refined Ads\", category: \"ad\", domains: [\"*.refinedads.com\"] }, { name: \"Reflektion\", category: \"analytics\", domains: [\"*.reflektion.com\", \"d26opx5dl8t69i.cloudfront.net\"] }, { name: \"Reflow\", company: \"Scenestealer\", category: \"ad\", domains: [\"*.reflow.tv\"] },\n    { name: \"Reklama\", category: \"ad\", domains: [\"*.o2.pl\", \"*.wp.pl\"], examples: [\"dot.wp.pl\", \"px.o2.pl\", \"px.wp.pl\"], totalExecutionTime: 846563, totalOccurrences: 1054 }, { name: \"Relevad ReleStar\", company: \"Relevad\", category: \"ad\", domains: [\"*.relestar.com\"] }, { name: \"Remarketing Pixel\", company: \"Adsterra Network\", category: \"ad\", domains: [\"*.datadbs.com\", \"*.remarketingpixel.com\"] }, { name: \"Remintrex\", company: \"SmartUp Venture\", category: \"ad\", domains: [\"*.remintrex.com\"] }, { name: \"Republer\", category: \"ad\", domains: [\"*.republer.com\"], examples: [\"sync.republer.com\"] }, { name: \"Research Now\", category: \"analytics\", domains: [\"*.researchgnow.com\", \"*.researchnow.com\"], examples: [\"tag.researchgnow.com\"] }, { name: \"Research Online\", company: \"Skills Development Scotland\", category: \"content\", domains: [\"*.researchonline.org.uk\"], examples: [\"www.researchonline.org.uk\"] }, { name: \"Resonance Insights\", category: \"analytics\", domains: [\"*.res-x.com\"], totalExecutionTime: 2277,\n    totalOccurrences: 20 }, { name: \"Resonate Networks\", category: \"analytics\", domains: [\"*.reson8.com\"], totalExecutionTime: 1739, totalOccurrences: 1 }, { name: \"Response Team\", category: \"ad\", domains: [\"*.i-transactads.com\"] }, { name: \"ResponseTap\", category: \"analytics\", domains: [\"*.adinsight.com\", \"*.responsetap.com\"], totalExecutionTime: 84074, totalOccurrences: 274 }, { name: \"ResponsiveVoice\", category: \"other\", domains: [\"*.responsivevoice.org\"], totalExecutionTime: 851397, totalOccurrences: 6863 }, { name: \"Retention Science\", category: \"ad\", domains: [\"*.retentionscience.com\", \"d1stxfv94hrhia.cloudfront.net\"], totalExecutionTime: 17276, totalOccurrences: 209 }, { name: \"Revcontent\", category: \"content\", domains: [\"*.revcontent.com\"], totalExecutionTime: 1153469, totalOccurrences: 1251 }, { name: \"Revee\", category: \"ad\", domains: [\"*.revee.com\"] }, { name: \"Revenue Conduit\", category: \"utility\", domains: [\"*.revenueconduit.com\"] }, { name: \"RevenueMantra\", category: \"ad\",\n    domains: [\"*.revenuemantra.com\"] }, { name: \"Reviews.co.uk\", category: \"analytics\", domains: [\"*.reviews.co.uk\"], totalExecutionTime: 425151, totalOccurrences: 1883 }, { name: \"Reviews.io\", category: \"analytics\", domains: [\"*.reviews.io\"], totalExecutionTime: 1713955, totalOccurrences: 4516 }, { name: \"Revolver Maps\", category: \"analytics\", domains: [\"*.revolvermaps.com\"], totalExecutionTime: 2132297, totalOccurrences: 2305 }, { name: \"Revv\", category: \"utility\", domains: [\"*.revv.co\"], totalExecutionTime: 26667, totalOccurrences: 11 }, { name: \"RichRelevance\", category: \"analytics\", domains: [\"*.richrelevance.com\"], totalExecutionTime: 3496, totalOccurrences: 19 }, { name: \"RightNow Service Cloud\", company: \"Oracle\", category: \"customer-success\", domains: [\"*.rightnowtech.com\", \"*.rnengage.com\"], totalExecutionTime: 8970, totalOccurrences: 122 }, { name: \"Rightster\", category: \"ad\", domains: [\"*.ads-creativesyndicator.com\"] }, { name: \"Riskified\", category: \"utility\", domains: [\"*\\\n.riskified.com\"], totalExecutionTime: 373865, totalOccurrences: 1643 }, { name: \"Rockerbox\", category: \"analytics\", homepage: \"https://www.rockerbox.com/\", domains: [\"getrockerbox.com\"], examples: [\"getrockerbox.com\"], totalExecutionTime: 19742, totalOccurrences: 162 }, { name: \"Rocket Fuel\", category: \"ad\", domains: [\"*.rfihub.com\", \"*.ru4.com\", \"*.rfihub.net\", \"*.ad1x.com\"], totalExecutionTime: 356189, totalOccurrences: 3247 }, { name: \"Rollbar\", category: \"utility\", domains: [\"*.rollbar.com\", \"d37gvrvc0wt4s1.cloudfront.net\"], examples: [\"api.rollbar.com\"], totalExecutionTime: 190180, totalOccurrences: 2349 }, { name: \"RomanCart\", category: \"utility\", domains: [\"*.romancart.com\"], totalExecutionTime: 510, totalOccurrences: 5 }, { name: \"Rondavu\", category: \"ad\", domains: [\"*.rondavu.com\"] }, { name: \"Roomkey\", category: \"content\", domains: [\"*.roomkey.com\"], examples: [\"www.roomkey.com\"] }, { name: \"Roost\", category: \"utility\", domains: [\"*.goroost.com\"] }, { name: \"Roxot\", category: \"\\\nad\", domains: [\"*.rxthdr.com\"] }, { name: \"Roxr Software\", category: \"analytics\", domains: [\"*.getclicky.com\"], totalExecutionTime: 851573, totalOccurrences: 12877 }, { name: \"Rtoaster\", company: \"Brainpad\", homepage: \"https://www.brainpad.co.jp/rtoaster/\", category: \"marketing\", domains: [\"*.rtoaster.jp\"], examples: [\"rt.rtoaster.jp\"], totalExecutionTime: 15065, totalOccurrences: 91 }, { name: \"Rubikloud.com\", category: \"analytics\", domains: [\"*.rubikloud.com\"] }, { name: \"Ruler Analytics\", company: \"Ruler\", category: \"analytics\", domains: [\"*.nyltx.com\", \"*.ruleranalytics.com\"], examples: [\"www.ruleranalytics.com\"], totalExecutionTime: 41074, totalOccurrences: 436 }, { name: \"Runner\", company: \"Rambler & Co\", category: \"content\", domains: [\"*.begun.ru\"], totalExecutionTime: 26, totalOccurrences: 1 }, { name: \"S4M\", category: \"ad\", domains: [\"*.sam4m.com\"] }, { name: \"SAP Hybris Marketing Convert\", company: \"SAP\", category: \"ad\", domains: [\"*.seewhy.com\"] }, { name: \"SAS Institute\", category: \"\\\nad\", domains: [\"*.aimatch.com\", \"*.sas.com\"], totalExecutionTime: 59419, totalOccurrences: 29 }, { name: \"SATORI\", homepage: \"https://satori.marketing/\", category: \"marketing\", domains: [\"satori.segs.jp\"], examples: [\"satori.segs.jp/s.js\"], totalExecutionTime: 62202, totalOccurrences: 816 }, { name: \"SC ShopMania Net SRL\", category: \"content\", domains: [\"*.shopmania.com\"] }, { name: \"SDL Media Manager\", company: \"SDL\", category: \"other\", domains: [\"*.sdlmedia.com\"] }, { name: \"SFR\", category: \"other\", domains: [\"*.sfr.fr\"], examples: [\"elr.sfr.fr\"], totalExecutionTime: 22751, totalOccurrences: 22 }, { name: \"SLI Systems\", category: \"utility\", domains: [\"*.resultslist.com\", \"*.resultspage.com\", \"*.sli-spark.com\"], totalExecutionTime: 2909, totalOccurrences: 33 }, { name: \"SMARTASSISTANT\", company: \"Smart Information Systems\", category: \"customer-success\", domains: [\"*.smartassistant.com\"] }, { name: \"SMARTSTREAM.TV\", category: \"ad\", domains: [\"*.smartstream.tv\"] }, { name: \"SPX\", company: \"\\\nSmaato\", category: \"ad\", domains: [\"*.smaato.net\"], totalExecutionTime: 519, totalOccurrences: 13 }, { name: \"Sabio\", category: \"customer-success\", domains: [\"*.sabio.co.uk\"], examples: [\"www.sabio.co.uk\"] }, { name: \"Sailthru\", category: \"analytics\", domains: [\"*.sail-horizon.com\", \"*.sail-personalize.com\", \"*.sail-track.com\"], totalExecutionTime: 59245, totalOccurrences: 678 }, { name: \"Sailthru Sightlines\", company: \"Sailthru\", category: \"marketing\", domains: [\"*.sailthru.com\"], totalExecutionTime: 6772, totalOccurrences: 18 }, { name: \"Sajari Pty\", category: \"utility\", domains: [\"*.sajari.com\"], totalExecutionTime: 70019, totalOccurrences: 197 }, { name: \"SaleCycle\", category: \"ad\", domains: [\"*.salecycle.com\", \"d16fk4ms6rqz1v.cloudfront.net\", \"d22j4fzzszoii2.cloudfront.net\", \"d30ke5tqu2tkyx.cloudfront.net\", \"dn1i8v75r669j.cloudfront.net\"], totalExecutionTime: 146399, totalOccurrences: 641 }, { name: \"Salesforce Live Agent\", company: \"Salesforce.com\", category: \"customer-success\", domains: [\n    \"*.salesforceliveagent.com\"], totalExecutionTime: 100033, totalOccurrences: 675 }, { name: \"Salesforce.com\", category: \"ad\", domains: [\"*.force.com\", \"*.salesforce.com\"], examples: [\"secure.force.com\"], totalExecutionTime: 1614051, totalOccurrences: 4970 }, { name: \"Samba TV\", company: \"Samba\", category: \"content\", domains: [\"*.samba.tv\"], totalExecutionTime: 1690, totalOccurrences: 7 }, { name: \"Samplicio.us\", category: \"analytics\", domains: [\"*.samplicio.us\"], totalExecutionTime: 1727, totalOccurrences: 5 }, { name: \"Say Media\", category: \"ad\", domains: [\"*.saymedia.com\"] }, { name: \"Scenario\", category: \"analytics\", domains: [\"*.getscenario.com\"] }, { name: \"Schuh (image shard)\", company: \"Schuh\", category: \"other\", domains: [\"d2ob0iztsaxy5v.cloudfront.net\"] }, { name: \"Science Rockstars\", category: \"analytics\", domains: [\"*.persuasionapi.com\"] }, { name: \"ScientiaMobile\", category: \"analytics\", domains: [\"*.wurflcloud.com\", \"*.wurfl.io\"], totalExecutionTime: 627, totalOccurrences: 3 },\n    { name: \"Scoota\", category: \"ad\", domains: [\"*.rockabox.co\", \"*.scoota.co\", \"d31i2625d5nv27.cloudfront.net\", \"dyjnzf8evxrp2.cloudfront.net\"] }, { name: \"ScribbleLive\", category: \"ad\", domains: [\"*.scribblelive.com\"] }, { name: \"SearchForce\", category: \"ad\", domains: [\"*.searchforce.net\"], totalExecutionTime: 118, totalOccurrences: 3 }, { name: \"SearchSpring\", category: \"utility\", domains: [\"*.searchspring.net\"], totalExecutionTime: 1175588, totalOccurrences: 309 }, { name: \"Searchanise\", category: \"analytics\", domains: [\"*.searchanise.com\"], examples: [\"www.searchanise.com\"], totalExecutionTime: 63519, totalOccurrences: 420 }, { name: \"Sears Holdings\", category: \"content\", domains: [\"*.shld.net\"] }, { name: \"Secomapp\", category: \"utility\", domains: [\"*.secomapp.com\"], totalExecutionTime: 2151952, totalOccurrences: 2137 }, { name: \"SecuredVisit\", company: \"4Cite Marketing\", category: \"ad\", domains: [\"*.securedvisit.com\"], totalExecutionTime: 41054, totalOccurrences: 369 }, { name: \"\\\nSecurityMetrics\", category: \"utility\", domains: [\"*.securitymetrics.com\"], totalExecutionTime: 8413, totalOccurrences: 2 }, { name: \"Segmento\", category: \"ad\", domains: [\"*.rutarget.ru\"], totalExecutionTime: 17111, totalOccurrences: 226 }, { name: \"Segmint\", category: \"analytics\", domains: [\"*.segmint.net\"], totalExecutionTime: 14122, totalOccurrences: 109 }, { name: \"Sekindo\", category: \"content\", domains: [\"*.sekindo.com\"], totalExecutionTime: 376, totalOccurrences: 4 }, { name: \"Seldon\", category: \"analytics\", domains: [\"*.rummblelabs.com\"] }, { name: \"SelectMedia International\", category: \"content\", domains: [\"*.selectmedia.asia\"], totalExecutionTime: 186574, totalOccurrences: 68 }, { name: \"Selligent\", category: \"ad\", domains: [\"*.emsecure.net\", \"*.slgnt.eu\", \"targetemsecure.blob.core.windows.net\"], totalExecutionTime: 163886, totalOccurrences: 506 }, { name: \"Sellpoints\", category: \"analytics\", domains: [\"*.sellpoints.com\"] }, { name: \"Semantics3\", category: \"analytics\", domains: [\n    \"*.hits.io\"] }, { name: \"Semasio\", category: \"analytics\", domains: [\"*.semasio.net\"] }, { name: \"Semcasting Site Visitor Attribution\", company: \"Semcasting\", category: \"ad\", domains: [\"*.smartzonessva.com\"] }, { name: \"Sentifi\", category: \"social\", domains: [\"*.sentifi.com\"] }, { name: \"ServMetric\", category: \"analytics\", domains: [\"*.servmetric.com\"] }, { name: \"ServiceSource International\", category: \"marketing\", domains: [\"*.scoutanalytics.net\"], examples: [\"scout.scoutanalytics.net\"] }, { name: \"ServiceTick\", category: \"analytics\", domains: [\"*.servicetick.com\"] }, { name: \"Servo\", company: \"Xervo\", category: \"hosting\", domains: [\"*.onmodulus.net\"] }, { name: \"SessionCam\", company: \"ServiceTick\", category: \"analytics\", domains: [\"*.sessioncam.com\", \"d2oh4tlt9mrke9.cloudfront.net\"] }, { name: \"Seznam\", category: \"utility\", domains: [\"*.imedia.cz\"], totalExecutionTime: 1323711, totalOccurrences: 6863 }, { name: \"Sharethrough\", category: \"ad\", domains: [\"*.sharethrough.com\"], totalExecutionTime: 46730,\n    totalOccurrences: 833 }, { name: \"SharpSpring\", category: \"marketing\", domains: [\"*.sharpspring.com\", \"*.marketingautomation.services\"], totalExecutionTime: 632191, totalOccurrences: 2080 }, { name: \"ShopRunner\", category: \"content\", domains: [\"*.shoprunner.com\", \"*.s-9.us\"], totalExecutionTime: 35573, totalOccurrences: 32 }, { name: \"ShopStorm\", category: \"utility\", domains: [\"*.shopstorm.com\"] }, { name: \"Shopatron\", category: \"hosting\", domains: [\"*.shopatron.com\"] }, { name: \"Shopgate\", category: \"utility\", domains: [\"*.shopgate.com\"], totalExecutionTime: 15293, totalOccurrences: 25 }, { name: \"ShopiMind\", company: \"ShopIMind\", category: \"ad\", domains: [\"*.shopimind.com\"] }, { name: \"Shopkeeper Tools\", category: \"utility\", domains: [\"*.shopkeepertools.com\"], totalExecutionTime: 500, totalOccurrences: 6 }, { name: \"Sidecar\", category: \"other\", domains: [\"*.getsidecar.com\", \"d3v27wwd40f0xu.cloudfront.net\"] }, { name: \"Sidereel\", category: \"analytics\", domains: [\"*.sidereel.com\"] },\n    { name: \"Sift Science\", category: \"utility\", domains: [\"*.siftscience.com\"], totalExecutionTime: 90167, totalOccurrences: 355 }, { name: \"Signal\", category: \"tag-manager\", domains: [\"*.sitetagger.co.uk\"] }, { name: \"Signyfyd\", category: \"utility\", domains: [\"*.signifyd.com\"], totalExecutionTime: 4752892, totalOccurrences: 2608 }, { name: \"Silktide\", category: \"hosting\", domains: [\"*.silktide.com\"], totalExecutionTime: 132707, totalOccurrences: 390 }, { name: \"Silverpop\", company: \"IBM\", category: \"ad\", domains: [\"*.mkt912.com\", \"*.mkt922.com\", \"*.mkt932.com\", \"*.mkt941.com\", \"*.mkt51.net\", \"*.mkt61.net\", \"*.pages01.net\", \"*.pages02.net\", \"*.pages03.net\", \"*.pages04.net\", \"*.pages05.net\"], totalExecutionTime: 4144, totalOccurrences: 58 }, { name: \"Simplaex\", category: \"marketing\", domains: [\"*.simplaex.net\"] }, { name: \"SimpleReach\", category: \"analytics\", domains: [\"*.simplereach.com\", \"d8rk54i4mohrb.cloudfront.net\"] }, { name: \"Simplestream\", category: \"content\", domains: [\"*.simp\\\nlestream.com\"], examples: [\"player.simplestream.com\"] }, { name: \"Simpli.fi\", category: \"ad\", domains: [\"*.simpli.fi\"], totalExecutionTime: 974218, totalOccurrences: 16378 }, { name: \"Simplicity Marketing\", category: \"ad\", domains: [\"*.flashtalking.com\"], totalExecutionTime: 579126, totalOccurrences: 2927 }, { name: \"SinnerSchrader Deutschland\", category: \"ad\", domains: [\"*.s2Betrieb.de\"] }, { name: \"Sirv\", category: \"other\", domains: [\"*.sirv.com\"], totalExecutionTime: 604262, totalOccurrences: 1034 }, { name: \"Site Meter\", category: \"analytics\", domains: [\"*.sitemeter.com\"] }, { name: \"Site24x7 Real User Monitoring\", company: \"Site24x7\", category: \"analytics\", domains: [\"*.site24x7rum.com\"], totalExecutionTime: 124283, totalOccurrences: 1007 }, { name: \"SiteGainer\", category: \"analytics\", domains: [\"*.sitegainer.com\", \"d191y0yd6d0jy4.cloudfront.net\"] }, { name: \"SiteScout\", company: \"Centro\", category: \"ad\", domains: [\"*.pixel.ad\", \"*.sitescout.com\"], totalExecutionTime: 256082, totalOccurrences: 3401 },\n    { name: \"Siteimprove\", category: \"utility\", domains: [\"*.siteimprove.com\", \"*.siteimproveanalytics.com\"], totalExecutionTime: 28494, totalOccurrences: 361 }, { name: \"Six Degrees Group\", category: \"hosting\", domains: [\"*.fstech.co.uk\"] }, { name: \"Skimbit\", category: \"ad\", domains: [\"*.redirectingat.com\", \"*.skimresources.com\", \"*.skimresources.net\"], totalExecutionTime: 32940093, totalOccurrences: 86270 }, { name: \"Skimlinks\", category: \"ad\", domains: [\"*.skimlinks.com\"] }, { name: \"SkyGlue Technology\", category: \"analytics\", domains: [\"*.skyglue.com\"], totalExecutionTime: 2567, totalOccurrences: 24 }, { name: \"SkyScanner\", category: \"content\", domains: [\"*.skyscanner.net\"], examples: [\"api.skyscanner.net\"], totalExecutionTime: 98147, totalOccurrences: 370 }, { name: \"Skybet\", company: \"Bonne Terre t/a Sky Vegas (Sky)\", category: \"other\", domains: [\"*.skybet.com\"] }, { name: \"Skype\", category: \"other\", domains: [\"*.skype.com\"], totalExecutionTime: 121901, totalOccurrences: 625 }, {\n    name: \"Slate Group\", category: \"content\", domains: [\"*.cdnslate.com\"] }, { name: \"SlimCut Media Outstream\", company: \"SlimCut Media\", category: \"ad\", domains: [\"*.freeskreen.com\"] }, { name: \"Smart Insight Tracking\", company: \"Emarsys\", category: \"analytics\", domains: [\"*.scarabresearch.com\"], totalExecutionTime: 361811, totalOccurrences: 1779 }, { name: \"Smart AdServer\", category: \"ad\", domains: [\"*.01net.com\", \"*.sascdn.com\", \"*.sasqos.com\", \"*.smartadserver.com\"], examples: [\"securite.01net.com\"], totalExecutionTime: 22356737, totalOccurrences: 107812 }, { name: \"SmartFocus\", category: \"analytics\", domains: [\"*.emv2.com\", \"*.emv3.com\", \"*.predictiveintent.com\", \"*.smartfocus.com\", \"*.themessagecloud.com\"] }, { name: \"Smarter Click\", category: \"ad\", domains: [\"*.smct.co\", \"*.smarterclick.co.uk\"], totalExecutionTime: 761, totalOccurrences: 11 }, { name: \"SmarterHQ\", category: \"analytics\", domains: [\"*.smarterhq.io\", \"d1n00d49gkbray.cloudfront.net\", \"*.smarterremarketer.net\"], totalExecutionTime: 2636,\n    totalOccurrences: 28 }, { name: \"Smarttools\", category: \"customer-success\", domains: [\"*.smartertrack.com\"] }, { name: \"Smartzer\", category: \"ad\", domains: [\"*.smartzer.com\"] }, { name: \"Snack Media\", category: \"content\", domains: [\"*.snack-media.com\"], totalExecutionTime: 575613, totalOccurrences: 423 }, { name: \"Snacktools\", category: \"ad\", domains: [\"*.bannersnack.com\"], totalExecutionTime: 162327, totalOccurrences: 303 }, { name: \"SnapEngage\", category: \"customer-success\", domains: [\"*.snapengage.com\"], totalExecutionTime: 147012, totalOccurrences: 1038 }, { name: \"SnapWidget\", category: \"content\", domains: [\"*.snapwidget.com\"] }, { name: \"Soasta\", category: \"analytics\", domains: [\"*.lognormal.net\"] }, { name: \"SociableLabs\", category: \"ad\", domains: [\"*.sociablelabs.net\", \"*.sociablelabs.com\"] }, { name: \"Social Annex\", category: \"customer-success\", domains: [\"*.socialannex.com\"] }, { name: \"SocialShopWave\", category: \"social\", domains: [\"*.socialshopwave.com\"], totalExecutionTime: 4962079,\n    totalOccurrences: 3720 }, { name: \"Socialphotos\", category: \"social\", domains: [\"*.slpht.com\"], totalExecutionTime: 12590, totalOccurrences: 120 }, { name: \"Sociomantic Labs\", company: \"DunnHumby\", category: \"ad\", domains: [\"*.sociomantic.com\"] }, { name: \"SodaHead\", category: \"analytics\", domains: [\"*.sodahead.com\"], examples: [\"pollware-cdn.sodahead.com\"] }, { name: \"Softwebzone\", category: \"hosting\", domains: [\"*.softwebzone.com\"], examples: [\"www.softwebzone.com\"] }, { name: \"Sojern\", category: \"marketing\", domains: [\"*.sojern.com\"], totalExecutionTime: 2086952, totalOccurrences: 4422 }, { name: \"Sokrati\", category: \"marketing\", domains: [\"*.sokrati.com\"] }, { name: \"Sonobi\", category: \"ad\", domains: [\"*.sonobi.com\"], totalExecutionTime: 4682222, totalOccurrences: 81682 }, { name: \"Sooqr Search\", company: \"Sooqr\", category: \"utility\", domains: [\"*.sooqr.com\"], totalExecutionTime: 176199, totalOccurrences: 396 }, { name: \"Sophus3\", category: \"analytics\", domains: [\"*.s3ae.com\", \"\\\n*.sophus3.com\"], totalExecutionTime: 5605, totalOccurrences: 11 }, { name: \"Sorenson Media\", category: \"content\", domains: [\"*.sorensonmedia.com\"] }, { name: \"Sortable\", category: \"ad\", domains: [\"*.deployads.com\"] }, { name: \"Sotic\", category: \"hosting\", domains: [\"*.sotic.net\", \"*.soticservers.net\"] }, { name: \"Soundest\", category: \"ad\", domains: [\"*.soundestlink.com\", \"*.soundest.net\"], totalExecutionTime: 835, totalOccurrences: 102 }, { name: \"Sourcepoint\", category: \"ad\", domains: [\"*.decenthat.com\", \"*.fallingfalcon.com\", \"*.summerhamster.com\", \"d2lv4zbk7v5f93.cloudfront.net\", \"d3qxwzhswv93jk.cloudfront.net\"], examples: [\"www.decenthat.com\", \"www.fallingfalcon.com\", \"www.summerhamster.com\"] }, { name: \"SourceKnowledge\", homepage: \"https://www.sourceknowledge.com\", category: \"ad\", domains: [\"*.provenpixel.com\"], totalExecutionTime: 505, totalOccurrences: 8 }, { name: \"SpaceNet\", category: \"hosting\", domains: [\"*.nmm.de\"] }, { name: \"Sparkflow\", company: \"Intercept Interactive\", category: \"\\\nad\", domains: [\"*.sparkflow.net\"] }, { name: \"Specific Media\", category: \"ad\", domains: [\"*.specificmedia.com\", \"*.adviva.net\", \"*.specificclick.net\"] }, { name: \"Spicy\", company: \"Data-Centric Alliance\", category: \"ad\", domains: [\"*.sspicy.ru\"] }, { name: \"Spoke\", category: \"customer-success\", domains: [\"*.121d8.com\"] }, { name: \"Spongecell\", category: \"ad\", domains: [\"*.spongecell.com\"] }, { name: \"Spot.IM\", category: \"social\", domains: [\"*.spot.im\", \"*.spotim.market\"], totalExecutionTime: 192547, totalOccurrences: 342 }, { name: \"SpotXchange\", category: \"ad\", domains: [\"*.spotxcdn.com\", \"*.spotxchange.com\", \"*.spotx.tv\"] }, { name: \"SpringServer\", category: \"ad\", domains: [\"*.springserve.com\"], totalExecutionTime: 1192823, totalOccurrences: 1432 }, { name: \"Spylight\", category: \"other\", domains: [\"*.spylight.com\"] }, { name: \"SreamAMG\", company: \"StreamAMG\", category: \"other\", domains: [\"*.streamamg.com\"], totalExecutionTime: 85506, totalOccurrences: 62 }, { name: \"StackAdapt\", category: \"\\\nad\", domains: [\"*.stackadapt.com\"], totalExecutionTime: 1338506, totalOccurrences: 14912 }, { name: \"StackExchange\", category: \"social\", domains: [\"*.sstatic.net\"], totalExecutionTime: 187262, totalOccurrences: 217 }, { name: \"Stackla PTY\", category: \"social\", domains: [\"*.stackla.com\"], totalExecutionTime: 271026, totalOccurrences: 175 }, { name: \"Stailamedia\", category: \"ad\", domains: [\"*.stailamedia.com\"] }, { name: \"Stamped.io\", category: \"analytics\", domains: [\"*.stamped.io\"], totalExecutionTime: 1665115, totalOccurrences: 12460 }, { name: \"Starfield Services Root Certificate Authority\", company: \"Starfield Technologies\", category: \"utility\", domains: [\"*.starfieldtech.com\", \"ss2.us\", \"*.ss2.us\"], examples: [\"ocsp.starfieldtech.com\"], totalExecutionTime: 18156, totalOccurrences: 39 }, { name: \"Starfield Technologies\", category: \"utility\", domains: [\"*.websiteprotection.com\"], examples: [\"seals.websiteprotection.com\"] }, { name: \"StatCounter\", category: \"analytics\", domains: [\"*.st\\\natcounter.com\"], totalExecutionTime: 5427381, totalOccurrences: 50769 }, { name: \"Statful\", category: \"analytics\", domains: [\"*.statful.com\"] }, { name: \"Steelhouse\", category: \"ad\", domains: [\"*.steelhousemedia.com\"], totalExecutionTime: 66172, totalOccurrences: 452 }, { name: \"Steepto\", category: \"ad\", domains: [\"*.steepto.com\"], totalExecutionTime: 170, totalOccurrences: 1 }, { name: \"StellaService\", category: \"analytics\", domains: [\"*.stellaservice.com\"] }, { name: \"StickyADS.tv\", category: \"ad\", domains: [\"*.stickyadstv.com\"], totalExecutionTime: 2198555, totalOccurrences: 1462 }, { name: \"STINGRAY\", company: \"FlexOne\", category: \"ad\", domains: [\"*.impact-ad.jp\"], examples: [\"y.one.impact-ad.jp\"], totalExecutionTime: 1261721, totalOccurrences: 9742 }, { name: \"Storify\", company: \"Adobe Systems\", category: \"social\", domains: [\"*.storify.com\"] }, { name: \"Storm Tag Manager\", company: \"Rakuten\", category: \"tag-manager\", domains: [\"*.stormcontainertag.com\"] }, { name: \"Storygize\", category: \"\\\nad\", domains: [\"*.storygize.net\"], examples: [\"www.storygize.net\"], totalExecutionTime: 60468, totalOccurrences: 154 }, { name: \"Strands\", category: \"utility\", domains: [\"*.strands.com\"] }, { name: \"StreamRail\", category: \"ad\", domains: [\"*.streamrail.com\", \"*.streamrail.net\"] }, { name: \"StrikeAd\", category: \"ad\", domains: [\"*.strikead.com\"] }, { name: \"Struq\", company: \"Quantcast\", category: \"ad\", domains: [\"*.struq.com\"] }, { name: \"StrÃ¶er Digital Media\", category: \"ad\", domains: [\"*.stroeerdigitalmedia.de\"] }, { name: \"StumbleUpon\", category: \"content\", domains: [\"*.stumble-upon.com\", \"*.stumbleupon.com\"], totalExecutionTime: 18653, totalOccurrences: 17 }, { name: \"Sub2 Technologies\", category: \"analytics\", domains: [\"*.sub2tech.com\"], totalExecutionTime: 6667, totalOccurrences: 31 }, { name: \"SublimeSkinz\", category: \"ad\", domains: [\"*.ayads.co\"], totalExecutionTime: 339456, totalOccurrences: 772 }, { name: \"Sumo Logic\", category: \"utility\", domains: [\"*.sumologic.com\"], totalExecutionTime: 19322,\n    totalOccurrences: 9 }, { name: \"Sunday Times Driving\", category: \"content\", domains: [\"*.driving.co.uk\"] }, { name: \"SundaySky\", category: \"ad\", domains: [\"*.sundaysky.com\", \"dds6m601du5ji.cloudfront.net\"], totalExecutionTime: 7435, totalOccurrences: 10 }, { name: \"Sunrise Integration\", category: \"utility\", domains: [\"*.sunriseintegration.com\"] }, { name: \"Supertool Network Technology\", category: \"analytics\", domains: [\"*.miaozhen.com\"], totalExecutionTime: 6166, totalOccurrences: 49 }, { name: \"Survata\", category: \"analytics\", domains: [\"*.survata.com\"] }, { name: \"SurveyGizmo\", category: \"analytics\", domains: [\"*.surveygizmo.eu\"], examples: [\"www.surveygizmo.eu\"] }, { name: \"SurveyMonkey\", category: \"analytics\", domains: [\"*.surveymonkey.com\"], totalExecutionTime: 28632, totalOccurrences: 250 }, { name: \"Survicate\", category: \"analytics\", domains: [\"*.survicate.com\"], totalExecutionTime: 933283, totalOccurrences: 3008 }, { name: \"Sweet Tooth\", category: \"ad\", domains: [\"*.sweetto\\\noth.io\"], totalExecutionTime: 2673, totalOccurrences: 41 }, { name: \"Swiftype\", category: \"utility\", domains: [\"*.swiftype.com\", \"*.swiftypecdn.com\"], totalExecutionTime: 383638, totalOccurrences: 982 }, { name: \"Switch Concepts\", category: \"ad\", domains: [\"*.switchadhub.com\"] }, { name: \"SwitchAds\", company: \"Switch Concepts\", category: \"ad\", domains: [\"*.switchads.com\"] }, { name: \"Swogo\", category: \"analytics\", domains: [\"*.xsellapp.com\"] }, { name: \"Swoop\", category: \"ad\", domains: [\"*.swoop.com\"], totalExecutionTime: 13511, totalOccurrences: 75 }, { name: \"Symantec\", category: \"utility\", domains: [\"*.norton.com\", \"*.symantec.com\", \"*.symcb.com\", \"*.symcd.com\"], examples: [\"extended-validation-ssl.websecurity.symantec.com\"], totalExecutionTime: 184600, totalOccurrences: 363 }, { name: \"Syncapse\", category: \"social\", domains: [\"*.clickable.net\"] }, { name: \"Synergetic\", category: \"ad\", domains: [\"*.synergetic.ag\"] }, { name: \"Synthetix\", category: \"customer-success\", domains: [\"*.sy\\\nn-finity.com\", \"*.synthetix-ec1.com\", \"*.synthetix.com\"], examples: [\"www.synthetix-ec1.com\"], totalExecutionTime: 6284, totalOccurrences: 27 }, { name: \"Syte\", category: \"other\", domains: [\"*.syteapi.com\"], examples: [\"cdn.syteapi.com\"], totalExecutionTime: 109749, totalOccurrences: 106 }, { name: \"TINT\", category: \"content\", domains: [\"*.71n7.com\", \"d33w9bm0n1egwm.cloudfront.net\", \"d36hc0p18k1aoc.cloudfront.net\", \"d3l7tj34e9fc43.cloudfront.net\"], examples: [\"www.71n7.com\"] }, { name: \"TNS (Kantar Group)\", category: \"analytics\", domains: [\"*.tns-counter.ru\"] }, { name: \"TRUSTe\", category: \"utility\", domains: [\"*.truste.com\"], totalExecutionTime: 123425, totalOccurrences: 613 }, { name: \"TV Genius\", company: \"Ericcson Media Services\", category: \"content\", domains: [\"*.tvgenius.net\"] }, { name: \"TVSquared\", category: \"ad\", domains: [\"*.tvsquared.com\"], totalExecutionTime: 548667, totalOccurrences: 4082 }, { name: \"TVTY\", category: \"ad\", domains: [\"*.distribeo.com\", \"*.ogigl.com\"] }, { name: \"\\\nTactics bvba\", category: \"hosting\", domains: [\"*.influid.co\"] }, { name: \"Tag Inspector\", company: \"InfoTrust\", category: \"analytics\", domains: [\"d22xmn10vbouk4.cloudfront.net\"], totalExecutionTime: 51386, totalOccurrences: 171 }, { name: \"TagCommander\", category: \"tag-manager\", domains: [\"*.commander1.com\", \"*.tagcommander.com\"], totalExecutionTime: 448164, totalOccurrences: 1509 }, { name: \"Tagboard\", category: \"social\", domains: [\"*.tagboard.com\"], totalExecutionTime: 106499, totalOccurrences: 49 }, { name: \"Taggstar\", company: \"Taggstar UK\", category: \"ad\", domains: [\"*.taggstar.com\"], totalExecutionTime: 16168, totalOccurrences: 68 }, { name: \"Tail Target\", company: \"Tail\", category: \"ad\", domains: [\"*.tailtarget.com\"], totalExecutionTime: 176612, totalOccurrences: 873 }, { name: \"Tailored\", category: \"other\", domains: [\"d24qm7bu56swjs.cloudfront.net\", \"dw3vahmen1rfy.cloudfront.net\", \"*.tailored.to\"] }, { name: \"Taleo Enterprise Cloud Service\", company: \"Oracle\", category: \"conten\\\nt\", domains: [\"*.taleo.net\"], totalExecutionTime: 4178, totalOccurrences: 68 }, { name: \"Talkable\", category: \"ad\", domains: [\"*.talkable.com\", \"d2jjzw81hqbuqv.cloudfront.net\"], examples: [\"www.talkable.com\"], totalExecutionTime: 154019, totalOccurrences: 601 }, { name: \"TapSense\", category: \"ad\", domains: [\"*.tapsense.com\"] }, { name: \"Tapad\", category: \"ad\", domains: [\"*.tapad.com\"], totalExecutionTime: 976, totalOccurrences: 54 }, { name: \"Teads\", category: \"ad\", domains: [\"*.teads.tv\"], totalExecutionTime: 2295585, totalOccurrences: 7565 }, { name: \"Team Internet Tonic\", company: \"Team Internet\", category: \"ad\", domains: [\"*.dntrax.com\"] }, { name: \"TechTarget\", category: \"content\", domains: [\"*.techtarget.com\", \"*.ttgtmedia.com\"], totalExecutionTime: 11857, totalOccurrences: 24 }, { name: \"Technorati\", company: \"Synacor\", category: \"ad\", domains: [\"*.technoratimedia.com\"], totalExecutionTime: 5382653, totalOccurrences: 27186 }, { name: \"Teedhaze\", category: \"content\", domains: [\"*\\\n.fuel451.com\"] }, { name: \"Tell Apart\", category: \"analytics\", domains: [\"*.tellapart.com\", \"*.tellaparts.com\"] }, { name: \"Tencent\", category: \"content\", domains: [\"*.qq.com\", \"*.ywxi.net\"], totalExecutionTime: 2265040, totalOccurrences: 8726 }, { name: \"Thanx Media\", category: \"utility\", domains: [\"*.hawksearch.info\"] }, { name: \"Thawte\", category: \"utility\", domains: [\"*.thawte.com\"], examples: [\"ocsp.thawte.com\", \"seal.thawte.com\"], totalExecutionTime: 307, totalOccurrences: 1 }, { name: \"Thesis\", category: \"analytics\", homepage: \"https://www.thesistesting.com/\", domains: [\"*.ttsep.com\"], examples: [\"thix.ttsep.com\"] }, { name: \"The AA\", category: \"ad\", domains: [\"*.adstheaa.com\"] }, { name: \"The ADEX\", category: \"ad\", domains: [\"*.theadex.com\"], totalExecutionTime: 13554, totalOccurrences: 129 }, { name: \"The Best Day\", category: \"social\", domains: [\"*.thebestday.com\"] }, { name: \"The Filter\", company: \"Exabre\", category: \"analytics\", domains: [\"*.thefilter.com\"] }, { name: \"The G\\\nuardian\", category: \"analytics\", domains: [\"*.ophan.co.uk\"] }, { name: \"The Hut Group\", category: \"content\", domains: [\"*.thcdn.com\"], totalExecutionTime: 497181, totalOccurrences: 281 }, { name: \"The Numa Group\", category: \"other\", domains: [\"*.hittail.com\"] }, { name: \"The Publisher Desk\", category: \"ad\", domains: [\"*.206ads.com\", \"*.publisherdesk.com\"] }, { name: \"The Sydney Morning Herald\", company: \"Fairfax Media\", category: \"content\", domains: [\"*.smh.com.au\"] }, { name: \"The Wall Street Jounal\", category: \"content\", domains: [\"*.wsj.net\"], totalExecutionTime: 3036, totalOccurrences: 5 }, { name: \"The Wall Street Journal\", category: \"content\", domains: [\"*.marketwatch.com\"] }, { name: \"TheFind\", category: \"content\", domains: [\"*.thefind.com\"] }, { name: \"Thinglink\", category: \"utility\", domains: [\"*.thinglink.com\"], totalExecutionTime: 2987, totalOccurrences: 53 }, { name: \"Thirdpresence\", category: \"ad\", domains: [\"*.thirdpresence.com\"] }, { name: \"ThreatMetrix\", category: \"util\\\nity\", domains: [\"*.online-metrix.net\"], totalExecutionTime: 1901757, totalOccurrences: 3530 }, { name: \"Throtle\", homepage: \"https://throtle.io/\", category: \"analytics\", domains: [\"*.thrtle.com\", \"*.v12group.com\"] }, { name: \"TicketMaster\", category: \"content\", domains: [\"*.t-x.io\", \"*.tmcs.net\"] }, { name: \"TikTok\", company: \"ByteDance Ltd\", homepage: \"https://www.tiktok.com/en/\", category: \"social\", domains: [\"*.tiktok.com\", \"*.ipstatp.com\"], examples: [\"analytics.tiktok.com\", \"https://s0.ipstatp.com/ad/business/track-log.js\"], totalExecutionTime: 111182189, totalOccurrences: 256224 }, { name: \"Tidio Live Chat\", company: \"Tidio\", homepage: \"https://www.tidiochat.com/en/\", category: \"customer-success\", domains: [\"*.tidiochat.com\"], totalExecutionTime: 26584634, totalOccurrences: 24598 }, { name: \"Tiledesk Live Chat\", company: \"Tiledesk SRL\", homepage: \"https://www.tiledesk.com/\", category: \"customer-success\", domains: [\"*.tiledesk.com\"], examples: [\"widget.tiledesk.com\"], totalExecutionTime: 253744,\n    totalOccurrences: 103 }, { name: \"Time\", category: \"content\", domains: [\"*.timeinc.net\"] }, { name: \"Time2Perf\", category: \"ad\", domains: [\"*.time2perf.com\"] }, { name: \"TinyURL\", category: \"utility\", domains: [\"*.tinyurl.com\"] }, { name: \"Tivo\", category: \"analytics\", domains: [\"*.rovicorp.com\"] }, { name: \"Tom&Co\", category: \"hosting\", domains: [\"*.tomandco.uk\"] }, { name: \"Toms Native Ads\", company: \"Purch\", category: \"ad\", domains: [\"*.natoms.com\"] }, { name: \"ToneMedia\", category: \"ad\", domains: [\"*.clickfuse.com\"] }, { name: \"Tonic\", company: \"Team Internet\", category: \"ad\", domains: [\"*.dntx.com\"] }, { name: \"Touch Commerce\", category: \"customer-success\", domains: [\"*.inq.com\", \"*.touchcommerce.com\"], totalExecutionTime: 12673, totalOccurrences: 74 }, { name: \"ToutApp\", category: \"ad\", domains: [\"*.toutapp.com\"] }, { name: \"TraceView\", company: \"Solarwinds\", category: \"analytics\", domains: [\"*.tracelytics.com\", \"d2gfdmu30u15x7.cloudfront.net\"] }, { name: \"TrackJS\", category: \"\\\nanalytics\", domains: [\"*.trackjs.com\", \"d2zah9y47r7bi2.cloudfront.net\"], examples: [\"usage.trackjs.com\"], totalExecutionTime: 2112335, totalOccurrences: 2268 }, { name: \"Tradedoubler\", category: \"ad\", domains: [\"*.pvnsolutions.com\", \"*.tradedoubler.com\"], totalExecutionTime: 31870, totalOccurrences: 165 }, { name: \"Tradelab\", category: \"ad\", domains: [\"*.tradelab.fr\"], totalExecutionTime: 5013, totalOccurrences: 44 }, { name: \"TrafficFactory\", category: \"ad\", domains: [\"*.trafficfactory.biz\"] }, { name: \"TrafficHunt\", category: \"ad\", domains: [\"*.traffichunt.com\"] }, { name: \"TrafficStars\", category: \"ad\", domains: [\"*.trafficstars.com\", \"*.tsyndicate.com\"], totalExecutionTime: 3435101, totalOccurrences: 7430 }, { name: \"Transifex\", category: \"utility\", domains: [\"*.transifex.com\"], totalExecutionTime: 193259, totalOccurrences: 546 }, { name: \"Travelex\", category: \"utility\", domains: [\"*.travelex.net\", \"*.travelex.co.uk\"], examples: [\"api.travelex.net\", \"travelmoney.travelex.co.uk\"] },\n    { name: \"Travelocity Canada\", company: \"Travelocity\", category: \"content\", domains: [\"*.travelocity.ca\"], examples: [\"www.travelocity.ca\"] }, { name: \"Travelocity USA\", company: \"Travelocity\", category: \"content\", domains: [\"*.travelocity.com\"], examples: [\"www.travelocity.com\"] }, { name: \"Travelzoo\", category: \"content\", domains: [\"*.travelzoo.com\"] }, { name: \"Treasure Data\", category: \"analytics\", domains: [\"*.treasuredata.com\"], totalExecutionTime: 1404314, totalOccurrences: 14403 }, { name: \"Tremor Video\", category: \"ad\", domains: [\"*.tremorhub.com\", \"*.videohub.tv\"] }, { name: \"Trialfire\", category: \"analytics\", domains: [\"*.trialfire.com\"], totalExecutionTime: 44579, totalOccurrences: 198 }, { name: \"Tribal Fusion\", company: \"Exponential Interactive\", category: \"ad\", domains: [\"*.tribalfusion.com\"], totalExecutionTime: 96569, totalOccurrences: 158016 }, { name: \"Triblio\", category: \"marketing\", domains: [\"*.tribl.io\"] }, { name: \"Triggered Messaging\", company: \"Fresh Releva\\\nnce\", category: \"ad\", domains: [\"*.triggeredmessaging.com\"] }, { name: \"Trinity Mirror\", category: \"content\", domains: [\"*.mirror.co.uk\"], totalExecutionTime: 13841, totalOccurrences: 41 }, { name: \"Trinity Mirror Digital Media\", category: \"social\", domains: [\"*.tm-aws.com\", \"*.icnetwork.co.uk\"] }, { name: \"TripAdvisor\", category: \"content\", domains: [\"*.jscache.com\", \"*.tacdn.com\", \"*.tamgrt.com\", \"*.tripadvisor.com\", \"*.viator.com\", \"*.tripadvisor.co.uk\"], examples: [\"www.jscache.com\", \"www.tamgrt.com\"], totalExecutionTime: 749303, totalOccurrences: 2354 }, { name: \"TripleLift\", category: \"ad\", domains: [\"*.3lift.com\"], totalExecutionTime: 8396, totalOccurrences: 4812 }, { name: \"Tru Optik\", category: \"ad\", domains: [\"*.truoptik.com\"] }, { name: \"TruConversion\", category: \"analytics\", domains: [\"*.truconversion.com\"], totalExecutionTime: 487670, totalOccurrences: 1008 }, { name: \"Trueffect\", category: \"marketing\", domains: [\"*.adlegend.com\"] }, { name: \"Truefit\", category: \"analytics\",\n    domains: [\"*.truefitcorp.com\"], examples: [\"cdn.truefitcorp.com\", \"fitrec.truefitcorp.com\", \"sch-cdn.truefitcorp.com\"], totalExecutionTime: 4647, totalOccurrences: 20 }, { name: \"Trust Guard\", category: \"utility\", domains: [\"*.trust-guard.com\"], totalExecutionTime: 3346, totalOccurrences: 35 }, { name: \"Trust Pilot\", category: \"analytics\", domains: [\"*.trustpilot.com\"], totalExecutionTime: 14795265, totalOccurrences: 54942 }, { name: \"Amazon Trust Services\", company: \"Amazon\", category: \"utility\", domains: [\"*.amazontrust.com\", \"o.ss2.us\"], examples: [\"ocsp.rootca1.amazontrust.com\"], totalExecutionTime: 107, totalOccurrences: 1 }, { name: \"Google Trust Services\", company: \"Google\", category: \"utility\", domains: [\"*.pki.goog\"], examples: [\"ocsp.pki.goog\"], totalExecutionTime: 18, totalOccurrences: 1 }, { name: \"Let's Encrypt\", homepage: \"https://letsencrypt.org/\", category: \"utility\", domains: [\"*.letsencrypt.org\"], examples: [\"ocsp.int-x3.letsencrypt.org\"], totalExecutionTime: 76, totalOccurrences: 3 },\n    { name: \"TrustX\", category: \"ad\", domains: [\"*.trustx.org\"] }, { name: \"Trusted Shops\", category: \"utility\", domains: [\"*.trustedshops.com\"], totalExecutionTime: 7373870, totalOccurrences: 17267 }, { name: \"Trustev\", company: \"TransUnion\", category: \"utility\", domains: [\"*.trustev.com\"], totalExecutionTime: 3272, totalOccurrences: 22 }, { name: \"Trustwave\", category: \"utility\", domains: [\"*.trustwave.com\"], totalExecutionTime: 4600, totalOccurrences: 7 }, { name: \"Tryzens TradeState\", company: \"Tryzens\", category: \"analytics\", domains: [\"*.tryzens-analytics.com\"], totalExecutionTime: 969, totalOccurrences: 9 }, { name: \"TubeMogul\", category: \"ad\", domains: [\"*.tubemogul.com\"], totalExecutionTime: 24151, totalOccurrences: 51 }, { name: \"Turn\", category: \"ad\", domains: [\"*.turn.com\"], totalExecutionTime: 4802, totalOccurrences: 72 }, { name: \"Tutorialize\", category: \"customer-success\", domains: [\"*.tutorialize.me\"] }, { name: \"Twenga\", category: \"content\", domains: [\"*.twenga.fr\", \"*\\\n.c4tw.net\", \"*.twenga.co.uk\"], examples: [\"tracker.twenga.co.uk\"] }, { name: \"Twitframe\", company: \"Superblock\", category: \"utility\", domains: [\"*.twitframe.com\"] }, { name: \"Twitter Online Conversion Tracking\", company: \"Twitter\", category: \"ad\", domains: [\"*.ads-twitter.com\", \"analytics.twitter.com\"], examples: [\"static.ads-twitter.com\"], totalExecutionTime: 6170585, totalOccurrences: 73452 }, { name: \"Twitter Short URL\", company: \"Twitter\", category: \"social\", domains: [\"*.t.co\"] }, { name: \"Twyn Group\", category: \"ad\", domains: [\"*.twyn.com\"] }, { name: \"Tynt\", company: \"33 Across\", category: \"ad\", domains: [\"*.tynt.com\"], totalExecutionTime: 41643525, totalOccurrences: 212415 }, { name: \"Typepad\", category: \"hosting\", domains: [\"*.typepad.com\"], totalExecutionTime: 834082, totalOccurrences: 813 }, { name: \"TyrbooBytes\", category: \"utility\", domains: [\"*.turbobytes.net\"] }, { name: \"UPS i-parcel\", company: \"UPS\", category: \"other\", domains: [\"*.i-parcel.com\"] }, { name: \"US Media C\\\nonsulting\", category: \"ad\", domains: [\"*.mediade.sk\"] }, { name: \"Ubertags\", category: \"tag-manager\", domains: [\"*.ubertags.com\"] }, { name: \"Umbel\", category: \"analytics\", domains: [\"*.umbel.com\"] }, { name: \"Unanimis\", company: \"Switch\", category: \"ad\", domains: [\"*.unanimis.co.uk\"] }, { name: \"Unbounce\", category: \"ad\", domains: [\"*.ubembed.com\", \"*.unbounce.com\", \"d2xxq4ijfwetlm.cloudfront.net\", \"d9hhrg4mnvzow.cloudfront.net\"], totalExecutionTime: 2902422, totalOccurrences: 8808 }, { name: \"Underdog Media\", category: \"ad\", domains: [\"*.underdog.media\", \"*.udmserve.net\"], totalExecutionTime: 524141, totalOccurrences: 289 }, { name: \"Understand Digital\", category: \"ad\", domains: [\"*.redirecting2.net\"] }, { name: \"Undertone\", company: \"Perion\", category: \"ad\", domains: [\"*.legolas-media.com\"], examples: [\"rt.legolas-media.com\"] }, { name: \"Unidays\", category: \"ad\", domains: [\"*.myunidays.com\", \"*.unidays.world\"] }, { name: \"Uniqodo\", category: \"ad\", domains: [\"*.uniqodo.com\"] }, { name: \"\\\nUnite\", category: \"ad\", domains: [\"*.uadx.com\"] }, { name: \"United Card Services\", category: \"utility\", domains: [\"*.ucs.su\"] }, { name: \"United Internet\", category: \"hosting\", domains: [\"*.uicdn.com\"], totalExecutionTime: 14225, totalOccurrences: 75 }, { name: \"United Internet Media\", category: \"ad\", domains: [\"*.ui-portal.de\"], totalExecutionTime: 20307, totalOccurrences: 59 }, { name: \"United Internet Media AG\", category: \"hosting\", domains: [\"*.tifbs.net\", \"*.uicdn.net\", \"*.uimserv.net\"], totalExecutionTime: 1737, totalOccurrences: 48 }, { name: \"Unknown\", category: \"other\", domains: [] }, { name: \"Unruly Media\", category: \"ad\", domains: [\"*.unrulymedia.com\"], totalExecutionTime: 679, totalOccurrences: 1789 }, { name: \"UpBuild\", category: \"ad\", domains: [\"*.upbuild.io\"], examples: [\"www.upbuild.io\"] }, { name: \"UpSellit\", category: \"analytics\", domains: [\"*.upsellit.com\"], examples: [\"www.upsellit.com\"], totalExecutionTime: 289920, totalOccurrences: 1013 }, { name: \"Upland Software\",\n    category: \"hosting\", domains: [\"*.clickability.com\"] }, { name: \"Airship\", category: \"marketing\", domains: [\"*.urbanairship.com\", \"*.aswpsdkus.com\"], totalExecutionTime: 4666, totalOccurrences: 37 }, { name: \"UsabilityTools\", category: \"analytics\", domains: [\"*.usabilitytools.com\"] }, { name: \"Usablenet.net\", category: \"utility\", domains: [\"*.usablenet.net\"] }, { name: \"Use It Better\", category: \"analytics\", domains: [\"*.useitbetter.com\"] }, { name: \"User Replay\", category: \"analytics\", domains: [\"*.userreplay.net\"] }, { name: \"UserReport\", category: \"analytics\", domains: [\"*.userreport.com\"], totalExecutionTime: 133479, totalOccurrences: 476 }, { name: \"Userneeds\", category: \"analytics\", domains: [\"*.userneeds.dk\"] }, { name: \"Userzoom\", category: \"analytics\", domains: [\"*.userzoom.com\"], totalExecutionTime: 5093, totalOccurrences: 4 }, { name: \"V12 Retail Finance\", category: \"utility\", domains: [\"*.v12finance.com\"] }, { name: \"Vacaciones eDreams\", category: \"content\", domains: [\"\\\n*.odistatic.net\"] }, { name: \"Varick Media Management\", category: \"ad\", domains: [\"*.vmmpxl.com\"] }, { name: \"Vdopia Chocolate\", company: \"Vdopia\", category: \"ad\", domains: [\"*.vdopia.com\"] }, { name: \"Ve\", company: \"Ve\", homepage: \"https://www.ve.com/\", category: \"marketing\", domains: [\"*.veinteractive.com\", \"*.ve.com\"] }, { name: \"Ve Interactive\", company: \"Ve\", category: \"ad\", domains: [\"*.vepxl1.net\", \"*.adgenie.co.uk\"] }, { name: \"Vee24\", category: \"customer-success\", domains: [\"*.vee24.com\"], totalExecutionTime: 20941, totalOccurrences: 38 }, { name: \"Veeseo\", category: \"content\", domains: [\"*.veeseo.com\"] }, { name: \"Venatus Media\", category: \"marketing\", domains: [\"*.alcvid.com\", \"*.venatusmedia.com\"] }, { name: \"Veoxa\", category: \"ad\", domains: [\"*.veoxa.com\"] }, { name: \"Vergic AB\", category: \"customer-success\", domains: [\"*.psplugin.com\"], totalExecutionTime: 48232, totalOccurrences: 71 }, { name: \"Vergic Engage Platform\", company: \"Vergic\", category: \"customer-success\", domains: [\n    \"*.vergic.com\"], totalExecutionTime: 41524, totalOccurrences: 57 }, { name: \"Verisign (Symantec)\", category: \"utility\", domains: [\"*.verisign.com\"] }, { name: \"Verizon\", category: \"utility\", domains: [\"*.public-trust.com\"], examples: [\"www.public-trust.com\"] }, { name: \"Verizon Digital Media CDN\", homepage: \"https://www.verizondigitalmedia.com/\", category: \"cdn\", domains: [\"*.edgecastcdn.net\", \"*.edgecastdns.net\"], totalExecutionTime: 98698, totalOccurrences: 108 }, { name: \"Verizon Uplynk\", company: \"Verizon\", category: \"content\", domains: [\"*.uplynk.com\"], totalExecutionTime: 572, totalOccurrences: 4 }, { name: \"Vero\", company: \"Semblance\", category: \"ad\", domains: [\"*.getvero.com\", \"d3qxef4rp70elm.cloudfront.net\"], totalExecutionTime: 613, totalOccurrences: 10 }, { name: \"VertaMedia\", category: \"ad\", domains: [\"*.vertamedia.com\"] }, { name: \"Vertical Mass\", category: \"ad\", domains: [\"*.vmweb.net\"] }, { name: \"Vestorly\", category: \"ad\", domains: [\"*.oodalab.com\"] }, { name: \"Vext\\\nras\", category: \"other\", domains: [\"*.vextras.com\"], totalExecutionTime: 4484, totalOccurrences: 42 }, { name: \"Viacom\", category: \"content\", domains: [\"*.mtvnservices.com\"], totalExecutionTime: 15501, totalOccurrences: 44 }, { name: \"Vibrant Media\", category: \"ad\", domains: [\"*.intellitxt.com\", \"*.picadmedia.com\"] }, { name: \"VidPulse\", category: \"analytics\", domains: [\"*.vidpulse.com\"] }, { name: \"Video Media Groep\", category: \"ad\", domains: [\"*.vmg.host\", \"*.inpagevideo.nl\"] }, { name: \"VideoHub\", company: \"Tremor Video\", category: \"ad\", domains: [\"*.scanscout.com\"], examples: [\"dt.scanscout.com\"] }, { name: \"Videology\", category: \"ad\", domains: [\"*.tidaltv.com\"] }, { name: \"Vidible\", category: \"ad\", domains: [\"*.vidible.tv\"] }, { name: \"VigLink\", category: \"ad\", domains: [\"*.viglink.com\"], totalExecutionTime: 3670311, totalOccurrences: 6219 }, { name: \"Vindico\", company: \"Viant\", category: \"ad\", domains: [\"*.vindicosuite.com\"] }, { name: \"Viocorp International\", category: \"content\",\n    domains: [\"*.vioapi.com\"] }, { name: \"ViralNinjas\", category: \"ad\", domains: [\"*.viralninjas.com\"] }, { name: \"Virool\", category: \"ad\", domains: [\"*.virool.com\"] }, { name: \"Virtual Earth\", company: \"Microsoft\", category: \"utility\", domains: [\"*.virtualearth.net\"], totalExecutionTime: 54315, totalOccurrences: 312 }, { name: \"Visely\", company: \"Visely\", category: \"other\", homepage: \"https://visely.io/\", domains: [\"*.visely.io\"] }, { name: \"VisScore\", category: \"analytics\", domains: [\"*.visscore.com\", \"d2hkbi3gan6yg6.cloudfront.net\"] }, { name: \"Visible Measures\", category: \"ad\", domains: [\"*.visiblemeasures.com\"], totalExecutionTime: 11, totalOccurrences: 13 }, { name: \"Visual Studio\", company: \"Microsoft\", category: \"utility\", domains: [\"*.visualstudio.com\"], totalExecutionTime: 3464, totalOccurrences: 3 }, { name: \"VisualDNA\", category: \"ad\", domains: [\"*.visualdna.com\"] }, { name: \"VisualVisitor\", category: \"ad\", domains: [\"*.id-visitors.com\"], examples: [\"frontend.id-visitors.co\\\nm\"], totalExecutionTime: 871, totalOccurrences: 14 }, { name: \"Vivocha S.p.A\", category: \"customer-success\", domains: [\"*.vivocha.com\"], totalExecutionTime: 65471, totalOccurrences: 38 }, { name: \"Vizu (Nielsen)\", category: \"analytics\", domains: [\"*.vizu.com\"] }, { name: \"Vizury\", category: \"ad\", domains: [\"*.vizury.com\"], totalExecutionTime: 1296, totalOccurrences: 20 }, { name: \"VoiceFive\", category: \"analytics\", domains: [\"*.voicefive.com\"] }, { name: \"Volvelle\", company: \"Optomaton\", category: \"ad\", domains: [\"*.volvelle.tech\"] }, { name: \"VouchedFor\", category: \"analytics\", domains: [\"*.vouchedfor.co.uk\"], totalExecutionTime: 30557, totalOccurrences: 18 }, { name: \"WARPCACHE\", category: \"utility\", domains: [\"*.warpcache.net\"] }, { name: \"WISHLIST\", company: \"Shopapps\", category: \"social\", domains: [\"*.shopapps.in\"] }, { name: \"WP Engine\", category: \"hosting\", domains: [\"*.wpengine.com\"], totalExecutionTime: 651034, totalOccurrences: 341 }, { name: \"WalkMe\", category: \"customer-suc\\\ncess\", domains: [\"*.walkme.com\"], totalExecutionTime: 636459, totalOccurrences: 495 }, { name: \"Watching That\", category: \"other\", domains: [\"*.watchingthat.com\"] }, { name: \"Wayfair\", category: \"analytics\", domains: [\"*.wayfair.com\"], examples: [\"t.wayfair.com\"] }, { name: \"Web CEO\", category: \"other\", domains: [\"*.websiteceo.com\"], examples: [\"www.websiteceo.com\"] }, { name: \"Web Dissector\", company: \"Beijing Gridsum Technologies\", category: \"analytics\", domains: [\"*.gridsumdissector.com\", \"*.webdissector.com\"], examples: [\"www.webdissector.com\"] }, { name: \"Web Forensics\", category: \"analytics\", domains: [\"*.webforensics.co.uk\"] }, { name: \"Web Security and Performance\", company: \"NCC Group\", category: \"utility\", domains: [\"*.nccgroup.trust\"] }, { name: \"WebEngage\", category: \"customer-success\", domains: [\"*.webengage.co\", \"*.webengage.com\", \"d23nd6ymopvz52.cloudfront.net\", \"d3701cc9l7v9a6.cloudfront.net\"], totalExecutionTime: 789975, totalOccurrences: 2283 }, { name: \"WebInsight\", company: \"\\\ndotMailer\", category: \"analytics\", domains: [\"*.trackedlink.net\", \"*.trackedweb.net\"], totalExecutionTime: 21241, totalOccurrences: 277 }, { name: \"WebPageOne Solutions\", category: \"other\", domains: [\"*.webpageone.com\"] }, { name: \"WebSpectator\", category: \"ad\", domains: [\"*.webspectator.com\"] }, { name: \"WebTuna\", company: \"Application Performance\", category: \"analytics\", domains: [\"*.webtuna.com\"] }, { name: \"WebVideoCore\", company: \"StreamingVideoProvider\", category: \"content\", domains: [\"*.webvideocore.net\"], totalExecutionTime: 74152, totalOccurrences: 38 }, { name: \"WebWombat\", category: \"utility\", domains: [\"*.ic.com.au\"] }, { name: \"Webcollage\", category: \"customer-success\", domains: [\"*.webcollage.net\"] }, { name: \"Webcore\", category: \"ad\", domains: [\"*.onefeed.co.uk\"] }, { name: \"Webkul\", company: \"Webkul Software\", category: \"utility\", domains: [\"*.webkul.com\"], totalExecutionTime: 172788, totalOccurrences: 490 }, { name: \"Webmarked\", category: \"utility\", domains: [\"*.webmar\\\nked.net\"], totalExecutionTime: 72467, totalOccurrences: 1077 }, { name: \"Weborama\", category: \"ad\", domains: [\"*.weborama.com\", \"*.weborama.fr\"], totalExecutionTime: 45883, totalOccurrences: 372 }, { name: \"WebpageFX\", category: \"ad\", domains: [\"*.leadmanagerfx.com\"], totalExecutionTime: 241118, totalOccurrences: 946 }, { name: \"Webphone\", company: \"IP WEB SERVICES\", category: \"customer-success\", domains: [\"*.webphone.net\"], totalExecutionTime: 4605, totalOccurrences: 20 }, { name: \"Webselect selectcommerce\", company: \"Webselect Internet\", category: \"hosting\", domains: [\"*.webselect.net\"] }, { name: \"Webthinking\", category: \"hosting\", domains: [\"*.webthinking.co.uk\"] }, { name: \"Webtrekk\", category: \"analytics\", domains: [\"*.wbtrk.net\", \"*.webtrekk-asia.net\", \"*.webtrekk.net\", \"*.wt-eu02.net\", \"*.wt-safetag.com\"], totalExecutionTime: 85572, totalOccurrences: 428 }, { name: \"Webtrends\", category: \"analytics\", domains: [\"*.webtrends.com\", \"*.webtrendslive.com\", \"d1q62gfb8siqnm.cloudfront\\\n.net\"], totalExecutionTime: 1437, totalOccurrences: 6 }, { name: \"Webtype\", category: \"cdn\", domains: [\"*.webtype.com\"], totalExecutionTime: 0, totalOccurrences: 1 }, { name: \"White Ops\", category: \"utility\", domains: [\"*.acexedge.com\", \"*.tagsrvcs.com\"] }, { name: \"Whitespace\", category: \"ad\", domains: [\"*.whitespacers.com\"] }, { name: \"WhosOn Live Chat Software\", category: \"customer-success\", domains: [\"*.whoson.com\"], totalExecutionTime: 20753, totalOccurrences: 112 }, { name: \"Wibbitz\", category: \"other\", domains: [\"*.wibbitz.com\"] }, { name: \"Wide Area Communications\", category: \"hosting\", domains: [\"*.widearea.co.uk\"] }, { name: \"WideOrbit\", category: \"marketing\", domains: [\"*.admaym.com\"] }, { name: \"William Reed\", category: \"content\", domains: [\"*.wrbm.com\"], totalExecutionTime: 50, totalOccurrences: 1 }, { name: \"WillyFogg.com\", category: \"content\", domains: [\"*.willyfogg.com\"] }, { name: \"Windows\", company: \"Microsoft\", category: \"utility\", domains: [\"*.windowsupdate.com\"], examples: [\n    \"ctldl.windowsupdate.com\"] }, { name: \"WisePops\", category: \"utility\", domains: [\"*.wisepops.com\"], totalExecutionTime: 2631328, totalOccurrences: 1950 }, { name: \"Wishlist King\", company: \"Appmate\", category: \"other\", homepage: \"https://appmate.io/\", domains: [\"*.appmate.io\"], examples: [\"api.appmate.io\"], totalExecutionTime: 130543, totalOccurrences: 235 }, { name: \"Wishpond Technologies\", category: \"marketing\", domains: [\"*.wishpond.com\", \"*.wishpond.net\"], totalExecutionTime: 771888, totalOccurrences: 1691 }, { name: \"WizRocket Technologies\", category: \"analytics\", domains: [\"*.wzrkt.com\"], totalExecutionTime: 138, totalOccurrences: 2 }, { name: \"Woopra\", category: \"analytics\", domains: [\"*.woopra.com\"], totalExecutionTime: 120767, totalOccurrences: 1366 }, { name: \"Woosmap\", category: \"utility\", domains: [\"*.woosmap.com\"], totalExecutionTime: 58710, totalOccurrences: 139 }, { name: \"WorkCast\", category: \"hosting\", domains: [\"*.workcast.net\"] }, { name: \"World News Media\", category: \"\\\ncontent\", domains: [\"*.wnmedia.co.uk\"] }, { name: \"Worldpay\", category: \"utility\", domains: [\"*.worldpay.com\"], totalExecutionTime: 25852, totalOccurrences: 18 }, { name: \"Wow Analytics\", category: \"analytics\", domains: [\"*.wowanalytics.co.uk\"], totalExecutionTime: 11162, totalOccurrences: 73 }, { name: \"Wowcher\", category: \"ad\", domains: [\"*.wowcher.co.uk\"] }, { name: \"Wufoo\", category: \"utility\", domains: [\"*.wufoo.com\"], totalExecutionTime: 381206, totalOccurrences: 1507 }, { name: \"Wunderkind\", category: \"marketing\", homepage: \"https://www.wunderkind.co/\", domains: [\"*.bounceexchange.com\", \"*.bouncex.net\", \"*.wknd.ai\", \"*.cdnbasket.net\", \"*.cdnwidget.com\"], examples: [\"events.bouncex.net\", \"tag.wknd.ai\", \"data.cdnbasket.net\", \"pix.cdnwidget.com\"], totalExecutionTime: 2016506, totalOccurrences: 1278 }, { name: \"Wyng\", category: \"ad\", domains: [\"*.offerpop.com\"] }, { name: \"XMLSHOP\", category: \"hosting\", domains: [\"*.xmlshop.biz\"] }, { name: \"XiTi\", company: \"AT Internet\", category: \"\\\nanalytics\", domains: [\"*.xiti.com\", \"*.aticdn.net\"], homepage: \"https://www.atinternet.com/en/\", examples: [\"tag.aticdn.net/123456789/smarttag.js\"], totalExecutionTime: 918257, totalOccurrences: 8483 }, { name: \"YUDU\", category: \"content\", domains: [\"*.yudu.com\"] }, { name: \"Yahoo! Ad Exchange\", company: \"Yahoo!\", category: \"ad\", domains: [\"*.yieldmanager.com\", \"*.browsiprod.com\"], examples: [\"yield-manager.browsiprod.com\"], totalExecutionTime: 12720569, totalOccurrences: 4994 }, { name: \"Yahoo! JAPAN Ads\", company: \"Yahoo! JAPAN\", category: \"ad\", homepage: \"https://marketing.yahoo.co.jp/service/yahooads/\", domains: [\"yads.c.yimg.jp\", \"s.yimg.jp\", \"b92.yahoo.co.jp\"], examples: [\"yads.c.yimg.jp/js/yads-async.js\", \"s.yimg.jp/images/listing/tool/yads/ydn/creative/video/ytop_video_timeline_sp.min.js\", \"b92.yahoo.co.jp/js/s_retargeting.js\"], totalExecutionTime: 6236624, totalOccurrences: 37464 }, { name: \"Yahoo! Tag Manager\", company: \"Yahoo! JAPAN\", category: \"tag-manager\", homepage: \"http\\\ns://marketing.yahoo.co.jp/service/tagmanager/\", domains: [\"*.yjtag.jp\"], examples: [\"s.yjtag.jp/tag.js\"] }, { name: \"Yahoo! Small Business\", company: \"Yahoo!\", category: \"hosting\", domains: [\"*.aabacosmallbusiness.com\"] }, { name: \"Yellow Robot\", category: \"ad\", domains: [\"*.backinstock.org\"], totalExecutionTime: 15268, totalOccurrences: 508 }, { name: \"YieldPartners\", category: \"ad\", domains: [\"*.yieldpartners.com\"] }, { name: \"Yieldbot\", category: \"ad\", domains: [\"*.yldbt.com\"] }, { name: \"Yieldify\", category: \"ad\", domains: [\"*.yieldify.com\", \"*.yieldifylabs.com\", \"d33wq5gej88ld6.cloudfront.net\", \"dwmvwp56lzq5t.cloudfront.net\"], examples: [\"geo.yieldifylabs.com\"], totalExecutionTime: 513761, totalOccurrences: 168 }, { name: \"Yieldlab\", category: \"ad\", domains: [\"*.yieldlab.net\"], totalExecutionTime: 54, totalOccurrences: 8 }, { name: \"Yieldmo\", category: \"ad\", domains: [\"*.yieldmo.com\"], totalExecutionTime: 51128, totalOccurrences: 2375 }, { name: \"Yieldr\", category: \"ad\", domains: [\n    \"*.254a.com\"] }, { name: \"Yo\", category: \"utility\", domains: [\"*.yopify.com\"] }, { name: \"YoYo\", category: \"utility\", domains: [\"*.goadservices.com\"] }, { name: \"Yotpo\", homepage: \"https://www.yotpo.com/\", category: \"marketing\", domains: [\"*.yotpo.com\", \"*.swellrewards.com\"], totalExecutionTime: 16919447, totalOccurrences: 26094 }, { name: \"Yottaa\", category: \"hosting\", domains: [\"*.yottaa.com\", \"*.yottaa.net\"], totalExecutionTime: 798791, totalOccurrences: 753 }, { name: \"YourAmigo\", category: \"utility\", domains: [\"*.youramigo.com\"] }, { name: \"YuMe\", category: \"ad\", domains: [\"*.yume.com\", \"*.yumenetworks.com\"], examples: [\"cks.yumenetworks.com\"] }, { name: \"Yummley\", category: \"other\", domains: [\"*.yummly.com\"], totalExecutionTime: 14163, totalOccurrences: 6 }, { name: \"ZEDO\", category: \"ad\", domains: [\"*.zedo.com\"] }, { name: \"Zafu\", category: \"analytics\", domains: [\"*.zafu.com\"] }, { name: \"Zaius\", category: \"ad\", domains: [\"*.zaius.com\"] }, { name: \"Zamplus ad\", category: \"ad\",\n    domains: [\"*.zampda.net\"] }, { name: \"Zanox\", category: \"ad\", domains: [\"*.zanox.com\", \"*.zanox.ws\"] }, { name: \"Zapper\", category: \"utility\", domains: [\"*.zapper.com\"] }, { name: \"Zarget\", category: \"analytics\", domains: [\"*.zarget.com\"] }, { name: \"Zemanta\", category: \"ad\", domains: [\"*.zemanta.com\"], totalExecutionTime: 2735, totalOccurrences: 28 }, { name: \"Zen Internet\", category: \"other\", domains: [\"*.zyen.com\"] }, { name: \"Zenovia Digital Exchange\", category: \"ad\", domains: [\"*.rhythmxchange.com\", \"*.zenoviaexchange.com\"] }, { name: \"ZergNet\", category: \"content\", domains: [\"*.zergnet.com\"], totalExecutionTime: 186, totalOccurrences: 4 }, { name: \"Zerogrey\", category: \"hosting\", domains: [\"*.zerogrey.com\"] }, { name: \"Ziff Davis Tech\", category: \"ad\", domains: [\"*.adziff.com\", \"*.zdbb.net\"], totalExecutionTime: 30706, totalOccurrences: 93 }, { name: \"Zmags\", category: \"marketing\", domains: [\"*.zmags.com\"], totalExecutionTime: 262514, totalOccurrences: 119 }, { name: \"Zolando\",\n    category: \"content\", domains: [\"*.ztat.net\"], totalExecutionTime: 229623, totalOccurrences: 48 }, { name: \"Zoover\", category: \"analytics\", domains: [\"*.zoover.nl\", \"*.zoover.co.uk\"], totalExecutionTime: 9173, totalOccurrences: 2 }, { name: \"Zopim\", category: \"customer-success\", domains: [\"*.zopim.io\"] }, { name: \"[24]7\", category: \"customer-success\", domains: [\"*.247-inc.net\", \"*.247inc.net\", \"d1af033869koo7.cloudfront.net\"], totalExecutionTime: 24965, totalOccurrences: 20 }, { name: \"adKernel\", category: \"ad\", domains: [\"*.adkernel.com\"], totalExecutionTime: 19140, totalOccurrences: 9621 }, { name: \"adMarketplace\", company: \"AMPexchange\", category: \"ad\", domains: [\"*.ampxchange.com\", \"*.admarketplace.net\"] }, { name: \"addtocalendar\", category: \"utility\", domains: [\"*.addtocalendar.com\"] }, { name: \"adnanny\", category: \"ad\", domains: [\"*.adserver01.de\"], totalExecutionTime: 2, totalOccurrences: 6 }, { name: \"affilinet\", category: \"ad\", domains: [\"*.reussissonsensemble.fr\", \"*.succe\\\nssfultogether.co.uk\"] }, { name: \"audioBoom\", category: \"social\", domains: [\"*.audioboom.com\", \"*.audioboo.fm\"], totalExecutionTime: 136729, totalOccurrences: 57 }, { name: \"bPay by Barclaycard\", company: \"Barclays Bank\", category: \"utility\", domains: [\"*.bpay.co.uk\"] }, { name: \"bRealTime\", category: \"ad\", domains: [\"*.brealtime.com\"], totalExecutionTime: 4479, totalOccurrences: 76 }, { name: \"bd4travel\", category: \"analytics\", domains: [\"*.bd4travel.com\"] }, { name: \"bizinformation-VOID\", company: \"bizinformation\", category: \"analytics\", domains: [\"*.bizinformation.org\"] }, { name: \"carrot\", category: \"social\", domains: [\"*.sharebutton.co\"] }, { name: \"cloudIQ\", category: \"analytics\", domains: [\"*.cloud-iq.com\"] }, { name: \"comScore\", category: \"analytics\", domains: [\"*.adxpose.com\", \"*.comscore.com\", \"*.sitestat.com\", \"*.zqtk.net\"], totalExecutionTime: 4938, totalOccurrences: 3 }, { name: \"content.ad\", category: \"ad\", domains: [\"*.content.ad\"] }, { name: \"d3 Media\", company: \"d3 Tec\\\nhnologies\", category: \"other\", domains: [\"*.d3sv.net\"] }, { name: \"dexiMEDIA\", category: \"ad\", domains: [\"*.deximedia.com\"] }, { name: \"dianomi\", category: \"ad\", domains: [\"*.dianomi.com\", \"*.dianomioffers.co.uk\"], totalExecutionTime: 52461, totalOccurrences: 86 }, { name: \"donReach\", category: \"social\", domains: [\"*.donreach.com\"] }, { name: \"dotMailer\", category: \"ad\", domains: [\"*.dmtrk.com\", \"*.dotmailer.com\", \"*.emlfiles.com\"] }, { name: \"dotMailer Surveys\", company: \"dotMailer\", category: \"analytics\", domains: [\"*.dotmailer-surveys.com\"] }, { name: \"dstillery\", category: \"ad\", domains: [\"*.dstillery.com\", \"*.media6degrees.com\"], totalExecutionTime: 1160, totalOccurrences: 12 }, { name: \"eBay\", category: \"ad\", domains: [\"*.ebay.com\", \"*.ebayimg.com\", \"*.fetchback.com\"], totalExecutionTime: 600826, totalOccurrences: 1026 }, { name: \"eBay Enterprise\", category: \"hosting\", domains: [\"*.csdata1.com\", \"*.gsipartners.com\"] }, { name: \"eBuzzing\", company: \"Teads Managed Services\", category: \"\\\nad\", domains: [\"*.ebz.io\"] }, { name: \"eDigital Research\", category: \"customer-success\", domains: [\"*.edigitalresearch.com\", \"*.edigitalsurvey.com\", \"*.edrcdn.com\", \"*.ecustomeropinions.com\"] }, { name: \"eGain\", category: \"analytics\", domains: [\"*.analytics-egain.com\", \"*.egain.com\"], totalExecutionTime: 8418, totalOccurrences: 74 }, { name: \"eHost\", category: \"hosting\", domains: [\"*.ehosts.net\"] }, { name: \"eKomi\", category: \"analytics\", domains: [\"*.ekomi.com\", \"*.ekomi.de\"], totalExecutionTime: 51192, totalOccurrences: 17 }, { name: \"eWAY\", company: \"Web Active Pty\", category: \"utility\", domains: [\"*.eway.com.au\"], examples: [\"www.eway.com.au\"], totalExecutionTime: 11094, totalOccurrences: 1 }, { name: \"eXTReMe digital\", category: \"analytics\", domains: [\"*.extreme-dm.com\"], totalExecutionTime: 3491, totalOccurrences: 78 }, { name: \"eXelate\", category: \"ad\", domains: [\"*.exelator.com\"], totalExecutionTime: 17905, totalOccurrences: 246 }, { name: \"ecommercefeed.net\", category: \"market\\\ning\", domains: [\"*.ecommercefeed.net\"] }, { name: \"engage:BDR\", category: \"ad\", domains: [\"*.bnmla.com\", \"*.ebdr3.com\"] }, { name: \"epago\", category: \"ad\", domains: [\"*.adaos-ads.net\"] }, { name: \"epoq internet services\", category: \"analytics\", domains: [\"*.epoq.de\"], totalExecutionTime: 84260, totalOccurrences: 122 }, { name: \"etouches\", category: \"hosting\", domains: [\"*.etouches.com\"], examples: [\"www.etouches.com\"] }, { name: \"etracker\", category: \"analytics\", domains: [\"*.etracker.com\", \"*.etracker.de\"], examples: [\"www.etracker.com\"], totalExecutionTime: 2076262, totalOccurrences: 5626 }, { name: \"everestads.com\", category: \"content\", domains: [\"*.verestads.net\"] }, { name: \"exebid.DCA\", company: \"Data-Centric Alliance\", category: \"ad\", domains: [\"*.exe.bid\"] }, { name: \"eyeReturn Marketing\", category: \"marketing\", domains: [\"*.eyereturn.com\"] }, { name: \"feedoptimise\", category: \"hosting\", domains: [\"*.feedoptimise.com\", \"d1w78njrm56n7g.cloudfront.net\"], totalExecutionTime: 126, totalOccurrences: 2 },\n    { name: \"fifty-five\", category: \"ad\", domains: [\"*.55labs.com\"] }, { name: \"fluct\", category: \"ad\", domains: [\"*.adingo.jp\"], totalExecutionTime: 5114249, totalOccurrences: 12890 }, { name: \"freegeoip.net\", company: \"(community-funded)\", category: \"utility\", domains: [\"*.freegeoip.net\"] }, { name: \"freewheel.tv\", category: \"content\", domains: [\"*.fwmrm.net\"], totalExecutionTime: 3847, totalOccurrences: 42 }, { name: \"gnatta\", category: \"customer-success\", domains: [\"*.gnatta.com\"] }, { name: \"home.pl\", category: \"hosting\", domains: [\"*.nscontext.eu\"] }, { name: \"hyfn\", category: \"ad\", domains: [\"*.hyfn.com\"] }, { name: \"iAdvize SAS\", category: \"customer-success\", domains: [\"*.iadvize.com\"], totalExecutionTime: 286995, totalOccurrences: 844 }, { name: \"iBillboard\", category: \"ad\", domains: [\"*.ibillboard.com\"], totalExecutionTime: 303, totalOccurrences: 2 }, { name: \"iCrossing\", category: \"ad\", domains: [\"*.ic-live.com\"] }, { name: \"iFactory\", company: \"RDW Group\", category: \"hostin\\\ng\", domains: [\"*.ifactory.com\"] }, { name: \"iGoDigital\", category: \"analytics\", domains: [\"*.igodigital.com\"], totalExecutionTime: 1800, totalOccurrences: 21 }, { name: \"iJento\", company: \"Fopsha\", category: \"ad\", domains: [\"*.ijento.com\"] }, { name: \"iPage\", category: \"hosting\", domains: [\"*.ipage.com\"], examples: [\"www.ipage.com\"], totalExecutionTime: 490, totalOccurrences: 6 }, { name: \"iPerceptions\", category: \"customer-success\", domains: [\"*.iperceptions.com\"], totalExecutionTime: 626044, totalOccurrences: 4662 }, { name: \"iTunes\", company: \"Apple\", category: \"content\", domains: [\"*.mzstatic.com\"] }, { name: \"imgix\", company: \"Zebrafish Labs\", category: \"utility\", domains: [\"*.imgix.net\"], totalExecutionTime: 40073, totalOccurrences: 98 }, { name: \"infogr.am\", category: \"utility\", domains: [\"*.infogr.am\", \"*.jifo.co\"], totalExecutionTime: 2008949, totalOccurrences: 233 }, { name: \"iotec\", category: \"analytics\", domains: [\"*.dsp.io\"] }, { name: \"iovation\", category: \"utility\", domains: [\n    \"*.iesnare.com\"], totalExecutionTime: 270232, totalOccurrences: 2159 }, { name: \"ipinfo.io\", category: \"utility\", domains: [\"*.ipinfo.io\"] }, { name: \"issuu\", category: \"content\", domains: [\"*.issuu.com\", \"*.isu.pub\"], totalExecutionTime: 5607951, totalOccurrences: 2714 }, { name: \"iubenda\", category: \"utility\", domains: [\"*.iubenda.com\"], examples: [\"www.iubenda.com\"], totalExecutionTime: 69911073, totalOccurrences: 97074 }, { name: \"j2 Cloud Services\", category: \"ad\", domains: [\"*.campaigner.com\"], totalExecutionTime: 12708, totalOccurrences: 28 }, { name: \"jsonip.com\", category: \"analytics\", domains: [\"*.jsonip.com\"] }, { name: \"linkpulse\", category: \"analytics\", domains: [\"*.lp4.io\"] }, { name: \"loGo_net\", category: \"analytics\", domains: [\"*.logo-net.co.uk\"] }, { name: \"mainADV\", category: \"ad\", domains: [\"*.httptrack.com\", \"*.solocpm.com\"] }, { name: \"mbr targeting\", category: \"ad\", domains: [\"*.m6r.eu\"], totalExecutionTime: 17, totalOccurrences: 1 }, { name: \"media.ventive\", category: \"\\\nad\", domains: [\"*.contentspread.net\"] }, { name: \"metrigo\", category: \"ad\", domains: [\"*.metrigo.com\"] }, { name: \"minicabit.com\", category: \"content\", domains: [\"*.minicabit.com\"] }, { name: \"mobiManage\", category: \"hosting\", domains: [\"*.mobimanage.com\"] }, { name: \"moving-pictures\", category: \"other\", domains: [\"*.moving-pictures.biz\", \"*.v6-moving-pictures.com\", \"*.vtstat.com\", \"*.moving-pictures.de\"] }, { name: \"my6sense\", category: \"ad\", domains: [\"*.mynativeplatform.com\"] }, { name: \"myThings\", category: \"ad\", domains: [\"*.mythings.com\", \"*.mythingsmedia.net\"] }, { name: \"mymovies\", category: \"content\", domains: [\"*.mymovies.net\"] }, { name: \"nRelate-VOID\", company: \"nRelate\", category: \"content\", domains: [\"*.nrelate.com\"] }, { name: \"nToklo\", category: \"analytics\", domains: [\"*.ntoklo.com\"] }, { name: \"neXeps\", category: \"ad\", domains: [\"*.nexeps.com\"] }, { name: \"ninemsn Pty.\", category: \"utility\", domains: [\"*.ninemsn.com.au\"] }, { name: \"nugg.ad\", category: \"ad\", domains: [\n    \"*.nuggad.net\"] }, { name: \"numero interactive\", company: \"numero\", category: \"ad\", domains: [\"*.numerointeractive.com\"] }, { name: \"optMD\", company: \"Optimax Media Delivery\", category: \"ad\", domains: [\"*.optmd.com\"] }, { name: \"otracking.com\", category: \"analytics\", domains: [\"*.otracking.com\"] }, { name: \"paysafecard\", company: \"Paysafe Group\", category: \"utility\", domains: [\"*.paysafecard.com\"] }, { name: \"piano\", category: \"ad\", domains: [\"*.npttech.com\", \"*.tinypass.com\"], examples: [\"www.npttech.com\"], totalExecutionTime: 1016108, totalOccurrences: 1146 }, { name: \"piclike\", category: \"ad\", domains: [\"*.piclike.us\"] }, { name: \"placehold.it\", category: \"utility\", domains: [\"*.placehold.it\"] }, { name: \"plista\", category: \"ad\", domains: [\"*.plista.com\"] }, { name: \"prebid.org\", category: \"utility\", domains: [\"*.prebid.org\"], totalExecutionTime: 462, totalOccurrences: 1 }, { name: \"reEmbed\", category: \"other\", domains: [\"*.reembed.com\"] }, { name: \"reddit\", category: \"social\", domains: [\n    \"*.reddit.com\", \"*.redditstatic.com\"], examples: [\"www.redditstatic.com\"], totalExecutionTime: 4113522, totalOccurrences: 18483 }, { name: \"rewardStyle.com\", category: \"ad\", domains: [\"*.rewardstyle.com\"], totalExecutionTime: 280999, totalOccurrences: 1491 }, { name: \"rss2json\", category: \"utility\", domains: [\"*.rss2json.com\"], totalExecutionTime: 1380, totalOccurrences: 18 }, { name: \"sage Pay\", company: \"Sage Pay Europe\", category: \"utility\", domains: [\"*.sagepay.com\"], totalExecutionTime: 4481, totalOccurrences: 40 }, { name: \"section.io\", category: \"utility\", domains: [\"*.squixa.net\"], examples: [\"beacon.squixa.net\", \"s.squixa.net\"] }, { name: \"smartclip\", category: \"ad\", domains: [\"*.smartclip.net\"], totalExecutionTime: 41051, totalOccurrences: 21 }, { name: \"sovrn\", category: \"ad\", domains: [\"*.lijit.com\"], totalExecutionTime: 2389059, totalOccurrences: 27306 }, { name: \"stackpile.io\", company: \"StackPile\", category: \"tag-manager\", domains: [\"*.stackpile.io\"] }, { name: \"temp\\\nlate-help.com\", category: \"hosting\", domains: [\"*.template-help.com\"], totalExecutionTime: 16016, totalOccurrences: 13 }, { name: \"test\", company: \"test only\", category: \"other\", domains: [\"*.testtesttest.com\"] }, { name: \"trueAnthem\", category: \"social\", domains: [\"*.tru.am\"] }, { name: \"tweetmeme-VOID\", company: \"tweetmeme\", category: \"analytics\", domains: [\"*.tweetmeme.com\"] }, { name: \"uLogin\", category: \"other\", domains: [\"*.ulogin.ru\"] }, { name: \"uLogix\", category: \"ad\", domains: [\"*.ulogix.ru\"] }, { name: \"ucfunnel ucX\", company: \"ucfunnel\", category: \"ad\", domains: [\"*.aralego.com\"], totalExecutionTime: 1469345, totalOccurrences: 7945 }, { name: \"up-value\", category: \"ad\", domains: [\"*.up-value.de\"] }, { name: \"wywy\", category: \"ad\", domains: [\"*.wywy.com\", \"*.wywyuserservice.com\"] }, { name: \"CDK Dealer Management\", company: \"CDK Global\", homepage: \"https://www.cdkglobal.com/us\", category: \"hosting\", domains: [\"*.assets-cdk.com\"], examples: [\"media-cf.assets-cdk.com\"], totalExecutionTime: 1052,\n    totalOccurrences: 4 }, { name: \"fam\", company: \"Fing Co Ltd.\", homepage: \"http://admin.fam-ad.com/report/\", category: \"ad\", domains: [\"*.fam-ad.com\"], examples: [\"img.fam-ad.com\"], totalExecutionTime: 1816, totalOccurrences: 10 }, { name: \"zypmedia\", category: \"ad\", domains: [\"*.extend.tv\"] }, { name: \"codigo\", homepage: \"https://www.codigo.se\", category: \"analytics\", domains: [\"*.codigo.se\"], examples: [\"analytics.codigo.se\"], totalExecutionTime: 469, totalOccurrences: 10 }, { name: \"Playground\", homepage: \"https://playground.xyz\", category: \"ad\", domains: [\"*.playground.xyz\"], examples: [\"ads.playground.xyz\"], totalExecutionTime: 2767, totalOccurrences: 26 }, { name: \"RAM\", homepage: \"https://www2.rampanel.com/\", category: \"analytics\", domains: [\"*.rampanel.com\"], examples: [\"inviso.rampanel.com\"], totalExecutionTime: 15413, totalOccurrences: 1 }, { name: \"Adition\", homepage: \"https://www.adition.com\", category: \"ad\", domains: [\"*.adition.com\"], examples: [\"dsp.adfarm1.adition.co\\\nm\"], totalExecutionTime: 74399, totalOccurrences: 491 }, { name: \"Widespace\", homepage: \"https://www.widespace.com\", category: \"ad\", domains: [\"*.widespace.com\"], examples: [\"sync.widespace.com\"] }, { name: \"Colpirio\", homepage: \"https://www.widespace.com\", category: \"analytics\", domains: [\"*.colpirio.com\"], examples: [\"proxy-tracker.colpirio.com\"] }, { name: \"Brandmetrics\", homepage: \"https://www.brandmetrics.com\", category: \"analytics\", domains: [\"*.brandmetrics.com\"], examples: [\"collector.brandmetrics.com\", \"cdn.brandmetrics.com\"], totalExecutionTime: 3689914, totalOccurrences: 30850 }, { name: \"EasyAd\", homepage: \"https://web.easy-ads.com/\", category: \"ad\", domains: [\"*.easy-ads.com\"], examples: [\"ads.easy-ads.com\"] }, { name: \"Glimr\", homepage: \"https://glimr.io/\", category: \"analytics\", domains: [\"*.glimr.io\"], examples: [\"pixel.glimr.io\"] }, { name: \"Webtreck\", homepage: \"https://www.webtrekk.com/en/home/\", category: \"analytics\", domains: [\"*.wcfbc.net\"], examples: [\"fbc.wcfbc.\\\nnet\"] }, { name: \"DigiTrust\", homepage: \"http://www.digitru.st/\", category: \"analytics\", domains: [\"*.digitru.st\"], examples: [\"cdn.digitru.st\"] }, { name: \"Kantar Sifo\", homepage: \"https://www.kantarsifo.se\", category: \"analytics\", domains: [\"*.research-int.se\"], examples: [\"trafficgateway.research-int.se\"], totalExecutionTime: 375, totalOccurrences: 1 }, { name: \"Concert\", homepage: \"https://concert.io/\", category: \"ad\", domains: [\"*.concert.io\"], examples: [\"cdn.concert.io\"], totalExecutionTime: 317481, totalOccurrences: 336 }, { name: \"Emerse\", homepage: \"https://www.emerse.com/\", category: \"ad\", domains: [\"*.emerse.com\"], examples: [\"tracking.emerse.com\"], totalExecutionTime: 2872, totalOccurrences: 13 }, { name: \"Iterate\", homepage: \"https://iteratehq.com/\", category: \"analytics\", domains: [\"*.iteratehq.com\"], totalExecutionTime: 8751, totalOccurrences: 72 }, { name: \"Cookiebot\", homepage: \"https://www.cookiebot.com/\", category: \"utility\", domains: [\"*.cookiebot.com\"], examples: [\n    \"consent.cookiebot.com\"], totalExecutionTime: 64865019, totalOccurrences: 187732 }, { name: \"Netlify\", homepage: \"https://www.netlify.com/\", category: \"utility\", domains: [\"*.netlify.com\", \"*.netlifyusercontent.com\"], examples: [\"cloud.netlifyusercontent.com\"], totalExecutionTime: 299527, totalOccurrences: 1323 }, { name: \"Scroll\", homepage: \"https://scroll.com/\", category: \"utility\", domains: [\"*.scroll.com\"], examples: [\"static.scroll.com\", \"connect.scroll.com\"] }, { name: \"Consumable\", homepage: \"https://consumable.com/\", category: \"ad\", domains: [\"*.serverbid.com\"], totalExecutionTime: 15203, totalOccurrences: 266 }, { name: \"DMD Marketing\", homepage: \"https://www.dmdconnects.com/\", category: \"ad\", domains: [\"*.medtargetsystem.com\"], totalExecutionTime: 257224, totalOccurrences: 846 }, { name: \"Catchpoint\", homepage: \"https://www.catchpoint.com/\", category: \"analytics\", domains: [\"*.3gl.net\", \"*.3genlabs.net\"], totalExecutionTime: 14822, totalOccurrences: 160 }, { name: \"Termin\\\nus\", homepage: \"https://terminus.com/\", category: \"ad\", domains: [\"*.terminus.services\"], totalExecutionTime: 28077, totalOccurrences: 207 }, { name: \"Acceptable Ads\", homepage: \"https://acceptableads.com/\", category: \"ad\", domains: [\"*.aaxads.com\", \"*.aaxdetect.com\"], totalExecutionTime: 2200, totalOccurrences: 34 }, { name: \"ClearBrain\", homepage: \"https://www.clearbrain.com/\", category: \"analytics\", domains: [\"*.clearbrain.com\"], examples: [\"api.clearbrain.com\"] }, { name: \"Optanon\", homepage: \"https://www.cookielaw.org/\", category: \"consent-provider\", domains: [\"*.onetrust.com\", \"*.cookielaw.org\"], examples: [\"cdn.cookielaw.org\", \"geolocation.onetrust.com\"], totalExecutionTime: 55293468, totalOccurrences: 113700 }, { name: \"TrustArc\", homepage: \"https://www.trustarc.com/\", category: \"utility\", domains: [\"*.trustarc.com\"], examples: [\"choices.trustarc.com\", \"consent.trustarc.com\"], totalExecutionTime: 2429376, totalOccurrences: 5941 }, { name: \"iSpot.tv\", homepage: \"https://www.ispo\\\nt.tv/\", category: \"ad\", domains: [\"*.ispot.tv\"], examples: [\"pt.ispot.tv\"], totalExecutionTime: 2947, totalOccurrences: 10 }, { name: \"RevJet\", homepage: \"https://www.revjet.com/\", category: \"ad\", domains: [\"*.revjet.com\"], examples: [\"pix.revjet.com\", \"ads.revjet.com\"], totalExecutionTime: 54608, totalOccurrences: 36 }, { name: \"atlasRTX\", homepage: \"https://www.atlasrtx.com/\", category: \"customer-success\", domains: [\"*.atlasrtx.com\"], examples: [\"app.atlasrtx.com\", \"cdn.atlasrtx.com\", \"dev.atlasrtx.com\"], totalExecutionTime: 52386, totalOccurrences: 46 }, { name: \"ContactAtOnce\", homepage: \"https://www.contactatonce.com/\", category: \"customer-success\", domains: [\"*.contactatonce.com\"], examples: [\"tag.contactatonce.com\", \"agentpresence.contactatonce.com\"] }, { name: \"Algolia\", homepage: \"https://www.algolia.com/\", category: \"utility\", domains: [\"*.algolianet.com\", \"*.algolia.net\", \"*.algolia.io\"], totalExecutionTime: 5603, totalOccurrences: 20 }, { name: \"EMX Digital\", homepage: \"htt\\\nps://emxdigital.com\", category: \"ad\", domains: [\"*.emxdgt.com\"], totalExecutionTime: 9160, totalOccurrences: 166 }, { name: \"Moxie\", homepage: \"https://www.gomoxie.com/\", category: \"utility\", domains: [\"*.gomoxie.solutions\"], totalExecutionTime: 24183, totalOccurrences: 28 }, { name: \"Scripps Network Digital\", homepage: \"https://www.scrippsnetworksdigital.com/\", category: \"ad\", domains: [\"*.snidigital.com\"] }, { name: \"TurnTo\", homepage: \"https://www.turntonetworks.com/\", category: \"utility\", domains: [\"*.turnto.com\"], totalExecutionTime: 4666, totalOccurrences: 32 }, { name: \"Quantum Metric\", homepage: \"https://www.quantummetric.com/\", category: \"analytics\", domains: [\"*.quantummetric.com\"], totalExecutionTime: 1699724, totalOccurrences: 1140 }, { name: \"Carbon Ads\", homepage: \"https://www.carbonads.net/\", category: \"ad\", domains: [\"*.carbonads.net\", \"*.carbonads.com\"], totalExecutionTime: 12059, totalOccurrences: 224 }, { name: \"Ably\", homepage: \"https://www.ably.io/\", category: \"uti\\\nlity\", domains: [\"*.ably.io\"], totalExecutionTime: 17031, totalOccurrences: 125 }, { name: \"Sectigo\", homepage: \"https://sectigo.com/\", category: \"utility\", domains: [\"*.sectigo.com\"], totalExecutionTime: 4576, totalOccurrences: 3 }, { name: \"Specless\", homepage: \"https://gospecless.com/\", category: \"ad\", domains: [\"*.specless.tech\"] }, { name: \"Loggly\", homepage: \"https://www.loggly.com/\", category: \"analytics\", domains: [\"*.loggly.com\", \"d9jmv9u00p0mv.cloudfront.net\"], examples: [\"logs-01.loggly.com\"], totalExecutionTime: 943, totalOccurrences: 5 }, { name: \"Intent Media\", homepage: \"https://intent.com/\", category: \"ad\", domains: [\"*.intentmedia.net\"] }, { name: \"Supership\", homepage: \"https://supership.jp/\", category: \"ad\", domains: [\"*.socdm.com\"], totalExecutionTime: 10809246, totalOccurrences: 17934 }, { name: \"F@N Communications\", homepage: \"https://www.fancs.com/\", category: \"ad\", domains: [\"*.ladsp.com\"], examples: [\"px.ladsp.com\"], totalExecutionTime: 258835, totalOccurrences: 1768 },\n    { name: \"Vidyard\", homepage: \"https://www.vidyard.com/\", category: \"utility\", domains: [\"*.vidyard.com\"], totalExecutionTime: 1165600, totalOccurrences: 1097 }, { name: \"RapidSSL\", homepage: \"https://www.rapidssl.com/\", category: \"utility\", domains: [\"*.rapidssl.com\"], totalExecutionTime: 845, totalOccurrences: 2 }, { name: \"Coherent Path\", homepage: \"https://coherentpath.com/\", category: \"utility\", domains: [\"*.coherentpath.com\"] }, { name: \"Attentive\", homepage: \"https://attentivemobile.com/\", category: \"ad\", domains: [\"*.attn.tv\", \"*.attentivemobile.com\"], totalExecutionTime: 5554871, totalOccurrences: 9099 }, { name: \"emetriq\", homepage: \"https://www.emetriq.com/\", category: \"ad\", domains: [\"*.emetriq.de\", \"*.xplosion.de\"], totalExecutionTime: 1917, totalOccurrences: 24 }, { name: \"Bonzai\", homepage: \"https://www.bonzai.co/\", category: \"ad\", domains: [\"*.bonzai.co\"] }, { name: \"Freshchat\", homepage: \"https://www.freshworks.com/live-chat-software/\", category: \"customer-success\",\n    domains: [\"*.freshchat.com\", \"*.freshworksapi.com\"], products: [{ name: \"Freshdesk Messaging\", urlPatterns: [\"wchat.freshchat.com\"], facades: [{ name: \"Freshdesk Messaging (formerly Freshchat) Facade\", repo: \"https://github.com/coliff/freshdesk-messaging-facade/\" }] }], totalExecutionTime: 23350324, totalOccurrences: 7081 }, { name: \"Contentful\", homepage: \"https://www.contentful.com/\", category: \"utility\", domains: [\"*.contentful.com\"], examples: [\"cdn.contentful.com\"], totalExecutionTime: 4826, totalOccurrences: 2 }, { name: \"PureCars\", homepage: \"https://www.purecars.com/\", category: \"marketing\", domains: [\"*.purecars.com\"], examples: [\"cdn.purecars.com\"], totalExecutionTime: 969442, totalOccurrences: 1292 }, { name: \"Tray Commerce\", homepage: \"https://www.tray.com.br/\", category: \"marketing\", domains: [\"*.tcdn.com.br\"], examples: [\"images.tcdn.com.br\"], totalExecutionTime: 68362173, totalOccurrences: 14071 }, { name: \"AdScore\", homepage: \"https://www.adscore.com/\", category: \"a\\\nd\", domains: [\"*.adsco.re\"], examples: [\"c.adsco.re\"], totalExecutionTime: 2812771, totalOccurrences: 4394 }, { name: \"WebsiteBuilder.com\", homepage: \"https://www.websitebuilder.com\", category: \"hosting\", domains: [\"*.mywebsitebuilder.com\"], totalExecutionTime: 19568135, totalOccurrences: 4688 }, { name: \"mParticle\", homepage: \"https://www.mparticle.com/\", category: \"utility\", domains: [\"*.mparticle.com\"], examples: [\"jssdks.mparticle.com\", \"identity.mparticle.com\"], totalExecutionTime: 403503, totalOccurrences: 1029 }, { name: \"Ada\", homepage: \"https://www.ada.support/\", category: \"customer-success\", domains: [\"*.ada.support\"], examples: [\"static.ada.support\"], totalExecutionTime: 695777, totalOccurrences: 985 }, { name: \"Quora Ads\", homepage: \"https://www.quora.com/business/\", category: \"ad\", domains: [\"*.quora.com\"], examples: [\"q.quora.com\"], totalExecutionTime: 1338719, totalOccurrences: 10614 }, { name: \"Auth0\", homepage: \"https://auth0.com/\", category: \"utility\", domains: [\"*.au\\\nth0.com\"], examples: [\"cdn.auth0.com\"], totalExecutionTime: 245638, totalOccurrences: 816 }, { name: \"Bridgewell DSP\", homepage: \"https://www.bridgewell.com/\", category: \"ad\", domains: [\"*.scupio.com\"], examples: [\"img.scupio.com\"], totalExecutionTime: 63728, totalOccurrences: 354 }, { name: \"Wicked Reports\", homepage: \"https://www.wickedreports.com/\", category: \"marketing\", domains: [\"*.wickedreports.com\"], examples: [\"widget.wickedreports.com\"], totalExecutionTime: 148754, totalOccurrences: 483 }, { name: \"Jaywing\", homepage: \"https://jaywing.com/\", category: \"marketing\", domains: [\"*.jaywing.com\"], examples: [\"amazon.almanac.jaywing.com\"] }, { name: \"Holimetrix\", homepage: \"https://u360.d-bi.fr/\", category: \"marketing\", domains: [\"*.d-bi.fr\"], examples: [\"u360.d-bi.fr\"] }, { name: \"iZooto\", homepage: \"https://www.izooto.com\", category: \"marketing\", domains: [\"*.izooto.com\"], examples: [\"cdn.izooto.com\"], totalExecutionTime: 1111125, totalOccurrences: 2022 }, { name: \"Ordergroove\", homepage: \"\\\nhttps://www.ordergroove.com/\", category: \"marketing\", domains: [\"*.ordergroove.com\"], examples: [\"static.ordergroove.com\"], totalExecutionTime: 99990, totalOccurrences: 274 }, { name: \"PageSense\", homepage: \"https://www.zoho.com/pagesense/\", category: \"analytics\", domains: [\"*.pagesense.io\"], examples: [\"cdn.pagesense.io\"], totalExecutionTime: 1996537, totalOccurrences: 6219 }, { name: \"Vizzit\", homepage: \"https://www.vizzit.se\", category: \"analytics\", domains: [\"*.vizzit.se\"], examples: [\"www.vizzit.se\", \"tag.vizzit.se\"], totalExecutionTime: 739, totalOccurrences: 7 }, { name: \"Click Guardian\", homepage: \"https://www.clickguardian.co.uk/\", category: \"ad\", domains: [\"*.clickguardian.app\", \"*.clickguardian.co.uk\"], examples: [\"v2.clickguardian.app\", \"protection.clickguardian.co.uk\"], totalExecutionTime: 202620, totalOccurrences: 1101 }, { name: \"Smartsupp\", company: \"Smartsupp.com\", homepage: \"https://www.smartsupp.com\", category: \"customer-success\", domains: [\"*.smartsuppchat.com\", \"*.\\\nsmartsupp.com\", \"smartsupp-widget-161959.c.cdn77.org\", \"*.smartsuppcdn.com\"], examples: [\"widget-v1.smartsuppcdn.com\"], totalExecutionTime: 9998165, totalOccurrences: 21505 }, { name: \"Smartlook\", company: \"Smartsupp.com\", homepage: \"https://www.smartlook.com/\", category: \"analytics\", domains: [\"*.smartlook.com\"], totalExecutionTime: 1386251, totalOccurrences: 16221 }, { name: \"Luigis Box\", company: \"Luigis Box\", homepage: \"https://www.luigisbox.com/\", category: \"utility\", domains: [\"*.luigisbox.com\"], totalExecutionTime: 2975273, totalOccurrences: 2356 }, { name: \"Targito\", company: \"VIVmail.cz\", homepage: \"https://www.targito.com\", category: \"marketing\", domains: [\"*.targito.com\"], totalExecutionTime: 3145, totalOccurrences: 29 }, { name: \"Foxentry\", company: \"AVANTRO\", homepage: \"https://foxentry.cz/\", category: \"utility\", domains: [\"*.foxentry.cz\"], totalExecutionTime: 758854, totalOccurrences: 2313 }, { name: \"Pendo\", homepage: \"https://www.pendo.io\", category: \"analytics\", domains: [\n    \"*.pendo.io\"], examples: [\"app.pendo.io\"], totalExecutionTime: 4935190, totalOccurrences: 12203 }, { name: \"Braze\", homepage: \"https://www.braze.com\", category: \"analytics\", domains: [\"*.appboycdn.com\"], examples: [\"js.appboycdn.com\"], totalExecutionTime: 399216, totalOccurrences: 2014 }, { name: \"Usersnap\", homepage: \"https://usersnap.com\", category: \"customer-success\", domains: [\"*.usersnap.com\"], examples: [\"api.usersnap.com\", \"cdn.usersnap.com\"], totalExecutionTime: 334324, totalOccurrences: 437 }, { name: \"Rewardful\", homepage: \"https://www.getrewardful.com\", category: \"analytics\", domains: [\"*.wdfl.co\"], examples: [\"r.wdfl.co\"], totalExecutionTime: 9094, totalOccurrences: 161 }, { name: \"Launch Darkly\", homepage: \"https://launchdarkly.com\", category: \"utility\", domains: [\"*.launchdarkly.com\"], examples: [\"app.launchdarkly.com\", \"events.launchdarkly.com\"], totalExecutionTime: 10547, totalOccurrences: 6 }, { name: \"Statuspage\", company: \"Atlassian\", homepage: \"https://www.statu\\\nspage.io\", category: \"utility\", domains: [\"*.statuspage.io\"], examples: [\"1k6wzpspjf99.statuspage.io\"], totalExecutionTime: 43124, totalOccurrences: 1212 }, { name: \"HyperInzerce\", homepage: \"https://hyperinzerce.cz\", category: \"ad\", domains: [\"*.hyperinzerce.cz\"], examples: [\"motorky.hyperinzerce.cz\"], totalExecutionTime: 1035, totalOccurrences: 39 }, { name: \"POWr\", homepage: \"https://www.powr.io\", category: \"utility\", domains: [\"*.powr.io\"], examples: [\"www.powr.io\"], totalExecutionTime: 191534674, totalOccurrences: 39716 }, { name: \"Coral\", company: \"Coral\", homepage: \"https://coralproject.net\", category: \"content\", domains: [\"*.coral.coralproject.net\"], examples: [\"company.coral.coralproject.net\"], totalExecutionTime: 61135, totalOccurrences: 250 }, { name: \"Bolt\", homepage: \"https://www.bolt.com/\", category: \"utility\", domains: [\"*.bolt.com\"], examples: [\"connect.bolt.com\"], totalExecutionTime: 513689, totalOccurrences: 217 }, { name: \"Judge.me\", homepage: \"https://judge.me/\", category: \"\\\nmarketing\", domains: [\"*.judge.me\"], examples: [\"cdn.judge.me\"], totalExecutionTime: 31886982, totalOccurrences: 27483 }, { name: \"Tilda\", homepage: \"https://tilda.cc/\", category: \"hosting\", domains: [\"*.tildacdn.com\"], examples: [\"stat.tildacdn.com\", \"static.tildacdn.com\", \"upwidget.tildacdn.com\"], totalExecutionTime: 94734169, totalOccurrences: 70321 }, { name: \"SalesLoft\", homepage: \"https://salesloft.com/\", category: \"marketing\", domains: [\"*.salesloft.com\"], examples: [\"scout-cdn.salesloft.com\"], totalExecutionTime: 42987, totalOccurrences: 705 }, { name: \"Accessibe Accessibility Overlay\", company: \"Accessibe\", homepage: \"https://accessibe.com/\", category: \"utility\", domains: [\"*.accessibe.com\", \"*.acsbapp.com\", \"*.acsbap.com\"], examples: [\"accessibe.com\", \"acsbapp.com\"], totalExecutionTime: 285765, totalOccurrences: 808 }, { name: \"Builder\", homepage: \"https://www.builder.io/\", category: \"hosting\", domains: [\"*.builder.io\"], examples: [\"cdn.builder.io\"], totalExecutionTime: 412358,\n    totalOccurrences: 261 }, { name: \"Pepperjam\", homepage: \"https://www.pepperjam.com/\", category: \"marketing\", domains: [\"*.pepperjam.com\", \"*.affiliatetechnology.com\"], examples: [\"container.pepperjam.com\"], totalExecutionTime: 2308, totalOccurrences: 35 }, { name: \"Reach\", homepage: \"https://withreach.com/\", category: \"utility\", domains: [\"*.gointerpay.net\"], examples: [\"checkout.gointerpay.net\"] }, { name: \"Chameleon\", homepage: \"https://www.trychameleon.com/\", category: \"marketing\", domains: [\"*.trychameleon.com\"], examples: [\"fast.trychameleon.com\"], totalExecutionTime: 24218, totalOccurrences: 8 }, { name: \"Matomo\", company: \"InnoCraft\", homepage: \"https://matomo.org/\", category: \"analytics\", domains: [\"*.matomo.cloud\"], totalExecutionTime: 3115176, totalOccurrences: 14345 }, { name: \"Segmanta\", homepage: \"https://segmanta.com/\", category: \"marketing\", domains: [\"*.segmanta.com\"], examples: [\"clientName.segmanta.com\"] }, { name: \"Podsights\", homepage: \"https://podsights.com/\", category: \"\\\nmarketing\", domains: [\"*.pdst.fm\", \"us-central1-adaptive-growth.cloudfunctions.net\"], examples: [\"cdn.pdst.fm\", \"sink.pdst.fm\"], totalExecutionTime: 71990, totalOccurrences: 1140 }, { name: \"Chatwoot\", homepage: \"https://www.chatwoot.com/\", category: \"customer-success\", domains: [\"*.chatwoot.com\"], examples: [\"cdn.chatwoot.com\", \"app.chatwoot.com\"], totalExecutionTime: 31973, totalOccurrences: 444 }, { name: \"Crisp\", homepage: \"https://crisp.chat/\", category: \"customer-success\", domains: [\"*.crisp.chat\"], examples: [\"client.crisp.chat\", \"client.relay.crisp.chat\"], totalExecutionTime: 33757, totalOccurrences: 1052 }, { name: \"Admiral CMP\", homepage: \"https://www.getadmiral.com\", category: \"consent-provider\", domains: [\"admiral.mgr.consensu.org\", \"*.admiral.mgr.consensu.org\"] }, { name: \"Adnuntius CMP\", homepage: \"https://adnuntius.com\", category: \"consent-provider\", domains: [\"adnuntiusconsent.mgr.consensu.org\", \"*.adnuntiusconsent.mgr.consensu.org\"] }, { name: \"Clickio CMP\", homepage: \"\\\nhttps://clickio.com\", category: \"consent-provider\", domains: [\"clickio.mgr.consensu.org\", \"*.clickio.mgr.consensu.org\"] }, { name: \"AppConsent CMP\", homepage: \"https://appconsent.io/en\", category: \"consent-provider\", domains: [\"appconsent.mgr.consensu.org\", \"*.appconsent.mgr.consensu.org\"] }, { name: \"DMG Media CMP\", homepage: \"https://www.dmgmedia.co.uk\", category: \"consent-provider\", domains: [\"dmgmedia.mgr.consensu.org\", \"*.dmgmedia.mgr.consensu.org\"] }, { name: \"Axel Springer CMP\", homepage: \"https://www.axelspringer.com\", category: \"consent-provider\", domains: [\"axelspringer.mgr.consensu.org\", \"*.axelspringer.mgr.consensu.org\"] }, { name: \"Bedrock CMP\", homepage: \"https://www.bedrockstreaming.com\", category: \"consent-provider\", domains: [\"bedrock.mgr.consensu.org\", \"*.bedrock.mgr.consensu.org\"] }, { name: \"BMIND CMP\", homepage: \"https://www.bmind.es\", category: \"consent-provider\", domains: [\"bmind.mgr.consensu.org\", \"*.bmind.mgr.consensu.org\"] }, { name: \"Borlabs CMP\", homepage: \"\\\nhttps://borlabs.io\", category: \"consent-provider\", domains: [\"borlabs.mgr.consensu.org\", \"*.borlabs.mgr.consensu.org\"] }, { name: \"Civic CMP\", homepage: \"https://www.civicuk.com\", category: \"consent-provider\", domains: [\"cookiecontrol.mgr.consensu.org\", \"*.cookiecontrol.mgr.consensu.org\"] }, { name: \"Commanders Act CMP\", homepage: \"https://www.commandersact.com\", category: \"consent-provider\", domains: [\"commandersact.mgr.consensu.org\", \"*.commandersact.mgr.consensu.org\"] }, { name: \"Complianz CMP\", homepage: \"https://complianz.io/\", category: \"consent-provider\", domains: [\"complianz.mgr.consensu.org\", \"*.complianz.mgr.consensu.org\"] }, { name: \"Consent Desk CMP\", homepage: \"https://www.consentdesk.com/\", category: \"consent-provider\", domains: [\"consentdesk.mgr.consensu.org\", \"*.consentdesk.mgr.consensu.org\"] }, { name: \"Consent Manager CMP\", homepage: \"https://consentmanager.net\", category: \"consent-provider\", domains: [\"consentmanager.mgr.consensu.org\", \"*.consentmanager.mgr.consensu.\\\norg\"] }, { name: \"Conversant CMP\", homepage: \"https://www.conversantmedia.eu/\", category: \"consent-provider\", domains: [\"conversant.mgr.consensu.org\", \"*.conversant.mgr.consensu.org\"] }, { name: \"Cookie Information CMP\", homepage: \"https://www.cookieinformation.com/\", category: \"consent-provider\", domains: [\"cookieinformation.mgr.consensu.org\", \"*.cookieinformation.mgr.consensu.org\"] }, { name: \"Cookiebot CMP\", homepage: \"https://www.cookiebot.com\", category: \"consent-provider\", domains: [\"cookiebot.mgr.consensu.org\", \"*.cookiebot.mgr.consensu.org\"] }, { name: \"Truendo CMP\", homepage: \"https://truendo.com/\", category: \"consent-provider\", domains: [\"truendo.mgr.consensu.org\", \"*.truendo.mgr.consensu.org\"] }, { name: \"Dentsu CMP\", homepage: \"https://www.dentsuaegisnetwork.de/\", category: \"consent-provider\", domains: [\"dan.mgr.consensu.org\", \"*.dan.mgr.consensu.org\"] }, { name: \"Didomi CMP\", homepage: \"https://www.didomi.io/en/\", category: \"consent-provider\", domains: [\"didomi.mgr.consens\\\nu.org\", \"*.didomi.mgr.consensu.org\"] }, { name: \"Ensighten CMP\", homepage: \"https://www.ensighten.com/\", category: \"consent-provider\", domains: [\"ensighten.mgr.consensu.org\", \"*.ensighten.mgr.consensu.org\"] }, { name: \"Evidon CMP\", homepage: \"https://evidon.com\", category: \"consent-provider\", domains: [\"evidon.mgr.consensu.org\", \"*.evidon.mgr.consensu.org\"] }, { name: \"Ezoic CMP\", homepage: \"https://www.ezoic.com/\", category: \"consent-provider\", domains: [\"ezoic.mgr.consensu.org\", \"*.ezoic.mgr.consensu.org\"] }, { name: \"Gemius CMP\", homepage: \"https://www.gemius.com\", category: \"consent-provider\", domains: [\"gemius.mgr.consensu.org\", \"*.gemius.mgr.consensu.org\"] }, { name: \"NitroPay CMP\", homepage: \"https://nitropay.com/\", category: \"consent-provider\", domains: [\"nitropay.mgr.consensu.org\", \"*.nitropay.mgr.consensu.org\"] }, { name: \"Google FundingChoices\", homepage: \"https://fundingchoices.google.com/start/\", category: \"consent-provider\", domains: [\"fundingchoices.mgr.consensu.org\", \"*\\\n.fundingchoices.mgr.consensu.org\", \"fundingchoicesmessages.google.com\", \"*.fundingchoicesmessages.google.com\"], totalExecutionTime: 257806056, totalOccurrences: 400016 }, { name: \"Gravito CMP\", homepage: \"https://www.gravito.net/\", category: \"consent-provider\", domains: [\"gravito.mgr.consensu.org\", \"*.gravito.mgr.consensu.org\"] }, { name: \"ID Ward CMP\", homepage: \"https://id-ward.com/enterprise\", category: \"consent-provider\", domains: [\"idward.mgr.consensu.org\", \"*.idward.mgr.consensu.org\"] }, { name: \"iubenda CMP\", homepage: \"https://www.iubenda.com\", category: \"consent-provider\", domains: [\"iubenda.mgr.consensu.org\", \"*.iubenda.mgr.consensu.org\"] }, { name: \"Jump CMP\", homepage: \"https://jumpgroup.it/\", category: \"consent-provider\", domains: [\"avacy.mgr.consensu.org\", \"*.avacy.mgr.consensu.org\"] }, { name: \"LiveRamp CMP\", homepage: \"https://liveramp.com/\", category: \"consent-provider\", domains: [\"faktor.mgr.consensu.org\", \"*.faktor.mgr.consensu.org\"] }, { name: \"Madvertise CMP\", homepage: \"\\\nhttps://madvertise.com/en/\", category: \"consent-provider\", domains: [\"madvertise.mgr.consensu.org\", \"*.madvertise.mgr.consensu.org\"] }, { name: \"Mairdumont Netletic CMP\", homepage: \"https://www.mairdumont-netletix.com/\", category: \"consent-provider\", domains: [\"mdnxmp.mgr.consensu.org\", \"*.mdnxmp.mgr.consensu.org\"] }, { name: \"Marfeel CMP\", homepage: \"https://www.marfeel.com/\", category: \"consent-provider\", domains: [\"marfeel.mgr.consensu.org\", \"*.marfeel.mgr.consensu.org\"] }, { name: \"Mediavine CMP\", homepage: \"https://www.mediavine.com/\", category: \"consent-provider\", domains: [\"mediavine.mgr.consensu.org\", \"*.mediavine.mgr.consensu.org\"] }, { name: \"ConsentServe CMP\", homepage: \"https://www.consentserve.com/\", category: \"consent-provider\", domains: [\"consentserve.mgr.consensu.org\", \"*.consentserve.mgr.consensu.org\"] }, { name: \"Next14 CMP\", homepage: \"https://www.next14.com/\", category: \"consent-provider\", domains: [\"next14.mgr.consensu.org\", \"*.next14.mgr.consensu.org\"] }, { name: \"\\\nAdRoll CMP\", homepage: \"https://www.adroll.com/\", category: \"consent-provider\", domains: [\"adroll.mgr.consensu.org\", \"*.adroll.mgr.consensu.org\"] }, { name: \"Ogury CMP\", homepage: \"https://www.ogury.com/\", category: \"consent-provider\", domains: [\"ogury.mgr.consensu.org\", \"*.ogury.mgr.consensu.org\"] }, { name: \"OneTag CMP\", homepage: \"https://onetag.net\", category: \"consent-provider\", domains: [\"onetag.mgr.consensu.org\", \"*.onetag.mgr.consensu.org\"] }, { name: \"OneTrust CMP\", homepage: \"https://onetrust.com\", category: \"consent-provider\", domains: [\"onetrust.mgr.consensu.org\", \"*.onetrust.mgr.consensu.org\"] }, { name: \"optAd360 CMP\", homepage: \"https://www.optad360.com/\", category: \"consent-provider\", domains: [\"optad360.mgr.consensu.org\", \"*.optad360.mgr.consensu.org\"] }, { name: \"Osano CMP\", homepage: \"https://www.osano.com\", category: \"consent-provider\", domains: [\"osano.mgr.consensu.org\", \"*.osano.mgr.consensu.org\"] }, { name: \"Playwire CMP\", homepage: \"https://www.playwire.com\", category: \"\\\nconsent-provider\", domains: [\"playwire.mgr.consensu.org\", \"*.playwire.mgr.consensu.org\"] }, { name: \"Pulselive CMP\", homepage: \"https://www.pulselive.com\", category: \"consent-provider\", domains: [\"pulselive.mgr.consensu.org\", \"*.pulselive.mgr.consensu.org\"] }, { name: \"Quantcast Choice\", homepage: \"https://quantcast.com\", category: \"consent-provider\", domains: [\"quantcast.mgr.consensu.org\", \"*.quantcast.mgr.consensu.org\"] }, { name: \"RCS Pubblicita CMP\", homepage: \"http://www.rcspubblicita.it/site/home.html\", category: \"consent-provider\", domains: [\"rcsmediagroup.mgr.consensu.org\", \"*.rcsmediagroup.mgr.consensu.org\"] }, { name: \"Rich Audience CMP\", homepage: \"https://richaudience.com\", category: \"consent-provider\", domains: [\"richaudience.mgr.consensu.org\", \"*.richaudience.mgr.consensu.org\"] }, { name: \"Ringier Axel Springer CMP\", homepage: \"https://www.ringieraxelspringer.pl/en/home/\", category: \"consent-provider\", domains: [\"rasp.mgr.consensu.org\", \"*.rasp.mgr.consensu.org\"] }, { name: \"\\\nSecure Privacy CMP\", homepage: \"https://secureprivacy.ai/\", category: \"consent-provider\", domains: [\"secureprivacy.mgr.consensu.org\", \"*.secureprivacy.mgr.consensu.org\"] }, { name: \"Securiti CMP\", homepage: \"https://securiti.ai/\", category: \"consent-provider\", domains: [\"securiti.mgr.consensu.org\", \"*.securiti.mgr.consensu.org\"] }, { name: \"Seznam.cz CMP\", homepage: \"https://www.seznam.cz/\", category: \"consent-provider\", domains: [\"seznam.mgr.consensu.org\", \"*.seznam.mgr.consensu.org\"] }, { name: \"ShareThis CMP\", homepage: \"https://sharethis.com\", category: \"consent-provider\", domains: [\"sharethis.mgr.consensu.org\", \"*.sharethis.mgr.consensu.org\"] }, { name: \"ShinyStat CMP\", homepage: \"https://www.shinystat.com\", category: \"consent-provider\", domains: [\"shinystat.mgr.consensu.org\", \"*.shinystat.mgr.consensu.org\"] }, { name: \"Sibbo CMP\", homepage: \"https://sibboventures.com/en/\", category: \"consent-provider\", domains: [\"sibboventures.mgr.consensu.org\", \"*.sibboventures.mgr.consensu.org\"] },\n    { name: \"Singlespot CMP\", homepage: \"https://www.singlespot.com/en\", category: \"consent-provider\", domains: [\"singlespot.mgr.consensu.org\", \"*.singlespot.mgr.consensu.org\"] }, { name: \"Sirdata CMP\", homepage: \"https://www.sirdata.com\", category: \"consent-provider\", domains: [\"sddan.mgr.consensu.org\", \"*.sddan.mgr.consensu.org\"] }, { name: \"Snigel CMP\", homepage: \"https://snigel.com\", category: \"consent-provider\", domains: [\"snigelweb.mgr.consensu.org\", \"*.snigelweb.mgr.consensu.org\"] }, { name: \"Sourcepoint CMP\", homepage: \"https://sourcepoint.com\", category: \"consent-provider\", domains: [\"sourcepoint.mgr.consensu.org\", \"*.sourcepoint.mgr.consensu.org\"] }, { name: \"Pubtech CMP\", homepage: \"https://www.pubtech.ai/\", category: \"consent-provider\", domains: [\"pubtech.mgr.consensu.org\", \"*.pubtech.mgr.consensu.org\"] }, { name: \"AdMetrics Pro CMP\", homepage: \"https://admetricspro.com\", category: \"consent-provider\", domains: [\"cmp.mgr.consensu.org\", \"*.cmp.mgr.consensu.org\"] }, { name: \"T\\\nraffective CMP\", homepage: \"https://traffective.com\", category: \"consent-provider\", domains: [\"traffective.mgr.consensu.org\", \"*.traffective.mgr.consensu.org\"] }, { name: \"UniConsent CMP\", homepage: \"https://www.uniconsent.com\", category: \"consent-provider\", domains: [\"uniconsent.mgr.consensu.org\", \"*.uniconsent.mgr.consensu.org\", \"cmp.uniconsent.com\", \"*.uniconsent.com\"], totalExecutionTime: 829870, totalOccurrences: 1336 }, { name: \"TrustArc CMP\", homepage: \"https://trustarc.com/\", category: \"consent-provider\", domains: [\"trustarc.mgr.consensu.org\", \"*.trustarc.mgr.consensu.org\"] }, { name: \"Usercentrics CMP\", homepage: \"https://usercentrics.com\", category: \"consent-provider\", domains: [\"usercentrics.mgr.consensu.org\", \"*.usercentrics.mgr.consensu.org\", \"*.usercentrics.eu\", \"*.services.usercentrics.eu\"], totalExecutionTime: 53008518, totalOccurrences: 49602 }, { name: \"WebAds CMP\", homepage: \"https://www.webads.nl/\", category: \"consent-provider\", domains: [\"webads.mgr.consensu.org\", \"\\\n*.webads.mgr.consensu.org\"] }, { name: \"Trustcommander\", company: \"Commandersact\", homepage: \"https://www.commandersact.com\", category: \"consent-provider\", domains: [\"*.trustcommander.net\"], examples: [\"cdn.trustcommander.net\", \"privacy.trustcommander.net\"], totalExecutionTime: 324770, totalOccurrences: 1713 }, { name: \"Hubvisor\", homepage: \"https://www.hubvisor.io\", category: \"ad\", domains: [\"*.hubvisor.io\"], examples: [\"cdn.hubvisor.io\", \"stream.hubvisor.io\"], totalExecutionTime: 404737, totalOccurrences: 492 }, { name: \"Castle\", homepage: \"https://castle.io\", category: \"utility\", domains: [\"*.castle.io\", \"d2t77mnxyo7adj.cloudfront.net\"], examples: [\"t.castle.io\"] }, { name: \"Wigzo\", homepage: \"https://www.wigzo.com/\", category: \"marketing\", domains: [\"*.wigzo.com\", \"*.wigzopush.com\"], examples: [\"app.wigzo.com\", \"tracker.wigzopush.com\"], totalExecutionTime: 215280, totalOccurrences: 762 }, { name: \"Convertful\", homepage: \"https://convertful.com/\", category: \"marketing\", domains: [\"*\\\n.convertful.com\"], examples: [\"app.convertful.com\"], totalExecutionTime: 215317, totalOccurrences: 1534 }, { name: \"OpenLink\", company: \"MediaWallah\", homepage: \"https://www.mediawallah.com/\", category: \"ad\", domains: [\"*.mediawallahscript.com\"], examples: [\"partner.mediawallahscript.com\"] }, { name: \"TPMN\", company: \"TPMN\", homepage: \"http://tpmn.io/\", category: \"ad\", domains: [\"*.tpmn.co.kr\"], examples: [\"ad.tpmn.co.kr\"], totalExecutionTime: 354, totalOccurrences: 10 }, { name: \"HERO\", company: \"Klarna\", homepage: \"https://www.usehero.com/\", category: \"customer-success\", domains: [\"*.usehero.com\"], examples: [\"api.usehero.com\", \"cdn.usehero.com\"], totalExecutionTime: 32092, totalOccurrences: 42 }, { name: \"Zync\", company: \"Zeta Global\", homepage: \"https://zetaglobal.com/\", category: \"marketing\", domains: [\"*.rezync.com\"], examples: [\"live.rezync.com\"], totalExecutionTime: 25978, totalOccurrences: 246 }, { name: \"AdFuel Video\", company: \"AdFuel\", homepage: \"https://goadfuel.com/\", category: \"\\\nad\", domains: [\"*.videoplayerhub.com\"], examples: [\"customer.videoplayerhub.com\"], totalExecutionTime: 82951, totalOccurrences: 1407 }, { name: \"Prefix Box AI Search\", company: \"Prefix Box\", homepage: \"https://www.prefixbox.com/\", category: \"utility\", domains: [\"*.prefixbox.com\"], examples: [\"cdn.prefixbox.com\"], totalExecutionTime: 51608, totalOccurrences: 58 }, { name: \"SpeedSize Service Worker\", company: \"SpeedSize\", homepage: \"https://speedsize.com/\", category: \"utility\", domains: [\"di6367dava8ow.cloudfront.net\", \"d2d22nphq0yz8t.cloudfront.net\"], examples: [\"di6367dava8ow.cloudfront.net\"] }, { name: \"Vonage Video API\", company: \"Vonage\", homepage: \"https://www.vonage.com/communications-apis/video/\", category: \"video\", domains: [\"*.opentok.com\"], examples: [\"static.opentok.com\"], totalExecutionTime: 220760, totalOccurrences: 304 }, { name: \"Checkout.com\", company: \"Checkout.com\", homepage: \"https://www.checkout.com\", category: \"utility\", domains: [\"*.checkout.com\"], examples: [\"cdn.\\\ncheckout.com\"], totalExecutionTime: 184372, totalOccurrences: 1367 }, { name: \"Noibu\", company: \"Noibu\", homepage: \"https://www.noibu.com\", category: \"utility\", domains: [\"*.noibu.com\"], examples: [\"input.noibu.com\"], totalExecutionTime: 1453903, totalOccurrences: 613 }, { name: \"Clarity\", company: \"Microsoft\", homepage: \"https://clarity.microsoft.com/\", category: \"utility\", domains: [\"*.clarity.ms\"], examples: [\"c.clarity.ms\"], totalExecutionTime: 208824616, totalOccurrences: 456309 }, { name: \"goinstore\", company: \"Emplifi\", homepage: \"https://goinstore.com/\", category: \"customer-success\", domains: [\"*.goinstore.com\"], examples: [\"gis.goinstore.com\"] }, { name: \"SegmentStream\", company: \"SegmentStream\", homepage: \"https://segmentstream.com/\", category: \"marketing\", domains: [\"*.segmentstream.com\"], examples: [\"track.segmentstream.com\"], totalExecutionTime: 8628, totalOccurrences: 13 }, { name: \"Amazon Associates\", company: \"Amazon\", homepage: \"https://affiliate-program.amazon.co.uk/\",\n    category: \"marketing\", domains: [\"*.associates-amazon.com\"], examples: [\"assoc-na.associates-amazon.com\"], totalExecutionTime: 50, totalOccurrences: 1 }, { name: \"DotMetrics\", company: \"Ipsos\", homepage: \"https://www.dotmetrics.net/\", category: \"analytics\", domains: [\"*.dotmetrics.net\"], examples: [\"uk-script.dotmetrics.net\"], totalExecutionTime: 159255, totalOccurrences: 817 }, { name: \"Truffle Bid\", company: \"Truffle\", homepage: \"https://truffle.bid/\", category: \"ad\", domains: [\"*.truffle.bid\"], examples: [\"matching.truffle.bid\"], totalExecutionTime: 24026, totalOccurrences: 39 }, { name: \"Hybrid\", company: \"Hybrid\", homepage: \"https://hybrid.ai/\", category: \"ad\", domains: [\"*.hybrid.ai\"], examples: [\"dm-eu.hybrid.ai\"], totalExecutionTime: 219740, totalOccurrences: 2326 }, { name: \"AdMan Media\", company: \"AdMan\", homepage: \"https://admanmedia.com/\", category: \"video\", domains: [\"*.admanmedia.com\"], examples: [\"cs.admanmedia.com\"], totalExecutionTime: 1924, totalOccurrences: 202 },\n    { name: \"ID5 Identity Cloud\", company: \"ID5\", homepage: \"https://id5.io/\", category: \"ad\", domains: [\"id5-sync.com\", \"*.id5-sync.com\"], examples: [\"id5-sync.com\"], totalExecutionTime: 26134069, totalOccurrences: 119336 }, { name: \"Audience Rate\", company: \"Audience Rate Limited\", homepage: \"https://www.audiencerate.com/\", category: \"ad\", domains: [\"*.audrte.com\"], examples: [\"a.audrte.com\"] }, { name: \"Seedtag\", company: \"Seedtag Advertising\", homepage: \"https://www.seedtag.com/\", category: \"ad\", domains: [\"*.seedtag.com\"], examples: [\"s.seedtag.com\"], totalExecutionTime: 3342567, totalOccurrences: 1503 }, { name: \"IVI\", company: \"IVI Technologies\", homepage: \"http://ivitechnologies.com/\", category: \"ad\", domains: [\"*.ivitrack.com\"], examples: [\"matching.ivitrack.com\"], totalExecutionTime: 3746, totalOccurrences: 34 }, { name: \"Sportradar\", company: \"Sportradar\", homepage: \"https://www.sportradar.com/\", category: \"ad\", domains: [\"*.sportradarserving.com\"], examples: [\"a.sportradars\\\nerving.com\"], totalExecutionTime: 520, totalOccurrences: 11 }, { name: \"ZEOTAP\", company: \"ZEOTAP\", homepage: \"https://zeotap.com/\", category: \"ad\", domains: [\"*.zeotap.com\"], examples: [\"spl.zeotap.com\"], totalExecutionTime: 14368, totalOccurrences: 96 }, { name: \"Web Content Assessor\", company: \"TMT Digital\", homepage: \"https://mediatrust.com/\", category: \"ad\", domains: [\"*.webcontentassessor.com\"], examples: [\"scripts.webcontentassessor.com\"], totalExecutionTime: 314249, totalOccurrences: 633 }, { name: \"Genie\", company: \"Media Force\", homepage: \"https://hellogenie.com/\", category: \"ad\", domains: [\"*.mfadsrvr.com\"], examples: [\"rtb.mfadsrvr.com\"], totalExecutionTime: 37, totalOccurrences: 2 }, { name: \"mediarithmics\", company: \"mediarithmics\", homepage: \"https://www.mediarithmics.com/\", category: \"ad\", domains: [\"*.mediarithmics.com\"], examples: [\"cookie-matching.mediarithmics.com\"], totalExecutionTime: 25799, totalOccurrences: 144 }, { name: \"Ozone Project\", company: \"The Ozone Pro\\\nject\", homepage: \"https://www.ozoneproject.com/\", category: \"ad\", domains: [\"*.the-ozone-project.com\"], examples: [\"elb.the-ozone-project.com\"], totalExecutionTime: 152768, totalOccurrences: 910 }, { name: \"FiftyAurora\", company: \"Fifty\", homepage: \"https://fifty.io/\", category: \"ad\", domains: [\"*.fiftyt.com\"], examples: [\"visitor.fiftyt.com\"] }, { name: \"smadex\", company: \"entravision\", homepage: \"https://smadex.com/\", category: \"ad\", domains: [\"*.smadex.com\"], examples: [\"cm.smadex.com\"], totalExecutionTime: 5, totalOccurrences: 1 }, { name: \"AWX\", company: \"Trinity Mirror\", category: \"ad\", domains: [\"*.tm-awx.com\"], examples: [\"felix.data.tm-awx.com\"], totalExecutionTime: 68744, totalOccurrences: 54 }, { name: \"XPO\", company: \"Knorex\", category: \"ad\", homepage: \"https://www.knorex.com/\", domains: [\"*.brand-display.com\"], examples: [\"dmp.brand-display.com\"], totalExecutionTime: 388629, totalOccurrences: 477 }, { name: \"Viafoura\", company: \"Viafoura\", category: \"ad\", homepage: \"https:\\\n//viafoura.com/\", domains: [\"*.viafoura.co\", \"*.viafoura.net\"], examples: [\"api.viafoura.co\", \"cdn.viafoura.net\"], totalExecutionTime: 307404, totalOccurrences: 446 }, { name: \"Adnami\", company: \"Adnami\", category: \"ad\", homepage: \"https://www.adnami.io/\", domains: [\"*.adnami.io\"], examples: [\"macro.adnami.io\"], totalExecutionTime: 272668, totalOccurrences: 1639 }, { name: \"LiveRamp Privacy Manager\", company: \"LiveRamp\", category: \"ad\", homepage: \"https://liveramp.com/privacy-legal-compliance/\", domains: [\"*.privacymanager.io\"], examples: [\"geo.privacymanager.io\"], totalExecutionTime: 6546055, totalOccurrences: 22295 }, { name: \"Onfocus\", company: \"Onfocus SAS\", category: \"ad\", domains: [\"*.4dex.io\"], examples: [\"script.4dex.io\"], totalExecutionTime: 4240761, totalOccurrences: 8836 }, { name: \"viewTag\", company: \"Advanced Store\", category: \"ad\", domains: [\"*.ad4m.at\"], examples: [\"ad4m.at\", \"as.ad4m.at\"], totalExecutionTime: 458, totalOccurrences: 21 }, { name: \"MRP Prelytics\", company: \"\\\nMarket Resource Partners\", category: \"ad\", homepage: \"https://www.mrpfd.com/\", domains: [\"*.mrpdata.net\"], examples: [\"j.mrpdata.net\"] }, { name: \"iPROM\", company: \"iPROM\", category: \"ad\", homepage: \"https://iprom.eu/\", domains: [\"*.iprom.net\"], examples: [\"core.iprom.net\"], totalExecutionTime: 114801, totalOccurrences: 72099 }, { name: \"Plausible\", company: \"Plausible\", homepage: \"https://plausible.io/\", category: \"analytics\", domains: [\"*.plausible.io\"] }, { name: \"Micro Analytics\", company: \"Micro Analytics\", homepage: \"https://microanalytics.io/\", category: \"analytics\", domains: [\"padmin.microanalytics.io\", \"www.microanalytics.io\", \"dev.microanalytics.io\", \"status.microanalytics.io\"] }, { name: \"Scale8\", company: \"Scale8\", homepage: \"https://scale8.com/\", category: \"analytics\", domains: [\"www.scale8.com\", \"api-dev.scale8.com\", \"cdn.scale8.com\", \"ui.scale8.com\"] }, { name: \"Cabin\", company: \"Cabin\", homepage: \"https://withcabin.com/\", category: \"analytics\", domains: [\"*.withcabin.co\\\nm\"], totalExecutionTime: 3843, totalOccurrences: 100 }, { name: \"Appcues\", company: \"Appcues\", homepage: \"https://www.appcues.com/\", category: \"analytics\", domains: [\"*.appcues.com\"], totalExecutionTime: 2154145, totalOccurrences: 2831 }, { name: \"Fathom Analytics\", company: \"Fathom\", homepage: \"https://usefathom.com/\", category: \"analytics\", domains: [\"*.usefathom.com\"], totalExecutionTime: 145389, totalOccurrences: 1141 }, { name: \"Clearbit\", company: \"Clearbit\", homepage: \"https://clearbit.com/\", category: \"analytics\", domains: [\"*.clearbitjs.com\", \"*.clearbitscripts.com\", \"*.clearbit.com\"], totalExecutionTime: 967253, totalOccurrences: 4171 }, { name: \"G2\", company: \"G2\", homepage: \"https://www.g2.com/\", category: \"utility\", domains: [\"*.g2.com\", \"*.g2crowd.com\"], totalExecutionTime: 195752, totalOccurrences: 406 }, { name: \"Navu\", company: \"Navu\", homepage: \"https://navu.co/\", category: \"ad\", domains: [\"*.navu.co\"] }, { name: \"InZynk\", company: \"InZynk\", homepage: \"https://inzynk.\\\ncom/\", category: \"ad\", domains: [\"*.inzynk.com\", \"*.inzynk.io\"], totalExecutionTime: 541, totalOccurrences: 8 }, { name: \"Integrate\", company: \"Integrate\", homepage: \"https://www.integrate.com/\", category: \"ad\", domains: [\"*.integrate.com\", \"*.listenloop.com\"], totalExecutionTime: 14260, totalOccurrences: 39 }, { name: \"Ad Lightning\", company: \"Boltive\", homepage: \"https://www.adlightning.com/\", category: \"ad\", domains: [\"*.adlightning.com\"], totalExecutionTime: 6879067, totalOccurrences: 3795 }, { name: \"GeoEdge\", company: \"GeoEdge\", homepage: \"https://www.geoedge.com/\", category: \"ad\", domains: [\"*.geoedge.com\", \"*.geoedge.be\"], totalExecutionTime: 1039615, totalOccurrences: 1796 }, { name: \"Doofinder\", company: \"Doofinder\", homepage: \"https://www.doofinder.com/\", category: \"utility\", domains: [\"cdn.doofinder.com\"], totalExecutionTime: 1750777, totalOccurrences: 12550 }, { name: \"Revlifter\", company: \"Revlifter\", homepage: \"https://www.revlifter.com/\", category: \"utility\", domains: [\n    \"assets.revlifter.com\"] }, { name: \"Didomi\", company: \"Didomi\", homepage: \"https://www.didomi.io/\", category: \"consent-provider\", domains: [\"sdk.privacy-center.org\", \"api.privacy-center.org\"], totalExecutionTime: 85132161, totalOccurrences: 84206 }, { name: \"Pubperf Analytics\", company: \"Pubperf\", homepage: \"https://www.pubperf.com/\", category: \"analytics\", domains: [\"*.pubperf.com\"], totalExecutionTime: 51392, totalOccurrences: 400 }];\n  }\n});\n\n// node_modules/@paulirish/trace_engine/node_modules/third-party-web/lib/index.js\nvar require_lib = __commonJS({\n  \"node_modules/@paulirish/trace_engine/node_modules/third-party-web/lib/index.js\"(exports2, module2) {\n    init_process_global();\n    var { createAPIFromDataset } = require_create_entity_finder_api();\n    var entities = require_entities();\n    module2.exports = createAPIFromDataset(entities);\n  }\n});\n\n// node_modules/@paulirish/trace_engine/third_party/third-party-web/third-party-web.js\nvar import_third_party_web;\nvar init_third_party_web = __esm({\n  \"node_modules/@paulirish/trace_engine/third_party/third-party-web/third-party-web.js\"() {\n    init_process_global();\n    import_third_party_web = __toESM(require_lib(), 1);\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/types/Configuration.js\nvar Configuration_exports = {};\n__export(Configuration_exports, {\n  configToCacheKey: () => configToCacheKey,\n  defaults: () => defaults\n});\nfunction configToCacheKey(config3) {\n  return JSON.stringify(config3);\n}\nvar defaults;\nvar init_Configuration = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/types/Configuration.js\"() {\n    init_process_global();\n    defaults = /* @__PURE__ */ __name(() => ({\n      includeRuntimeCallStats: false,\n      showAllEvents: false,\n      debugMode: false,\n      maxInvalidationEventsPerEvent: 20,\n      enableAnimationsFrameHandler: false\n    }), \"defaults\");\n    __name(configToCacheKey, \"configToCacheKey\");\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/types/Extensions.js\nvar Extensions_exports = {};\n__export(Extensions_exports, {\n  extensionPalette: () => extensionPalette,\n  isConsoleTimestampPayloadTrackEntry: () => isConsoleTimestampPayloadTrackEntry,\n  isExtensionEntryObj: () => isExtensionEntryObj,\n  isExtensionPayloadMarker: () => isExtensionPayloadMarker,\n  isSyntheticExtensionEntry: () => isSyntheticExtensionEntry,\n  isValidExtensionPayload: () => isValidExtensionPayload\n});\nfunction isExtensionPayloadMarker(payload) {\n  return payload.dataType === \"marker\";\n}\nfunction isExtensionEntryObj(payload) {\n  const hasTrack = \"track\" in payload && Boolean(payload.track);\n  const validEntryType = payload.dataType === \"track-entry\" || payload.dataType === void 0;\n  return validEntryType && hasTrack;\n}\nfunction isConsoleTimestampPayloadTrackEntry(payload) {\n  return payload.url !== void 0 && payload.description !== void 0;\n}\nfunction isValidExtensionPayload(payload) {\n  return isExtensionPayloadMarker(payload) || isExtensionEntryObj(payload) || isConsoleTimestampPayloadTrackEntry(payload);\n}\nfunction isSyntheticExtensionEntry(entry) {\n  return entry.cat === \"devtools.extension\";\n}\nvar extensionPalette;\nvar init_Extensions = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/types/Extensions.js\"() {\n    init_process_global();\n    extensionPalette = [\n      \"primary\",\n      \"primary-light\",\n      \"primary-dark\",\n      \"secondary\",\n      \"secondary-light\",\n      \"secondary-dark\",\n      \"tertiary\",\n      \"tertiary-light\",\n      \"tertiary-dark\",\n      \"error\",\n      \"warning\"\n    ];\n    __name(isExtensionPayloadMarker, \"isExtensionPayloadMarker\");\n    __name(isExtensionEntryObj, \"isExtensionEntryObj\");\n    __name(isConsoleTimestampPayloadTrackEntry, \"isConsoleTimestampPayloadTrackEntry\");\n    __name(isValidExtensionPayload, \"isValidExtensionPayload\");\n    __name(isSyntheticExtensionEntry, \"isSyntheticExtensionEntry\");\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/types/File.js\nvar File_exports = {};\n__export(File_exports, {\n  DataOrigin: () => DataOrigin,\n  EntriesLinkState: () => EntriesLinkState,\n  EventKeyType: () => EventKeyType,\n  isEntriesLinkAnnotation: () => isEntriesLinkAnnotation,\n  isEntryLabelAnnotation: () => isEntryLabelAnnotation,\n  isTimeRangeAnnotation: () => isTimeRangeAnnotation,\n  traceEventKeyToValues: () => traceEventKeyToValues\n});\nfunction isTimeRangeAnnotation(annotation) {\n  return annotation.type === \"TIME_RANGE\";\n}\nfunction isEntryLabelAnnotation(annotation) {\n  return annotation.type === \"ENTRY_LABEL\";\n}\nfunction isEntriesLinkAnnotation(annotation) {\n  return annotation.type === \"ENTRIES_LINK\";\n}\nfunction traceEventKeyToValues(key) {\n  const parts = key.split(\"-\");\n  const type = parts[0];\n  switch (type) {\n    case EventKeyType.PROFILE_CALL:\n      if (parts.length !== 5 || !parts.every((part, i) => i === 0 || typeof part === \"number\" || !isNaN(parseInt(part, 10)))) {\n        throw new Error(`Invalid ProfileCallKey: ${key}`);\n      }\n      return {\n        type: parts[0],\n        processID: parseInt(parts[1], 10),\n        threadID: parseInt(parts[2], 10),\n        sampleIndex: parseInt(parts[3], 10),\n        protocol: parseInt(parts[4], 10)\n      };\n    case EventKeyType.RAW_EVENT:\n      if (parts.length !== 2 || !(typeof parts[1] === \"number\" || !isNaN(parseInt(parts[1], 10)))) {\n        throw new Error(`Invalid RawEvent Key: ${key}`);\n      }\n      return {\n        type: parts[0],\n        rawIndex: parseInt(parts[1], 10)\n      };\n    case EventKeyType.SYNTHETIC_EVENT:\n      if (parts.length !== 2 || !(typeof parts[1] === \"number\" || !isNaN(parseInt(parts[1], 10)))) {\n        throw new Error(`Invalid SyntheticEvent Key: ${key}`);\n      }\n      return {\n        type: parts[0],\n        rawIndex: parseInt(parts[1], 10)\n      };\n    case EventKeyType.LEGACY_TIMELINE_FRAME: {\n      if (parts.length !== 2 || Number.isNaN(parseInt(parts[1], 10))) {\n        throw new Error(`Invalid LegacyTimelineFrame Key: ${key}`);\n      }\n      return {\n        type,\n        rawIndex: parseInt(parts[1], 10)\n      };\n    }\n    default:\n      throw new Error(`Unknown trace event key: ${key}`);\n  }\n}\nvar DataOrigin, EntriesLinkState, EventKeyType;\nvar init_File = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/types/File.js\"() {\n    init_process_global();\n    (function(DataOrigin2) {\n      DataOrigin2[\"CPU_PROFILE\"] = \"CPUProfile\";\n      DataOrigin2[\"TRACE_EVENTS\"] = \"TraceEvents\";\n    })(DataOrigin || (DataOrigin = {}));\n    (function(EntriesLinkState2) {\n      EntriesLinkState2[\"CREATION_NOT_STARTED\"] = \"creation_not_started\";\n      EntriesLinkState2[\"PENDING_TO_EVENT\"] = \"pending_to_event\";\n      EntriesLinkState2[\"CONNECTED\"] = \"connected\";\n    })(EntriesLinkState || (EntriesLinkState = {}));\n    (function(EventKeyType2) {\n      EventKeyType2[\"RAW_EVENT\"] = \"r\";\n      EventKeyType2[\"SYNTHETIC_EVENT\"] = \"s\";\n      EventKeyType2[\"PROFILE_CALL\"] = \"p\";\n      EventKeyType2[\"LEGACY_TIMELINE_FRAME\"] = \"l\";\n    })(EventKeyType || (EventKeyType = {}));\n    __name(isTimeRangeAnnotation, \"isTimeRangeAnnotation\");\n    __name(isEntryLabelAnnotation, \"isEntryLabelAnnotation\");\n    __name(isEntriesLinkAnnotation, \"isEntriesLinkAnnotation\");\n    __name(traceEventKeyToValues, \"traceEventKeyToValues\");\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/types/Overlays.js\nvar init_Overlays = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/types/Overlays.js\"() {\n    init_process_global();\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/types/Timing.js\nvar Timing_exports = {};\n__export(Timing_exports, {\n  Micro: () => Micro,\n  Milli: () => Milli,\n  Seconds: () => Seconds\n});\nfunction Micro(value) {\n  return value;\n}\nfunction Milli(value) {\n  return value;\n}\nfunction Seconds(value) {\n  return value;\n}\nvar init_Timing = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/types/Timing.js\"() {\n    init_process_global();\n    __name(Micro, \"Micro\");\n    __name(Milli, \"Milli\");\n    __name(Seconds, \"Seconds\");\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/types/TraceEvents.js\nvar TraceEvents_exports = {};\n__export(TraceEvents_exports, {\n  AuctionWorkletType: () => AuctionWorkletType,\n  CallFrameID: () => CallFrameID,\n  Categories: () => Categories,\n  InvalidationEventType: () => InvalidationEventType,\n  LayoutInvalidationReason: () => LayoutInvalidationReason,\n  MarkerName: () => MarkerName,\n  NO_NAVIGATION: () => NO_NAVIGATION,\n  Name: () => Name,\n  Phase: () => Phase,\n  ProcessID: () => ProcessID,\n  ProfileID: () => ProfileID,\n  SampleIndex: () => SampleIndex,\n  Scope: () => Scope,\n  SelectorTimingsKey: () => SelectorTimingsKey,\n  StyleRecalcInvalidationReason: () => StyleRecalcInvalidationReason,\n  ThreadID: () => ThreadID,\n  WorkerId: () => WorkerId,\n  eventIsPageLoadEvent: () => eventIsPageLoadEvent,\n  isAbortPostTaskCallback: () => isAbortPostTaskCallback,\n  isActivateLayerTree: () => isActivateLayerTree,\n  isAnimation: () => isAnimation,\n  isAnimationFrameAsyncEnd: () => isAnimationFrameAsyncEnd,\n  isAnimationFrameAsyncStart: () => isAnimationFrameAsyncStart,\n  isAnimationFramePresentation: () => isAnimationFramePresentation,\n  isAnyScriptSourceEvent: () => isAnyScriptSourceEvent,\n  isAuctionWorkletDoneWithProcess: () => isAuctionWorkletDoneWithProcess,\n  isAuctionWorkletRunningInProcess: () => isAuctionWorkletRunningInProcess,\n  isBegin: () => isBegin,\n  isBeginCommitCompositorFrame: () => isBeginCommitCompositorFrame,\n  isBeginFrame: () => isBeginFrame,\n  isBeginMainThreadFrame: () => isBeginMainThreadFrame,\n  isBeginRemoteFontLoad: () => isBeginRemoteFontLoad,\n  isCommit: () => isCommit,\n  isCommitLoad: () => isCommitLoad,\n  isComplete: () => isComplete,\n  isCompositeLayers: () => isCompositeLayers,\n  isConsoleRunTask: () => isConsoleRunTask,\n  isConsoleTime: () => isConsoleTime,\n  isConsoleTimeStamp: () => isConsoleTimeStamp,\n  isDOMStats: () => isDOMStats,\n  isDebuggerAsyncTaskRun: () => isDebuggerAsyncTaskRun,\n  isDebuggerAsyncTaskScheduled: () => isDebuggerAsyncTaskScheduled,\n  isDecodeImage: () => isDecodeImage,\n  isDecodeLazyPixelRef: () => isDecodeLazyPixelRef,\n  isDidCommitSameDocumentNavigation: () => isDidCommitSameDocumentNavigation,\n  isDispatch: () => isDispatch,\n  isDisplayListItemListSnapshot: () => isDisplayListItemListSnapshot,\n  isDomLoading: () => isDomLoading,\n  isDrawFrame: () => isDrawFrame,\n  isDrawLazyPixelRef: () => isDrawLazyPixelRef,\n  isDroppedFrame: () => isDroppedFrame,\n  isEnd: () => isEnd,\n  isEventTiming: () => isEventTiming,\n  isEventTimingEnd: () => isEventTimingEnd,\n  isEventTimingStart: () => isEventTimingStart,\n  isFireAnimationFrame: () => isFireAnimationFrame,\n  isFireIdleCallback: () => isFireIdleCallback,\n  isFirstContentfulPaint: () => isFirstContentfulPaint,\n  isFirstPaint: () => isFirstPaint,\n  isFlowPhase: () => isFlowPhase,\n  isFlowPhaseEvent: () => isFlowPhaseEvent,\n  isFrameCommittedInBrowser: () => isFrameCommittedInBrowser,\n  isFunctionCall: () => isFunctionCall,\n  isGPUTask: () => isGPUTask,\n  isHandlePostMessage: () => isHandlePostMessage,\n  isInstant: () => isInstant,\n  isInteractiveTime: () => isInteractiveTime,\n  isInvalidateLayout: () => isInvalidateLayout,\n  isInvalidationTracking: () => isInvalidationTracking,\n  isJSInvocationEvent: () => isJSInvocationEvent,\n  isLargestContentfulPaintCandidate: () => isLargestContentfulPaintCandidate,\n  isLargestImagePaintCandidate: () => isLargestImagePaintCandidate,\n  isLargestTextPaintCandidate: () => isLargestTextPaintCandidate,\n  isLayerTreeHostImplSnapshot: () => isLayerTreeHostImplSnapshot,\n  isLayout: () => isLayout,\n  isLayoutImageUnsized: () => isLayoutImageUnsized,\n  isLayoutInvalidationTracking: () => isLayoutInvalidationTracking,\n  isLayoutShift: () => isLayoutShift,\n  isLegacyScreenshot: () => isLegacyScreenshot,\n  isLegacySyntheticScreenshot: () => isLegacySyntheticScreenshot,\n  isLegacyTimelineFrame: () => isLegacyTimelineFrame,\n  isLinkPreconnect: () => isLinkPreconnect,\n  isMainFrameViewport: () => isMainFrameViewport,\n  isMarkDOMContent: () => isMarkDOMContent,\n  isMarkLoad: () => isMarkLoad,\n  isMarkerEvent: () => isMarkerEvent,\n  isNavigationStart: () => isNavigationStart,\n  isNeedsBeginFrameChanged: () => isNeedsBeginFrameChanged,\n  isNestableAsyncPhase: () => isNestableAsyncPhase,\n  isNetworkTrackEntry: () => isNetworkTrackEntry,\n  isPaint: () => isPaint,\n  isPaintImage: () => isPaintImage,\n  isPairableAsyncBegin: () => isPairableAsyncBegin,\n  isPairableAsyncEnd: () => isPairableAsyncEnd,\n  isPairableAsyncInstant: () => isPairableAsyncInstant,\n  isParseAuthorStyleSheetEvent: () => isParseAuthorStyleSheetEvent,\n  isParseHTML: () => isParseHTML,\n  isParseMetaViewport: () => isParseMetaViewport,\n  isPerformanceMark: () => isPerformanceMark,\n  isPerformanceMeasure: () => isPerformanceMeasure,\n  isPerformanceMeasureBegin: () => isPerformanceMeasureBegin,\n  isPhaseAsync: () => isPhaseAsync,\n  isPipelineReporter: () => isPipelineReporter,\n  isPrePaint: () => isPrePaint,\n  isProcessName: () => isProcessName,\n  isProfile: () => isProfile,\n  isProfileCall: () => isProfileCall,\n  isProfileChunk: () => isProfileChunk,\n  isRasterTask: () => isRasterTask,\n  isRecalcStyle: () => isRecalcStyle,\n  isReceivedDataEvent: () => isReceivedDataEvent,\n  isRemoteFontLoaded: () => isRemoteFontLoaded,\n  isRenderFrameImplCreateChildFrame: () => isRenderFrameImplCreateChildFrame,\n  isRendererEvent: () => isRendererEvent,\n  isRequestIdleCallback: () => isRequestIdleCallback,\n  isRequestMainThreadFrame: () => isRequestMainThreadFrame,\n  isResourceChangePriority: () => isResourceChangePriority,\n  isResourceFinish: () => isResourceFinish,\n  isResourceMarkAsCached: () => isResourceMarkAsCached,\n  isResourceReceiveResponse: () => isResourceReceiveResponse,\n  isResourceReceivedData: () => isResourceReceivedData,\n  isResourceSendRequest: () => isResourceSendRequest,\n  isResourceWillSendRequest: () => isResourceWillSendRequest,\n  isRunPostTaskCallback: () => isRunPostTaskCallback,\n  isRunTask: () => isRunTask,\n  isRundownScript: () => isRundownScript,\n  isRundownScriptCompiled: () => isRundownScriptCompiled,\n  isRundownScriptSource: () => isRundownScriptSource,\n  isRundownScriptSourceLarge: () => isRundownScriptSourceLarge,\n  isSchedulePostMessage: () => isSchedulePostMessage,\n  isSchedulePostTaskCallback: () => isSchedulePostTaskCallback,\n  isScheduleStyleInvalidationTracking: () => isScheduleStyleInvalidationTracking,\n  isScheduleStyleRecalculation: () => isScheduleStyleRecalculation,\n  isScreenshot: () => isScreenshot,\n  isScrollLayer: () => isScrollLayer,\n  isSelectorStats: () => isSelectorStats,\n  isSetLayerId: () => isSetLayerId,\n  isStyleInvalidatorInvalidationTracking: () => isStyleInvalidatorInvalidationTracking,\n  isStyleRecalcInvalidationTracking: () => isStyleRecalcInvalidationTracking,\n  isSyntheticAnimation: () => isSyntheticAnimation,\n  isSyntheticBased: () => isSyntheticBased,\n  isSyntheticConsoleTiming: () => isSyntheticConsoleTiming,\n  isSyntheticCpuProfile: () => isSyntheticCpuProfile,\n  isSyntheticInteraction: () => isSyntheticInteraction,\n  isSyntheticLayoutShift: () => isSyntheticLayoutShift,\n  isSyntheticLayoutShiftCluster: () => isSyntheticLayoutShiftCluster,\n  isSyntheticNetworkRequest: () => isSyntheticNetworkRequest,\n  isSyntheticUserTiming: () => isSyntheticUserTiming,\n  isSyntheticWebSocketConnection: () => isSyntheticWebSocketConnection,\n  isThreadName: () => isThreadName,\n  isTimerFire: () => isTimerFire,\n  isTimerInstall: () => isTimerInstall,\n  isTracingSessionIdForWorker: () => isTracingSessionIdForWorker,\n  isTracingStartedInBrowser: () => isTracingStartedInBrowser,\n  isUpdateCounters: () => isUpdateCounters,\n  isUpdateLayer: () => isUpdateLayer,\n  isUserTiming: () => isUserTiming,\n  isUserTimingMeasure: () => isUserTimingMeasure,\n  isV8Compile: () => isV8Compile,\n  isWebSocketCreate: () => isWebSocketCreate,\n  isWebSocketDestroy: () => isWebSocketDestroy,\n  isWebSocketEvent: () => isWebSocketEvent,\n  isWebSocketInfo: () => isWebSocketInfo,\n  isWebSocketReceiveHandshakeResponse: () => isWebSocketReceiveHandshakeResponse,\n  isWebSocketSendHandshakeRequest: () => isWebSocketSendHandshakeRequest,\n  isWebSocketTraceEvent: () => isWebSocketTraceEvent,\n  isWebSocketTransfer: () => isWebSocketTransfer,\n  objectIsCallFrame: () => objectIsCallFrame\n});\nfunction isNestableAsyncPhase(phase) {\n  return phase === Phase.ASYNC_NESTABLE_START || phase === Phase.ASYNC_NESTABLE_END || phase === Phase.ASYNC_NESTABLE_INSTANT;\n}\nfunction isPhaseAsync(phase) {\n  return isNestableAsyncPhase(phase) || phase === Phase.ASYNC_BEGIN || phase === Phase.ASYNC_STEP_INTO || phase === Phase.ASYNC_END || phase === Phase.ASYNC_STEP_PAST;\n}\nfunction isFlowPhase(phase) {\n  return phase === Phase.FLOW_START || phase === Phase.FLOW_STEP || phase === Phase.FLOW_END;\n}\nfunction objectIsCallFrame(object) {\n  return \"functionName\" in object && typeof object.functionName === \"string\" && (\"scriptId\" in object && (typeof object.scriptId === \"string\" || typeof object.scriptId === \"number\")) && (\"columnNumber\" in object && typeof object.columnNumber === \"number\") && (\"lineNumber\" in object && typeof object.lineNumber === \"number\") && (\"url\" in object && typeof object.url === \"string\");\n}\nfunction isRunTask(event) {\n  return event.name === Name.RUN_TASK && event.ph === Phase.COMPLETE;\n}\nfunction isAuctionWorkletRunningInProcess(event) {\n  return event.name === \"AuctionWorkletRunningInProcess\";\n}\nfunction isAuctionWorkletDoneWithProcess(event) {\n  return event.name === \"AuctionWorkletDoneWithProcess\";\n}\nfunction isLegacyScreenshot(event) {\n  return event.name === Name.SCREENSHOT && \"id\" in event;\n}\nfunction isLegacySyntheticScreenshot(event) {\n  return event.name === Name.SCREENSHOT && \"dataUri\" in (event.args ?? {});\n}\nfunction isScreenshot(event) {\n  return event.name === Name.SCREENSHOT && \"source_id\" in (event.args ?? {});\n}\nfunction isMarkerEvent(event) {\n  if (event.ph === Phase.INSTANT || event.ph === Phase.MARK) {\n    return markerTypeGuards.some((fn) => fn(event));\n  }\n  return false;\n}\nfunction eventIsPageLoadEvent(event) {\n  if (event.ph === Phase.INSTANT || event.ph === Phase.MARK) {\n    return pageLoadEventTypeGuards.some((fn) => fn(event));\n  }\n  return false;\n}\nfunction isTracingSessionIdForWorker(event) {\n  return event.name === \"TracingSessionIdForWorker\";\n}\nfunction isScheduleStyleInvalidationTracking(event) {\n  return event.name === Name.SCHEDULE_STYLE_INVALIDATION_TRACKING;\n}\nfunction isStyleRecalcInvalidationTracking(event) {\n  return event.name === Name.STYLE_RECALC_INVALIDATION_TRACKING;\n}\nfunction isStyleInvalidatorInvalidationTracking(event) {\n  return event.name === Name.STYLE_INVALIDATOR_INVALIDATION_TRACKING;\n}\nfunction isBeginCommitCompositorFrame(event) {\n  return event.name === Name.BEGIN_COMMIT_COMPOSITOR_FRAME;\n}\nfunction isParseMetaViewport(event) {\n  return event.name === Name.PARSE_META_VIEWPORT;\n}\nfunction isLinkPreconnect(event) {\n  return event.name === Name.LINK_PRECONNECT;\n}\nfunction isScheduleStyleRecalculation(event) {\n  return event.name === Name.SCHEDULE_STYLE_RECALCULATION;\n}\nfunction isRenderFrameImplCreateChildFrame(event) {\n  return event.name === Name.RENDER_FRAME_IMPL_CREATE_CHILD_FRAME;\n}\nfunction isLayoutImageUnsized(event) {\n  return event.name === Name.LAYOUT_IMAGE_UNSIZED;\n}\nfunction isPairableAsyncBegin(e) {\n  return e.ph === Phase.ASYNC_NESTABLE_START;\n}\nfunction isPairableAsyncEnd(e) {\n  return e.ph === Phase.ASYNC_NESTABLE_END;\n}\nfunction isPairableAsyncInstant(e) {\n  return e.ph === Phase.ASYNC_NESTABLE_INSTANT;\n}\nfunction isAnimationFrameAsyncStart(data31) {\n  return data31.name === Name.ANIMATION_FRAME && data31.ph === Phase.ASYNC_NESTABLE_START;\n}\nfunction isAnimationFrameAsyncEnd(data31) {\n  return data31.name === Name.ANIMATION_FRAME && data31.ph === Phase.ASYNC_NESTABLE_END;\n}\nfunction isAnimationFramePresentation(data31) {\n  return data31.name === Name.ANIMATION_FRAME_PRESENTATION;\n}\nfunction isPipelineReporter(event) {\n  return event.name === Name.PIPELINE_REPORTER;\n}\nfunction isSyntheticBased(event) {\n  return \"rawSourceEvent\" in event;\n}\nfunction isSyntheticInteraction(event) {\n  return Boolean(\"interactionId\" in event && event.args?.data && \"beginEvent\" in event.args.data && \"endEvent\" in event.args.data);\n}\nfunction isDrawFrame(event) {\n  return event.name === Name.DRAW_FRAME && event.ph === Phase.INSTANT;\n}\nfunction isBeginFrame(event) {\n  return Boolean(event.name === Name.BEGIN_FRAME && event.args && \"frameSeqId\" in event.args);\n}\nfunction isDroppedFrame(event) {\n  return Boolean(event.name === Name.DROPPED_FRAME && event.args && \"frameSeqId\" in event.args);\n}\nfunction isRequestMainThreadFrame(event) {\n  return event.name === Name.REQUEST_MAIN_THREAD_FRAME;\n}\nfunction isBeginMainThreadFrame(event) {\n  return event.name === Name.BEGIN_MAIN_THREAD_FRAME;\n}\nfunction isNeedsBeginFrameChanged(event) {\n  return event.name === Name.NEEDS_BEGIN_FRAME_CHANGED;\n}\nfunction isCommit(event) {\n  return Boolean(event.name === Name.COMMIT && event.args && \"frameSeqId\" in event.args);\n}\nfunction isRasterTask(event) {\n  return event.name === Name.RASTER_TASK;\n}\nfunction isCompositeLayers(event) {\n  return event.name === Name.COMPOSITE_LAYERS;\n}\nfunction isActivateLayerTree(event) {\n  return event.name === Name.ACTIVATE_LAYER_TREE;\n}\nfunction isInvalidationTracking(event) {\n  return isScheduleStyleInvalidationTracking(event) || isStyleRecalcInvalidationTracking(event) || isStyleInvalidatorInvalidationTracking(event) || isLayoutInvalidationTracking(event);\n}\nfunction isDrawLazyPixelRef(event) {\n  return event.name === Name.DRAW_LAZY_PIXEL_REF;\n}\nfunction isDecodeLazyPixelRef(event) {\n  return event.name === Name.DECODE_LAZY_PIXEL_REF;\n}\nfunction isDecodeImage(event) {\n  return event.name === Name.DECODE_IMAGE;\n}\nfunction isSelectorStats(event) {\n  return event.name === Name.SELECTOR_STATS;\n}\nfunction isRecalcStyle(event) {\n  return event.name === Name.RECALC_STYLE;\n}\nfunction isLayout(event) {\n  return event.name === Name.LAYOUT && Boolean(event.args && \"beginData\" in event.args);\n}\nfunction isInvalidateLayout(event) {\n  return event.name === Name.INVALIDATE_LAYOUT;\n}\nfunction isDebuggerAsyncTaskScheduled(event) {\n  return event.name === Name.DEBUGGER_ASYNC_TASK_SCHEDULED;\n}\nfunction isDebuggerAsyncTaskRun(event) {\n  return event.name === Name.DEBUGGER_ASYNC_TASK_RUN;\n}\nfunction ProfileID(value) {\n  return value;\n}\nfunction CallFrameID(value) {\n  return value;\n}\nfunction SampleIndex(value) {\n  return value;\n}\nfunction ProcessID(value) {\n  return value;\n}\nfunction ThreadID(value) {\n  return value;\n}\nfunction WorkerId(value) {\n  return value;\n}\nfunction isComplete(event) {\n  return event.ph === Phase.COMPLETE;\n}\nfunction isBegin(event) {\n  return event.ph === Phase.BEGIN;\n}\nfunction isEnd(event) {\n  return event.ph === Phase.END;\n}\nfunction isDispatch(event) {\n  return event.name === \"EventDispatch\" && event.ph === Phase.COMPLETE;\n}\nfunction isInstant(event) {\n  return event.ph === Phase.INSTANT;\n}\nfunction isRendererEvent(event) {\n  return isInstant(event) || isComplete(event);\n}\nfunction isFireIdleCallback(event) {\n  return event.name === \"FireIdleCallback\" && event.ph === Phase.COMPLETE;\n}\nfunction isSchedulePostMessage(event) {\n  return event.name === Name.SCHEDULE_POST_MESSAGE;\n}\nfunction isHandlePostMessage(event) {\n  return event.name === Name.HANDLE_POST_MESSAGE && event.ph === Phase.COMPLETE;\n}\nfunction isUpdateCounters(event) {\n  return event.name === \"UpdateCounters\";\n}\nfunction isDOMStats(event) {\n  return event.name === \"DOMStats\";\n}\nfunction isThreadName(event) {\n  return event.name === Name.THREAD_NAME;\n}\nfunction isProcessName(event) {\n  return event.name === \"process_name\";\n}\nfunction isTracingStartedInBrowser(event) {\n  return event.name === Name.TRACING_STARTED_IN_BROWSER;\n}\nfunction isFrameCommittedInBrowser(event) {\n  return event.name === \"FrameCommittedInBrowser\";\n}\nfunction isCommitLoad(event) {\n  return event.name === \"CommitLoad\";\n}\nfunction isAnimation(event) {\n  return event.name === \"Animation\" && event.cat.includes(\"devtools.timeline\");\n}\nfunction isSyntheticAnimation(event) {\n  if (event.name !== \"Animation\" || !event.cat.includes(\"devtools.timeline\")) {\n    return false;\n  }\n  const data31 = event.args?.data;\n  if (!data31) {\n    return false;\n  }\n  return \"beginEvent\" in data31 && \"endEvent\" in data31;\n}\nfunction isLayoutShift(event) {\n  return event.name === Name.LAYOUT_SHIFT;\n}\nfunction isLayoutInvalidationTracking(event) {\n  return event.name === Name.LAYOUT_INVALIDATION_TRACKING;\n}\nfunction isFirstContentfulPaint(event) {\n  return event.name === \"firstContentfulPaint\";\n}\nfunction isLargestContentfulPaintCandidate(event) {\n  return event.name === Name.MARK_LCP_CANDIDATE;\n}\nfunction isLargestImagePaintCandidate(event) {\n  return event.name === \"LargestImagePaint::Candidate\";\n}\nfunction isLargestTextPaintCandidate(event) {\n  return event.name === \"LargestTextPaint::Candidate\";\n}\nfunction isMarkLoad(event) {\n  return event.name === \"MarkLoad\";\n}\nfunction isFirstPaint(event) {\n  return event.name === \"firstPaint\";\n}\nfunction isMarkDOMContent(event) {\n  return event.name === \"MarkDOMContent\";\n}\nfunction isInteractiveTime(event) {\n  return event.name === \"InteractiveTime\";\n}\nfunction isEventTiming(event) {\n  return event.name === Name.EVENT_TIMING;\n}\nfunction isEventTimingEnd(event) {\n  return isEventTiming(event) && event.ph === Phase.ASYNC_NESTABLE_END;\n}\nfunction isEventTimingStart(event) {\n  return isEventTiming(event) && event.ph === Phase.ASYNC_NESTABLE_START;\n}\nfunction isGPUTask(event) {\n  return event.name === \"GPUTask\";\n}\nfunction isProfile(event) {\n  return event.name === Name.PROFILE;\n}\nfunction isSyntheticCpuProfile(event) {\n  return event.name === Name.CPU_PROFILE && event.ph === Phase.COMPLETE;\n}\nfunction isProfileChunk(event) {\n  return event.name === Name.PROFILE_CHUNK;\n}\nfunction isResourceChangePriority(event) {\n  return event.name === \"ResourceChangePriority\";\n}\nfunction isResourceSendRequest(event) {\n  return event.name === \"ResourceSendRequest\";\n}\nfunction isResourceReceiveResponse(event) {\n  return event.name === \"ResourceReceiveResponse\";\n}\nfunction isResourceMarkAsCached(event) {\n  return event.name === \"ResourceMarkAsCached\";\n}\nfunction isResourceFinish(event) {\n  return event.name === \"ResourceFinish\";\n}\nfunction isResourceWillSendRequest(event) {\n  return event.name === \"ResourceWillSendRequest\";\n}\nfunction isResourceReceivedData(event) {\n  return event.name === \"ResourceReceivedData\";\n}\nfunction isReceivedDataEvent(event) {\n  return event.name === \"ResourceReceivedData\" || event.name === \"ResourceFinish\" || event.name === \"ResourceReceiveResponse\";\n}\nfunction isSyntheticNetworkRequest(event) {\n  return event.name === Name.SYNTHETIC_NETWORK_REQUEST;\n}\nfunction isSyntheticWebSocketConnection(event) {\n  return event.name === \"SyntheticWebSocketConnection\";\n}\nfunction isNetworkTrackEntry(event) {\n  return isSyntheticNetworkRequest(event) || isSyntheticWebSocketConnection(event) || isWebSocketTraceEvent(event);\n}\nfunction isPrePaint(event) {\n  return event.name === \"PrePaint\";\n}\nfunction isNavigationStart(event) {\n  return event.name === \"navigationStart\" && event.args?.data?.documentLoaderURL !== \"\";\n}\nfunction isDidCommitSameDocumentNavigation(event) {\n  return event.name === \"RenderFrameHostImpl::DidCommitSameDocumentNavigation\" && event.ph === Phase.COMPLETE;\n}\nfunction isMainFrameViewport(event) {\n  return event.name === \"PaintTimingVisualizer::Viewport\";\n}\nfunction isSyntheticUserTiming(event) {\n  if (event.cat !== \"blink.user_timing\") {\n    return false;\n  }\n  const data31 = event.args?.data;\n  if (!data31) {\n    return false;\n  }\n  return \"beginEvent\" in data31 && \"endEvent\" in data31;\n}\nfunction isSyntheticConsoleTiming(event) {\n  if (event.cat !== \"blink.console\") {\n    return false;\n  }\n  const data31 = event.args?.data;\n  if (!data31) {\n    return false;\n  }\n  return \"beginEvent\" in data31 && \"endEvent\" in data31;\n}\nfunction isUserTiming(event) {\n  return event.cat === \"blink.user_timing\";\n}\nfunction isDomLoading(event) {\n  return event.name === Name.DOM_LOADING;\n}\nfunction isBeginRemoteFontLoad(event) {\n  return event.name === Name.BEGIN_REMOTE_FONT_LOAD;\n}\nfunction isRemoteFontLoaded(event) {\n  return event.name === Name.REMOTE_FONT_LOADED;\n}\nfunction isPerformanceMeasure(event) {\n  return isUserTiming(event) && isPhaseAsync(event.ph);\n}\nfunction isPerformanceMeasureBegin(event) {\n  return isPerformanceMeasure(event) && event.ph === Phase.ASYNC_NESTABLE_START;\n}\nfunction isPerformanceMark(event) {\n  return isUserTiming(event) && (event.ph === Phase.MARK || event.ph === Phase.INSTANT);\n}\nfunction isConsoleTime(event) {\n  return event.cat === \"blink.console\" && isPhaseAsync(event.ph);\n}\nfunction isConsoleTimeStamp(event) {\n  return event.ph === Phase.INSTANT && event.name === Name.TIME_STAMP;\n}\nfunction isUserTimingMeasure(event) {\n  return event.name === Name.USER_TIMING_MEASURE;\n}\nfunction isParseHTML(event) {\n  return event.name === \"ParseHTML\";\n}\nfunction isSyntheticLayoutShift(event) {\n  return event.name === Name.SYNTHETIC_LAYOUT_SHIFT;\n}\nfunction isSyntheticLayoutShiftCluster(event) {\n  return event.name === Name.SYNTHETIC_LAYOUT_SHIFT_CLUSTER;\n}\nfunction isProfileCall(event) {\n  return \"callFrame\" in event;\n}\nfunction isPaint(event) {\n  return event.name === Name.PAINT;\n}\nfunction isPaintImage(event) {\n  return event.name === Name.PAINT_IMAGE && event.ph === Phase.COMPLETE;\n}\nfunction isScrollLayer(event) {\n  return event.name === Name.SCROLL_LAYER && event.ph === Phase.COMPLETE;\n}\nfunction isSetLayerId(event) {\n  return event.name === Name.SET_LAYER_TREE_ID;\n}\nfunction isUpdateLayer(event) {\n  return event.name === Name.UPDATE_LAYER;\n}\nfunction isDisplayListItemListSnapshot(event) {\n  return event.name === Name.DISPLAY_ITEM_LIST_SNAPSHOT;\n}\nfunction isLayerTreeHostImplSnapshot(event) {\n  return event.name === Name.LAYER_TREE_HOST_IMPL_SNAPSHOT;\n}\nfunction isFireAnimationFrame(event) {\n  return event.name === Name.FIRE_ANIMATION_FRAME && event.ph === Phase.COMPLETE;\n}\nfunction isTimerInstall(event) {\n  return event.name === Name.TIMER_INSTALL;\n}\nfunction isTimerFire(event) {\n  return event.name === Name.TIMER_FIRE && event.ph === Phase.COMPLETE;\n}\nfunction isRequestIdleCallback(event) {\n  return event.name === Name.REQUEST_IDLE_CALLBACK;\n}\nfunction isWebSocketCreate(event) {\n  return event.name === Name.WEB_SOCKET_CREATE;\n}\nfunction isWebSocketInfo(event) {\n  return event.name === Name.WEB_SOCKET_SEND_HANDSHAKE_REQUEST || event.name === Name.WEB_SOCKET_RECEIVE_HANDSHAKE_REQUEST || event.name === Name.WEB_SOCKET_DESTROY;\n}\nfunction isWebSocketTransfer(event) {\n  return event.name === Name.WEB_SOCKET_SEND || event.name === Name.WEB_SOCKET_RECEIVE;\n}\nfunction isWebSocketSendHandshakeRequest(event) {\n  return event.name === Name.WEB_SOCKET_SEND_HANDSHAKE_REQUEST;\n}\nfunction isWebSocketReceiveHandshakeResponse(event) {\n  return event.name === Name.WEB_SOCKET_RECEIVE_HANDSHAKE_REQUEST;\n}\nfunction isWebSocketDestroy(event) {\n  return event.name === Name.WEB_SOCKET_DESTROY;\n}\nfunction isWebSocketTraceEvent(event) {\n  return isWebSocketCreate(event) || isWebSocketInfo(event) || isWebSocketTransfer(event);\n}\nfunction isWebSocketEvent(event) {\n  return isWebSocketTraceEvent(event) || isSyntheticWebSocketConnection(event);\n}\nfunction isV8Compile(event) {\n  return event.name === Name.COMPILE && event.ph === Phase.COMPLETE;\n}\nfunction isFunctionCall(event) {\n  return event.name === Name.FUNCTION_CALL && event.ph === Phase.COMPLETE;\n}\nfunction isSchedulePostTaskCallback(event) {\n  return event.name === Name.SCHEDULE_POST_TASK_CALLBACK;\n}\nfunction isRunPostTaskCallback(event) {\n  return event.name === Name.RUN_POST_TASK_CALLBACK && event.ph === Phase.COMPLETE;\n}\nfunction isAbortPostTaskCallback(event) {\n  return event.name === Name.ABORT_POST_TASK_CALLBACK && event.ph === Phase.COMPLETE;\n}\nfunction isJSInvocationEvent(event) {\n  switch (event.name) {\n    case Name.RUN_MICROTASKS:\n    case Name.FUNCTION_CALL:\n    // TODO(paulirish): Define types for these Evaluate* events\n    case Name.EVALUATE_SCRIPT:\n    case Name.EVALUATE_MODULE:\n    case Name.EVENT_DISPATCH:\n    case Name.V8_EXECUTE:\n    case Name.V8_CONSOLE_RUN_TASK:\n      return true;\n  }\n  if (event.name.startsWith(\"v8\") || event.name.startsWith(\"V8\")) {\n    return true;\n  }\n  if (isConsoleRunTask(event)) {\n    return true;\n  }\n  return false;\n}\nfunction isConsoleRunTask(event) {\n  return event.name === Name.V8_CONSOLE_RUN_TASK;\n}\nfunction isFlowPhaseEvent(event) {\n  return event.ph === Phase.FLOW_START || event.ph === Phase.FLOW_STEP || event.ph === Phase.FLOW_END;\n}\nfunction isParseAuthorStyleSheetEvent(event) {\n  return event.name === Name.PARSE_AUTHOR_STYLE_SHEET && event.ph === Phase.COMPLETE;\n}\nfunction isLegacyTimelineFrame(data31) {\n  return \"idle\" in data31 && typeof data31.idle === \"boolean\";\n}\nfunction isRundownScriptCompiled(event) {\n  return event.cat === \"disabled-by-default-devtools.target-rundown\";\n}\nfunction isRundownScript(event) {\n  return event.cat === \"disabled-by-default-devtools.v8-source-rundown\" && event.name === \"ScriptCatchup\";\n}\nfunction isRundownScriptSource(event) {\n  return event.cat === \"disabled-by-default-devtools.v8-source-rundown-sources\" && event.name === \"ScriptCatchup\";\n}\nfunction isRundownScriptSourceLarge(event) {\n  return event.cat === \"disabled-by-default-devtools.v8-source-rundown-sources\" && event.name === \"LargeScriptCatchup\";\n}\nfunction isAnyScriptSourceEvent(event) {\n  return event.cat === \"disabled-by-default-devtools.v8-source-rundown-sources\";\n}\nvar Phase, Scope, AuctionWorkletType, markerTypeGuards, MarkerName, pageLoadEventTypeGuards, NO_NAVIGATION, LayoutInvalidationReason, StyleRecalcInvalidationReason, InvalidationEventType, SelectorTimingsKey, Name, Categories;\nvar init_TraceEvents = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/types/TraceEvents.js\"() {\n    init_process_global();\n    (function(Phase2) {\n      Phase2[\"BEGIN\"] = \"B\";\n      Phase2[\"END\"] = \"E\";\n      Phase2[\"COMPLETE\"] = \"X\";\n      Phase2[\"INSTANT\"] = \"I\";\n      Phase2[\"COUNTER\"] = \"C\";\n      Phase2[\"ASYNC_NESTABLE_START\"] = \"b\";\n      Phase2[\"ASYNC_NESTABLE_INSTANT\"] = \"n\";\n      Phase2[\"ASYNC_NESTABLE_END\"] = \"e\";\n      Phase2[\"ASYNC_STEP_INTO\"] = \"T\";\n      Phase2[\"ASYNC_BEGIN\"] = \"S\";\n      Phase2[\"ASYNC_END\"] = \"F\";\n      Phase2[\"ASYNC_STEP_PAST\"] = \"p\";\n      Phase2[\"FLOW_START\"] = \"s\";\n      Phase2[\"FLOW_STEP\"] = \"t\";\n      Phase2[\"FLOW_END\"] = \"f\";\n      Phase2[\"SAMPLE\"] = \"P\";\n      Phase2[\"OBJECT_CREATED\"] = \"N\";\n      Phase2[\"OBJECT_SNAPSHOT\"] = \"O\";\n      Phase2[\"OBJECT_DESTROYED\"] = \"D\";\n      Phase2[\"METADATA\"] = \"M\";\n      Phase2[\"MEMORY_DUMP_GLOBAL\"] = \"V\";\n      Phase2[\"MEMORY_DUMP_PROCESS\"] = \"v\";\n      Phase2[\"MARK\"] = \"R\";\n      Phase2[\"CLOCK_SYNC\"] = \"c\";\n    })(Phase || (Phase = {}));\n    __name(isNestableAsyncPhase, \"isNestableAsyncPhase\");\n    __name(isPhaseAsync, \"isPhaseAsync\");\n    __name(isFlowPhase, \"isFlowPhase\");\n    (function(Scope2) {\n      Scope2[\"THREAD\"] = \"t\";\n      Scope2[\"PROCESS\"] = \"p\";\n      Scope2[\"GLOBAL\"] = \"g\";\n    })(Scope || (Scope = {}));\n    __name(objectIsCallFrame, \"objectIsCallFrame\");\n    __name(isRunTask, \"isRunTask\");\n    (function(AuctionWorkletType2) {\n      AuctionWorkletType2[\"BIDDER\"] = \"bidder\";\n      AuctionWorkletType2[\"SELLER\"] = \"seller\";\n      AuctionWorkletType2[\"UNKNOWN\"] = \"unknown\";\n    })(AuctionWorkletType || (AuctionWorkletType = {}));\n    __name(isAuctionWorkletRunningInProcess, \"isAuctionWorkletRunningInProcess\");\n    __name(isAuctionWorkletDoneWithProcess, \"isAuctionWorkletDoneWithProcess\");\n    __name(isLegacyScreenshot, \"isLegacyScreenshot\");\n    __name(isLegacySyntheticScreenshot, \"isLegacySyntheticScreenshot\");\n    __name(isScreenshot, \"isScreenshot\");\n    markerTypeGuards = [\n      isMarkDOMContent,\n      isMarkLoad,\n      isFirstPaint,\n      isFirstContentfulPaint,\n      isLargestContentfulPaintCandidate,\n      isNavigationStart\n    ];\n    MarkerName = [\"MarkDOMContent\", \"MarkLoad\", \"firstPaint\", \"firstContentfulPaint\", \"largestContentfulPaint::Candidate\"];\n    __name(isMarkerEvent, \"isMarkerEvent\");\n    pageLoadEventTypeGuards = [\n      ...markerTypeGuards,\n      isInteractiveTime\n    ];\n    __name(eventIsPageLoadEvent, \"eventIsPageLoadEvent\");\n    __name(isTracingSessionIdForWorker, \"isTracingSessionIdForWorker\");\n    NO_NAVIGATION = \"NO_NAVIGATION\";\n    (function(LayoutInvalidationReason2) {\n      LayoutInvalidationReason2[\"SIZE_CHANGED\"] = \"Size changed\";\n      LayoutInvalidationReason2[\"ATTRIBUTE\"] = \"Attribute\";\n      LayoutInvalidationReason2[\"ADDED_TO_LAYOUT\"] = \"Added to layout\";\n      LayoutInvalidationReason2[\"SCROLLBAR_CHANGED\"] = \"Scrollbar changed\";\n      LayoutInvalidationReason2[\"REMOVED_FROM_LAYOUT\"] = \"Removed from layout\";\n      LayoutInvalidationReason2[\"STYLE_CHANGED\"] = \"Style changed\";\n      LayoutInvalidationReason2[\"FONTS_CHANGED\"] = \"Fonts changed\";\n      LayoutInvalidationReason2[\"UNKNOWN\"] = \"Unknown\";\n    })(LayoutInvalidationReason || (LayoutInvalidationReason = {}));\n    __name(isScheduleStyleInvalidationTracking, \"isScheduleStyleInvalidationTracking\");\n    (function(StyleRecalcInvalidationReason2) {\n      StyleRecalcInvalidationReason2[\"ANIMATION\"] = \"Animation\";\n      StyleRecalcInvalidationReason2[\"RELATED_STYLE_RULE\"] = \"Related style rule\";\n    })(StyleRecalcInvalidationReason || (StyleRecalcInvalidationReason = {}));\n    __name(isStyleRecalcInvalidationTracking, \"isStyleRecalcInvalidationTracking\");\n    __name(isStyleInvalidatorInvalidationTracking, \"isStyleInvalidatorInvalidationTracking\");\n    __name(isBeginCommitCompositorFrame, \"isBeginCommitCompositorFrame\");\n    __name(isParseMetaViewport, \"isParseMetaViewport\");\n    __name(isLinkPreconnect, \"isLinkPreconnect\");\n    __name(isScheduleStyleRecalculation, \"isScheduleStyleRecalculation\");\n    __name(isRenderFrameImplCreateChildFrame, \"isRenderFrameImplCreateChildFrame\");\n    __name(isLayoutImageUnsized, \"isLayoutImageUnsized\");\n    __name(isPairableAsyncBegin, \"isPairableAsyncBegin\");\n    __name(isPairableAsyncEnd, \"isPairableAsyncEnd\");\n    __name(isPairableAsyncInstant, \"isPairableAsyncInstant\");\n    __name(isAnimationFrameAsyncStart, \"isAnimationFrameAsyncStart\");\n    __name(isAnimationFrameAsyncEnd, \"isAnimationFrameAsyncEnd\");\n    __name(isAnimationFramePresentation, \"isAnimationFramePresentation\");\n    __name(isPipelineReporter, \"isPipelineReporter\");\n    __name(isSyntheticBased, \"isSyntheticBased\");\n    __name(isSyntheticInteraction, \"isSyntheticInteraction\");\n    __name(isDrawFrame, \"isDrawFrame\");\n    __name(isBeginFrame, \"isBeginFrame\");\n    __name(isDroppedFrame, \"isDroppedFrame\");\n    __name(isRequestMainThreadFrame, \"isRequestMainThreadFrame\");\n    __name(isBeginMainThreadFrame, \"isBeginMainThreadFrame\");\n    __name(isNeedsBeginFrameChanged, \"isNeedsBeginFrameChanged\");\n    __name(isCommit, \"isCommit\");\n    __name(isRasterTask, \"isRasterTask\");\n    __name(isCompositeLayers, \"isCompositeLayers\");\n    __name(isActivateLayerTree, \"isActivateLayerTree\");\n    __name(isInvalidationTracking, \"isInvalidationTracking\");\n    __name(isDrawLazyPixelRef, \"isDrawLazyPixelRef\");\n    __name(isDecodeLazyPixelRef, \"isDecodeLazyPixelRef\");\n    __name(isDecodeImage, \"isDecodeImage\");\n    (function(InvalidationEventType2) {\n      InvalidationEventType2[\"StyleInvalidatorInvalidationTracking\"] = \"StyleInvalidatorInvalidationTracking\";\n      InvalidationEventType2[\"StyleRecalcInvalidationTracking\"] = \"StyleRecalcInvalidationTracking\";\n    })(InvalidationEventType || (InvalidationEventType = {}));\n    (function(SelectorTimingsKey2) {\n      SelectorTimingsKey2[\"Elapsed\"] = \"elapsed (us)\";\n      SelectorTimingsKey2[\"RejectPercentage\"] = \"reject_percentage\";\n      SelectorTimingsKey2[\"FastRejectCount\"] = \"fast_reject_count\";\n      SelectorTimingsKey2[\"MatchAttempts\"] = \"match_attempts\";\n      SelectorTimingsKey2[\"MatchCount\"] = \"match_count\";\n      SelectorTimingsKey2[\"Selector\"] = \"selector\";\n      SelectorTimingsKey2[\"StyleSheetId\"] = \"style_sheet_id\";\n      SelectorTimingsKey2[\"InvalidationCount\"] = \"invalidation_count\";\n    })(SelectorTimingsKey || (SelectorTimingsKey = {}));\n    __name(isSelectorStats, \"isSelectorStats\");\n    __name(isRecalcStyle, \"isRecalcStyle\");\n    __name(isLayout, \"isLayout\");\n    __name(isInvalidateLayout, \"isInvalidateLayout\");\n    __name(isDebuggerAsyncTaskScheduled, \"isDebuggerAsyncTaskScheduled\");\n    __name(isDebuggerAsyncTaskRun, \"isDebuggerAsyncTaskRun\");\n    __name(ProfileID, \"ProfileID\");\n    __name(CallFrameID, \"CallFrameID\");\n    __name(SampleIndex, \"SampleIndex\");\n    __name(ProcessID, \"ProcessID\");\n    __name(ThreadID, \"ThreadID\");\n    __name(WorkerId, \"WorkerId\");\n    __name(isComplete, \"isComplete\");\n    __name(isBegin, \"isBegin\");\n    __name(isEnd, \"isEnd\");\n    __name(isDispatch, \"isDispatch\");\n    __name(isInstant, \"isInstant\");\n    __name(isRendererEvent, \"isRendererEvent\");\n    __name(isFireIdleCallback, \"isFireIdleCallback\");\n    __name(isSchedulePostMessage, \"isSchedulePostMessage\");\n    __name(isHandlePostMessage, \"isHandlePostMessage\");\n    __name(isUpdateCounters, \"isUpdateCounters\");\n    __name(isDOMStats, \"isDOMStats\");\n    __name(isThreadName, \"isThreadName\");\n    __name(isProcessName, \"isProcessName\");\n    __name(isTracingStartedInBrowser, \"isTracingStartedInBrowser\");\n    __name(isFrameCommittedInBrowser, \"isFrameCommittedInBrowser\");\n    __name(isCommitLoad, \"isCommitLoad\");\n    __name(isAnimation, \"isAnimation\");\n    __name(isSyntheticAnimation, \"isSyntheticAnimation\");\n    __name(isLayoutShift, \"isLayoutShift\");\n    __name(isLayoutInvalidationTracking, \"isLayoutInvalidationTracking\");\n    __name(isFirstContentfulPaint, \"isFirstContentfulPaint\");\n    __name(isLargestContentfulPaintCandidate, \"isLargestContentfulPaintCandidate\");\n    __name(isLargestImagePaintCandidate, \"isLargestImagePaintCandidate\");\n    __name(isLargestTextPaintCandidate, \"isLargestTextPaintCandidate\");\n    __name(isMarkLoad, \"isMarkLoad\");\n    __name(isFirstPaint, \"isFirstPaint\");\n    __name(isMarkDOMContent, \"isMarkDOMContent\");\n    __name(isInteractiveTime, \"isInteractiveTime\");\n    __name(isEventTiming, \"isEventTiming\");\n    __name(isEventTimingEnd, \"isEventTimingEnd\");\n    __name(isEventTimingStart, \"isEventTimingStart\");\n    __name(isGPUTask, \"isGPUTask\");\n    __name(isProfile, \"isProfile\");\n    __name(isSyntheticCpuProfile, \"isSyntheticCpuProfile\");\n    __name(isProfileChunk, \"isProfileChunk\");\n    __name(isResourceChangePriority, \"isResourceChangePriority\");\n    __name(isResourceSendRequest, \"isResourceSendRequest\");\n    __name(isResourceReceiveResponse, \"isResourceReceiveResponse\");\n    __name(isResourceMarkAsCached, \"isResourceMarkAsCached\");\n    __name(isResourceFinish, \"isResourceFinish\");\n    __name(isResourceWillSendRequest, \"isResourceWillSendRequest\");\n    __name(isResourceReceivedData, \"isResourceReceivedData\");\n    __name(isReceivedDataEvent, \"isReceivedDataEvent\");\n    __name(isSyntheticNetworkRequest, \"isSyntheticNetworkRequest\");\n    __name(isSyntheticWebSocketConnection, \"isSyntheticWebSocketConnection\");\n    __name(isNetworkTrackEntry, \"isNetworkTrackEntry\");\n    __name(isPrePaint, \"isPrePaint\");\n    __name(isNavigationStart, \"isNavigationStart\");\n    __name(isDidCommitSameDocumentNavigation, \"isDidCommitSameDocumentNavigation\");\n    __name(isMainFrameViewport, \"isMainFrameViewport\");\n    __name(isSyntheticUserTiming, \"isSyntheticUserTiming\");\n    __name(isSyntheticConsoleTiming, \"isSyntheticConsoleTiming\");\n    __name(isUserTiming, \"isUserTiming\");\n    __name(isDomLoading, \"isDomLoading\");\n    __name(isBeginRemoteFontLoad, \"isBeginRemoteFontLoad\");\n    __name(isRemoteFontLoaded, \"isRemoteFontLoaded\");\n    __name(isPerformanceMeasure, \"isPerformanceMeasure\");\n    __name(isPerformanceMeasureBegin, \"isPerformanceMeasureBegin\");\n    __name(isPerformanceMark, \"isPerformanceMark\");\n    __name(isConsoleTime, \"isConsoleTime\");\n    __name(isConsoleTimeStamp, \"isConsoleTimeStamp\");\n    __name(isUserTimingMeasure, \"isUserTimingMeasure\");\n    __name(isParseHTML, \"isParseHTML\");\n    __name(isSyntheticLayoutShift, \"isSyntheticLayoutShift\");\n    __name(isSyntheticLayoutShiftCluster, \"isSyntheticLayoutShiftCluster\");\n    __name(isProfileCall, \"isProfileCall\");\n    __name(isPaint, \"isPaint\");\n    __name(isPaintImage, \"isPaintImage\");\n    __name(isScrollLayer, \"isScrollLayer\");\n    __name(isSetLayerId, \"isSetLayerId\");\n    __name(isUpdateLayer, \"isUpdateLayer\");\n    __name(isDisplayListItemListSnapshot, \"isDisplayListItemListSnapshot\");\n    __name(isLayerTreeHostImplSnapshot, \"isLayerTreeHostImplSnapshot\");\n    __name(isFireAnimationFrame, \"isFireAnimationFrame\");\n    __name(isTimerInstall, \"isTimerInstall\");\n    __name(isTimerFire, \"isTimerFire\");\n    __name(isRequestIdleCallback, \"isRequestIdleCallback\");\n    __name(isWebSocketCreate, \"isWebSocketCreate\");\n    __name(isWebSocketInfo, \"isWebSocketInfo\");\n    __name(isWebSocketTransfer, \"isWebSocketTransfer\");\n    __name(isWebSocketSendHandshakeRequest, \"isWebSocketSendHandshakeRequest\");\n    __name(isWebSocketReceiveHandshakeResponse, \"isWebSocketReceiveHandshakeResponse\");\n    __name(isWebSocketDestroy, \"isWebSocketDestroy\");\n    __name(isWebSocketTraceEvent, \"isWebSocketTraceEvent\");\n    __name(isWebSocketEvent, \"isWebSocketEvent\");\n    __name(isV8Compile, \"isV8Compile\");\n    __name(isFunctionCall, \"isFunctionCall\");\n    __name(isSchedulePostTaskCallback, \"isSchedulePostTaskCallback\");\n    __name(isRunPostTaskCallback, \"isRunPostTaskCallback\");\n    __name(isAbortPostTaskCallback, \"isAbortPostTaskCallback\");\n    __name(isJSInvocationEvent, \"isJSInvocationEvent\");\n    __name(isConsoleRunTask, \"isConsoleRunTask\");\n    __name(isFlowPhaseEvent, \"isFlowPhaseEvent\");\n    __name(isParseAuthorStyleSheetEvent, \"isParseAuthorStyleSheetEvent\");\n    (function(Name2) {\n      Name2[\"THREAD_NAME\"] = \"thread_name\";\n      Name2[\"PROGRAM\"] = \"Program\";\n      Name2[\"RUN_TASK\"] = \"RunTask\";\n      Name2[\"ASYNC_TASK\"] = \"AsyncTask\";\n      Name2[\"RUN_MICROTASKS\"] = \"RunMicrotasks\";\n      Name2[\"XHR_LOAD\"] = \"XHRLoad\";\n      Name2[\"XHR_READY_STATE_CHANGED\"] = \"XHRReadyStateChange\";\n      Name2[\"PARSE_HTML\"] = \"ParseHTML\";\n      Name2[\"PARSE_CSS\"] = \"ParseAuthorStyleSheet\";\n      Name2[\"COMPILE_CODE\"] = \"V8.CompileCode\";\n      Name2[\"COMPILE_MODULE\"] = \"V8.CompileModule\";\n      Name2[\"COMPILE\"] = \"v8.compile\";\n      Name2[\"COMPILE_SCRIPT\"] = \"V8.CompileScript\";\n      Name2[\"OPTIMIZE\"] = \"V8.OptimizeCode\";\n      Name2[\"WASM_STREAM_FROM_RESPONSE_CALLBACK\"] = \"v8.wasm.streamFromResponseCallback\";\n      Name2[\"WASM_COMPILED_MODULE\"] = \"v8.wasm.compiledModule\";\n      Name2[\"WASM_CACHED_MODULE\"] = \"v8.wasm.cachedModule\";\n      Name2[\"WASM_MODULE_CACHE_HIT\"] = \"v8.wasm.moduleCacheHit\";\n      Name2[\"WASM_MODULE_CACHE_INVALID\"] = \"v8.wasm.moduleCacheInvalid\";\n      Name2[\"PROFILE_CALL\"] = \"ProfileCall\";\n      Name2[\"EVALUATE_SCRIPT\"] = \"EvaluateScript\";\n      Name2[\"FUNCTION_CALL\"] = \"FunctionCall\";\n      Name2[\"EVENT_DISPATCH\"] = \"EventDispatch\";\n      Name2[\"EVALUATE_MODULE\"] = \"v8.evaluateModule\";\n      Name2[\"REQUEST_MAIN_THREAD_FRAME\"] = \"RequestMainThreadFrame\";\n      Name2[\"REQUEST_ANIMATION_FRAME\"] = \"RequestAnimationFrame\";\n      Name2[\"CANCEL_ANIMATION_FRAME\"] = \"CancelAnimationFrame\";\n      Name2[\"FIRE_ANIMATION_FRAME\"] = \"FireAnimationFrame\";\n      Name2[\"REQUEST_IDLE_CALLBACK\"] = \"RequestIdleCallback\";\n      Name2[\"CANCEL_IDLE_CALLBACK\"] = \"CancelIdleCallback\";\n      Name2[\"FIRE_IDLE_CALLBACK\"] = \"FireIdleCallback\";\n      Name2[\"TIMER_INSTALL\"] = \"TimerInstall\";\n      Name2[\"TIMER_REMOVE\"] = \"TimerRemove\";\n      Name2[\"TIMER_FIRE\"] = \"TimerFire\";\n      Name2[\"WEB_SOCKET_CREATE\"] = \"WebSocketCreate\";\n      Name2[\"WEB_SOCKET_SEND_HANDSHAKE\"] = \"WebSocketSendHandshakeRequest\";\n      Name2[\"WEB_SOCKET_RECEIVE_HANDSHAKE\"] = \"WebSocketReceiveHandshakeResponse\";\n      Name2[\"WEB_SOCKET_DESTROY\"] = \"WebSocketDestroy\";\n      Name2[\"WEB_SOCKET_SEND\"] = \"WebSocketSend\";\n      Name2[\"WEB_SOCKET_RECEIVE\"] = \"WebSocketReceive\";\n      Name2[\"CRYPTO_DO_ENCRYPT\"] = \"DoEncrypt\";\n      Name2[\"CRYPTO_DO_ENCRYPT_REPLY\"] = \"DoEncryptReply\";\n      Name2[\"CRYPTO_DO_DECRYPT\"] = \"DoDecrypt\";\n      Name2[\"CRYPTO_DO_DECRYPT_REPLY\"] = \"DoDecryptReply\";\n      Name2[\"CRYPTO_DO_DIGEST\"] = \"DoDigest\";\n      Name2[\"CRYPTO_DO_DIGEST_REPLY\"] = \"DoDigestReply\";\n      Name2[\"CRYPTO_DO_SIGN\"] = \"DoSign\";\n      Name2[\"CRYPTO_DO_SIGN_REPLY\"] = \"DoSignReply\";\n      Name2[\"CRYPTO_DO_VERIFY\"] = \"DoVerify\";\n      Name2[\"CRYPTO_DO_VERIFY_REPLY\"] = \"DoVerifyReply\";\n      Name2[\"V8_EXECUTE\"] = \"V8.Execute\";\n      Name2[\"V8_CONSOLE_RUN_TASK\"] = \"V8Console::runTask\";\n      Name2[\"SCHEDULE_POST_TASK_CALLBACK\"] = \"SchedulePostTaskCallback\";\n      Name2[\"RUN_POST_TASK_CALLBACK\"] = \"RunPostTaskCallback\";\n      Name2[\"ABORT_POST_TASK_CALLBACK\"] = \"AbortPostTaskCallback\";\n      Name2[\"DEBUGGER_ASYNC_TASK_RUN\"] = \"v8::Debugger::AsyncTaskRun\";\n      Name2[\"DEBUGGER_ASYNC_TASK_SCHEDULED\"] = \"v8::Debugger::AsyncTaskScheduled\";\n      Name2[\"GC\"] = \"GCEvent\";\n      Name2[\"DOMGC\"] = \"BlinkGC.AtomicPhase\";\n      Name2[\"MAJOR_GC\"] = \"MajorGC\";\n      Name2[\"MINOR_GC\"] = \"MinorGC\";\n      Name2[\"GC_COLLECT_GARBARGE\"] = \"BlinkGC.AtomicPhase\";\n      Name2[\"CPPGC_SWEEP\"] = \"CppGC.IncrementalSweep\";\n      Name2[\"SCHEDULE_STYLE_RECALCULATION\"] = \"ScheduleStyleRecalculation\";\n      Name2[\"LAYOUT\"] = \"Layout\";\n      Name2[\"RECALC_STYLE\"] = \"UpdateLayoutTree\";\n      Name2[\"INVALIDATE_LAYOUT\"] = \"InvalidateLayout\";\n      Name2[\"LAYOUT_INVALIDATION_TRACKING\"] = \"LayoutInvalidationTracking\";\n      Name2[\"COMPUTE_INTERSECTION\"] = \"ComputeIntersections\";\n      Name2[\"HIT_TEST\"] = \"HitTest\";\n      Name2[\"PRE_PAINT\"] = \"PrePaint\";\n      Name2[\"LAYERIZE\"] = \"Layerize\";\n      Name2[\"LAYOUT_SHIFT\"] = \"LayoutShift\";\n      Name2[\"SYNTHETIC_LAYOUT_SHIFT\"] = \"SyntheticLayoutShift\";\n      Name2[\"SYNTHETIC_LAYOUT_SHIFT_CLUSTER\"] = \"SyntheticLayoutShiftCluster\";\n      Name2[\"UPDATE_LAYER_TREE\"] = \"UpdateLayerTree\";\n      Name2[\"SCHEDULE_STYLE_INVALIDATION_TRACKING\"] = \"ScheduleStyleInvalidationTracking\";\n      Name2[\"STYLE_RECALC_INVALIDATION_TRACKING\"] = \"StyleRecalcInvalidationTracking\";\n      Name2[\"STYLE_INVALIDATOR_INVALIDATION_TRACKING\"] = \"StyleInvalidatorInvalidationTracking\";\n      Name2[\"SELECTOR_STATS\"] = \"SelectorStats\";\n      Name2[\"BEGIN_COMMIT_COMPOSITOR_FRAME\"] = \"BeginCommitCompositorFrame\";\n      Name2[\"PARSE_META_VIEWPORT\"] = \"ParseMetaViewport\";\n      Name2[\"SCROLL_LAYER\"] = \"ScrollLayer\";\n      Name2[\"UPDATE_LAYER\"] = \"UpdateLayer\";\n      Name2[\"PAINT_SETUP\"] = \"PaintSetup\";\n      Name2[\"PAINT\"] = \"Paint\";\n      Name2[\"PAINT_IMAGE\"] = \"PaintImage\";\n      Name2[\"COMMIT\"] = \"Commit\";\n      Name2[\"COMPOSITE_LAYERS\"] = \"CompositeLayers\";\n      Name2[\"RASTER_TASK\"] = \"RasterTask\";\n      Name2[\"IMAGE_DECODE_TASK\"] = \"ImageDecodeTask\";\n      Name2[\"IMAGE_UPLOAD_TASK\"] = \"ImageUploadTask\";\n      Name2[\"DECODE_IMAGE\"] = \"Decode Image\";\n      Name2[\"DRAW_LAZY_PIXEL_REF\"] = \"Draw LazyPixelRef\";\n      Name2[\"DECODE_LAZY_PIXEL_REF\"] = \"Decode LazyPixelRef\";\n      Name2[\"GPU_TASK\"] = \"GPUTask\";\n      Name2[\"RASTERIZE\"] = \"Rasterize\";\n      Name2[\"EVENT_TIMING\"] = \"EventTiming\";\n      Name2[\"OPTIMIZE_CODE\"] = \"V8.OptimizeCode\";\n      Name2[\"CACHE_SCRIPT\"] = \"v8.produceCache\";\n      Name2[\"CACHE_MODULE\"] = \"v8.produceModuleCache\";\n      Name2[\"V8_SAMPLE\"] = \"V8Sample\";\n      Name2[\"JIT_CODE_ADDED\"] = \"JitCodeAdded\";\n      Name2[\"JIT_CODE_MOVED\"] = \"JitCodeMoved\";\n      Name2[\"STREAMING_COMPILE_SCRIPT\"] = \"v8.parseOnBackground\";\n      Name2[\"STREAMING_COMPILE_SCRIPT_WAITING\"] = \"v8.parseOnBackgroundWaiting\";\n      Name2[\"STREAMING_COMPILE_SCRIPT_PARSING\"] = \"v8.parseOnBackgroundParsing\";\n      Name2[\"BACKGROUND_DESERIALIZE\"] = \"v8.deserializeOnBackground\";\n      Name2[\"FINALIZE_DESERIALIZATION\"] = \"V8.FinalizeDeserialization\";\n      Name2[\"COMMIT_LOAD\"] = \"CommitLoad\";\n      Name2[\"MARK_LOAD\"] = \"MarkLoad\";\n      Name2[\"MARK_DOM_CONTENT\"] = \"MarkDOMContent\";\n      Name2[\"MARK_FIRST_PAINT\"] = \"firstPaint\";\n      Name2[\"MARK_FCP\"] = \"firstContentfulPaint\";\n      Name2[\"MARK_LCP_CANDIDATE\"] = \"largestContentfulPaint::Candidate\";\n      Name2[\"MARK_LCP_INVALIDATE\"] = \"largestContentfulPaint::Invalidate\";\n      Name2[\"NAVIGATION_START\"] = \"navigationStart\";\n      Name2[\"CONSOLE_TIME\"] = \"ConsoleTime\";\n      Name2[\"USER_TIMING\"] = \"UserTiming\";\n      Name2[\"INTERACTIVE_TIME\"] = \"InteractiveTime\";\n      Name2[\"TIME_STAMP\"] = \"TimeStamp\";\n      Name2[\"BEGIN_FRAME\"] = \"BeginFrame\";\n      Name2[\"NEEDS_BEGIN_FRAME_CHANGED\"] = \"NeedsBeginFrameChanged\";\n      Name2[\"BEGIN_MAIN_THREAD_FRAME\"] = \"BeginMainThreadFrame\";\n      Name2[\"ACTIVATE_LAYER_TREE\"] = \"ActivateLayerTree\";\n      Name2[\"DRAW_FRAME\"] = \"DrawFrame\";\n      Name2[\"DROPPED_FRAME\"] = \"DroppedFrame\";\n      Name2[\"FRAME_STARTED_LOADING\"] = \"FrameStartedLoading\";\n      Name2[\"PIPELINE_REPORTER\"] = \"PipelineReporter\";\n      Name2[\"SCREENSHOT\"] = \"Screenshot\";\n      Name2[\"RESOURCE_WILL_SEND_REQUEST\"] = \"ResourceWillSendRequest\";\n      Name2[\"RESOURCE_SEND_REQUEST\"] = \"ResourceSendRequest\";\n      Name2[\"RESOURCE_RECEIVE_RESPONSE\"] = \"ResourceReceiveResponse\";\n      Name2[\"RESOURCE_RECEIVE_DATA\"] = \"ResourceReceivedData\";\n      Name2[\"RESOURCE_FINISH\"] = \"ResourceFinish\";\n      Name2[\"RESOURCE_MARK_AS_CACHED\"] = \"ResourceMarkAsCached\";\n      Name2[\"WEB_SOCKET_SEND_HANDSHAKE_REQUEST\"] = \"WebSocketSendHandshakeRequest\";\n      Name2[\"WEB_SOCKET_RECEIVE_HANDSHAKE_REQUEST\"] = \"WebSocketReceiveHandshakeResponse\";\n      Name2[\"CPU_PROFILE\"] = \"CpuProfile\";\n      Name2[\"PROFILE\"] = \"Profile\";\n      Name2[\"START_PROFILING\"] = \"CpuProfiler::StartProfiling\";\n      Name2[\"PROFILE_CHUNK\"] = \"ProfileChunk\";\n      Name2[\"UPDATE_COUNTERS\"] = \"UpdateCounters\";\n      Name2[\"JS_SAMPLE\"] = \"JSSample\";\n      Name2[\"ANIMATION\"] = \"Animation\";\n      Name2[\"PARSE_AUTHOR_STYLE_SHEET\"] = \"ParseAuthorStyleSheet\";\n      Name2[\"EMBEDDER_CALLBACK\"] = \"EmbedderCallback\";\n      Name2[\"SET_LAYER_TREE_ID\"] = \"SetLayerTreeId\";\n      Name2[\"TRACING_STARTED_IN_PAGE\"] = \"TracingStartedInPage\";\n      Name2[\"TRACING_STARTED_IN_BROWSER\"] = \"TracingStartedInBrowser\";\n      Name2[\"TRACING_SESSION_ID_FOR_WORKER\"] = \"TracingSessionIdForWorker\";\n      Name2[\"LAZY_PIXEL_REF\"] = \"LazyPixelRef\";\n      Name2[\"LAYER_TREE_HOST_IMPL_SNAPSHOT\"] = \"cc::LayerTreeHostImpl\";\n      Name2[\"PICTURE_SNAPSHOT\"] = \"cc::Picture\";\n      Name2[\"DISPLAY_ITEM_LIST_SNAPSHOT\"] = \"cc::DisplayItemList\";\n      Name2[\"INPUT_LATENCY_MOUSE_MOVE\"] = \"InputLatency::MouseMove\";\n      Name2[\"INPUT_LATENCY_MOUSE_WHEEL\"] = \"InputLatency::MouseWheel\";\n      Name2[\"IMPL_SIDE_FLING\"] = \"InputHandlerProxy::HandleGestureFling::started\";\n      Name2[\"SCHEDULE_POST_MESSAGE\"] = \"SchedulePostMessage\";\n      Name2[\"HANDLE_POST_MESSAGE\"] = \"HandlePostMessage\";\n      Name2[\"RENDER_FRAME_IMPL_CREATE_CHILD_FRAME\"] = \"RenderFrameImpl::createChildFrame\";\n      Name2[\"LAYOUT_IMAGE_UNSIZED\"] = \"LayoutImageUnsized\";\n      Name2[\"DOM_LOADING\"] = \"domLoading\";\n      Name2[\"BEGIN_REMOTE_FONT_LOAD\"] = \"BeginRemoteFontLoad\";\n      Name2[\"REMOTE_FONT_LOADED\"] = \"RemoteFontLoaded\";\n      Name2[\"ANIMATION_FRAME\"] = \"AnimationFrame\";\n      Name2[\"ANIMATION_FRAME_PRESENTATION\"] = \"AnimationFrame::Presentation\";\n      Name2[\"SYNTHETIC_NETWORK_REQUEST\"] = \"SyntheticNetworkRequest\";\n      Name2[\"USER_TIMING_MEASURE\"] = \"UserTiming::Measure\";\n      Name2[\"LINK_PRECONNECT\"] = \"LinkPreconnect\";\n    })(Name || (Name = {}));\n    Categories = {\n      Console: \"blink.console\",\n      UserTiming: \"blink.user_timing\",\n      Loading: \"loading\"\n    };\n    __name(isLegacyTimelineFrame, \"isLegacyTimelineFrame\");\n    __name(isRundownScriptCompiled, \"isRundownScriptCompiled\");\n    __name(isRundownScript, \"isRundownScript\");\n    __name(isRundownScriptSource, \"isRundownScriptSource\");\n    __name(isRundownScriptSourceLarge, \"isRundownScriptSourceLarge\");\n    __name(isAnyScriptSourceEvent, \"isAnyScriptSourceEvent\");\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/types/types.js\nvar init_types2 = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/types/types.js\"() {\n    init_process_global();\n    init_Configuration();\n    init_Extensions();\n    init_File();\n    init_Overlays();\n    init_Timing();\n    init_TraceEvents();\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/handlers/helpers.js\nvar helpers_exports = {};\n__export(helpers_exports, {\n  addEventToEntityMapping: () => addEventToEntityMapping,\n  addNetworkRequestToEntityMapping: () => addNetworkRequestToEntityMapping,\n  getEntityForEvent: () => getEntityForEvent,\n  getEntityForUrl: () => getEntityForUrl,\n  getNonResolvedURL: () => getNonResolvedURL,\n  makeUpEntity: () => makeUpEntity\n});\nfunction getEntityForEvent(event, entityMappings3) {\n  const url = getNonResolvedURL(event);\n  if (!url) {\n    return;\n  }\n  return getEntityForUrl(url, entityMappings3);\n}\nfunction getEntityForUrl(url, entityMappings3) {\n  const cachedByUrl = entityMappings3.entityByUrlCache.get(url);\n  if (cachedByUrl) {\n    return cachedByUrl;\n  }\n  const entity = import_third_party_web.default.getEntity(url) ?? makeUpEntity(entityMappings3.createdEntityCache, url);\n  if (entity) {\n    entityMappings3.entityByUrlCache.set(url, entity);\n  }\n  return entity;\n}\nfunction getNonResolvedURL(entry, handlerData) {\n  if (TraceEvents_exports.isProfileCall(entry)) {\n    return entry.callFrame.url;\n  }\n  if (TraceEvents_exports.isSyntheticNetworkRequest(entry)) {\n    return entry.args.data.url;\n  }\n  if (TraceEvents_exports.isParseAuthorStyleSheetEvent(entry) && entry.args) {\n    return entry.args.data.stylesheetUrl;\n  }\n  if (entry.args?.data?.stackTrace && entry.args.data.stackTrace.length > 0) {\n    return entry.args.data.stackTrace[0].url;\n  }\n  if (TraceEvents_exports.isParseHTML(entry)) {\n    return entry.args.beginData.url;\n  }\n  if (handlerData) {\n    if (TraceEvents_exports.isDecodeImage(entry)) {\n      const paintEvent = handlerData.ImagePainting.paintImageForEvent.get(entry);\n      return paintEvent ? getNonResolvedURL(paintEvent, handlerData) : null;\n    }\n    if (TraceEvents_exports.isDrawLazyPixelRef(entry) && entry.args?.LazyPixelRef) {\n      const paintEvent = handlerData.ImagePainting.paintImageByDrawLazyPixelRef.get(entry.args.LazyPixelRef);\n      return paintEvent ? getNonResolvedURL(paintEvent, handlerData) : null;\n    }\n  }\n  if (entry.args?.data?.url) {\n    return entry.args.data.url;\n  }\n  const requestId = entry.args?.data?.requestId;\n  if (handlerData && requestId) {\n    const url = handlerData.NetworkRequests.byId.get(requestId)?.args.data.url;\n    if (url) {\n      return url;\n    }\n  }\n  return null;\n}\nfunction makeUpEntity(entityCache, url) {\n  if (url.startsWith(\"chrome-extension:\")) {\n    return makeUpChromeExtensionEntity(entityCache, url);\n  }\n  if (!url.startsWith(\"http\")) {\n    return;\n  }\n  const rootDomain = import_third_party_web.default.getRootDomain(url);\n  if (!rootDomain) {\n    return;\n  }\n  if (entityCache.has(rootDomain)) {\n    return entityCache.get(rootDomain);\n  }\n  const unrecognizedEntity = {\n    name: rootDomain,\n    company: rootDomain,\n    category: \"\",\n    categories: [],\n    domains: [rootDomain],\n    averageExecutionTime: 0,\n    totalExecutionTime: 0,\n    totalOccurrences: 0,\n    isUnrecognized: true\n  };\n  entityCache.set(rootDomain, unrecognizedEntity);\n  return unrecognizedEntity;\n}\nfunction getChromeExtensionOrigin(url) {\n  return url.protocol + \"//\" + url.host;\n}\nfunction makeUpChromeExtensionEntity(entityCache, url, extensionName) {\n  const parsedUrl = new URL(url);\n  const origin = getChromeExtensionOrigin(parsedUrl);\n  const host = new URL(origin).host;\n  const name = extensionName || host;\n  const cachedEntity = entityCache.get(origin);\n  if (cachedEntity) {\n    return cachedEntity;\n  }\n  const chromeExtensionEntity = {\n    name,\n    company: name,\n    category: \"Chrome Extension\",\n    homepage: \"https://chromewebstore.google.com/detail/\" + host,\n    categories: [],\n    domains: [origin],\n    averageExecutionTime: 0,\n    totalExecutionTime: 0,\n    totalOccurrences: 0\n  };\n  entityCache.set(origin, chromeExtensionEntity);\n  return chromeExtensionEntity;\n}\nfunction addEventToEntityMapping(event, entityMappings3) {\n  if (entityMappings3.entityByEvent.has(event)) {\n    return;\n  }\n  const entity = getEntityForEvent(event, entityMappings3);\n  if (!entity) {\n    return;\n  }\n  const mappedEvents = entityMappings3.eventsByEntity.get(entity);\n  if (mappedEvents) {\n    mappedEvents.push(event);\n  } else {\n    entityMappings3.eventsByEntity.set(entity, [event]);\n  }\n  entityMappings3.entityByEvent.set(event, entity);\n}\nfunction addNetworkRequestToEntityMapping(networkRequest, entityMappings3, requestTraceEvents) {\n  const entity = getEntityForEvent(networkRequest, entityMappings3);\n  if (!entity) {\n    return;\n  }\n  const eventsToMap = [networkRequest, ...Object.values(requestTraceEvents).flat()];\n  const mappedEvents = entityMappings3.eventsByEntity.get(entity);\n  if (mappedEvents) {\n    mappedEvents.push(...eventsToMap);\n  } else {\n    entityMappings3.eventsByEntity.set(entity, eventsToMap);\n  }\n  for (const evt of eventsToMap) {\n    entityMappings3.entityByEvent.set(evt, entity);\n  }\n}\nvar init_helpers = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/handlers/helpers.js\"() {\n    init_process_global();\n    init_third_party_web();\n    init_types2();\n    __name(getEntityForEvent, \"getEntityForEvent\");\n    __name(getEntityForUrl, \"getEntityForUrl\");\n    __name(getNonResolvedURL, \"getNonResolvedURL\");\n    __name(makeUpEntity, \"makeUpEntity\");\n    __name(getChromeExtensionOrigin, \"getChromeExtensionOrigin\");\n    __name(makeUpChromeExtensionEntity, \"makeUpChromeExtensionEntity\");\n    __name(addEventToEntityMapping, \"addEventToEntityMapping\");\n    __name(addNetworkRequestToEntityMapping, \"addNetworkRequestToEntityMapping\");\n  }\n});\n\n// node_modules/@paulirish/trace_engine/core/platform/ArrayUtilities.js\nvar ArrayUtilities_exports = {};\n__export(ArrayUtilities_exports, {\n  DEFAULT_COMPARATOR: () => DEFAULT_COMPARATOR,\n  arrayDoesNotContainNullOrUndefined: () => arrayDoesNotContainNullOrUndefined,\n  binaryIndexOf: () => binaryIndexOf,\n  intersectOrdered: () => intersectOrdered,\n  lowerBound: () => lowerBound,\n  mergeOrdered: () => mergeOrdered,\n  nearestIndexFromBeginning: () => nearestIndexFromBeginning,\n  nearestIndexFromEnd: () => nearestIndexFromEnd,\n  removeElement: () => removeElement,\n  sortRange: () => sortRange,\n  upperBound: () => upperBound\n});\nfunction swap(array, i1, i2) {\n  const temp = array[i1];\n  array[i1] = array[i2];\n  array[i2] = temp;\n}\nfunction partition(array, comparator, left, right, pivotIndex) {\n  const pivotValue = array[pivotIndex];\n  swap(array, right, pivotIndex);\n  let storeIndex = left;\n  for (let i = left; i < right; ++i) {\n    if (comparator(array[i], pivotValue) < 0) {\n      swap(array, storeIndex, i);\n      ++storeIndex;\n    }\n  }\n  swap(array, right, storeIndex);\n  return storeIndex;\n}\nfunction quickSortRange(array, comparator, left, right, sortWindowLeft, sortWindowRight) {\n  if (right <= left) {\n    return;\n  }\n  const pivotIndex = Math.floor(Math.random() * (right - left)) + left;\n  const pivotNewIndex = partition(array, comparator, left, right, pivotIndex);\n  if (sortWindowLeft < pivotNewIndex) {\n    quickSortRange(array, comparator, left, pivotNewIndex - 1, sortWindowLeft, sortWindowRight);\n  }\n  if (pivotNewIndex < sortWindowRight) {\n    quickSortRange(array, comparator, pivotNewIndex + 1, right, sortWindowLeft, sortWindowRight);\n  }\n}\nfunction sortRange(array, comparator, leftBound, rightBound, sortWindowLeft, sortWindowRight) {\n  if (leftBound === 0 && rightBound === array.length - 1 && sortWindowLeft === 0 && sortWindowRight >= rightBound) {\n    array.sort(comparator);\n  } else {\n    quickSortRange(array, comparator, leftBound, rightBound, sortWindowLeft, sortWindowRight);\n  }\n  return array;\n}\nfunction mergeOrIntersect(array1, array2, comparator, mergeNotIntersect) {\n  const result = [];\n  let i = 0;\n  let j = 0;\n  while (i < array1.length && j < array2.length) {\n    const compareValue = comparator(array1[i], array2[j]);\n    if (mergeNotIntersect || !compareValue) {\n      result.push(compareValue <= 0 ? array1[i] : array2[j]);\n    }\n    if (compareValue <= 0) {\n      i++;\n    }\n    if (compareValue >= 0) {\n      j++;\n    }\n  }\n  if (mergeNotIntersect) {\n    while (i < array1.length) {\n      result.push(array1[i++]);\n    }\n    while (j < array2.length) {\n      result.push(array2[j++]);\n    }\n  }\n  return result;\n}\nfunction lowerBound(array, needle, comparator, left, right) {\n  let l = left || 0;\n  let r = right !== void 0 ? right : array.length;\n  while (l < r) {\n    const m = l + r >> 1;\n    if (comparator(needle, array[m]) > 0) {\n      l = m + 1;\n    } else {\n      r = m;\n    }\n  }\n  return r;\n}\nfunction upperBound(array, needle, comparator, left, right) {\n  let l = left || 0;\n  let r = right !== void 0 ? right : array.length;\n  while (l < r) {\n    const m = l + r >> 1;\n    if (comparator(needle, array[m]) >= 0) {\n      l = m + 1;\n    } else {\n      r = m;\n    }\n  }\n  return r;\n}\nfunction nearestIndex(arr, predicate, searchStart) {\n  const searchFromEnd = searchStart === \"END\";\n  if (arr.length === 0) {\n    return null;\n  }\n  let left = 0;\n  let right = arr.length - 1;\n  let pivot = 0;\n  let matchesPredicate = false;\n  let moveToTheRight = false;\n  let middle = 0;\n  do {\n    middle = left + (right - left) / 2;\n    pivot = searchFromEnd ? Math.ceil(middle) : Math.floor(middle);\n    matchesPredicate = predicate(arr[pivot]);\n    moveToTheRight = matchesPredicate === searchFromEnd;\n    if (moveToTheRight) {\n      left = Math.min(right, pivot + (left === pivot ? 1 : 0));\n    } else {\n      right = Math.max(left, pivot + (right === pivot ? -1 : 0));\n    }\n  } while (right !== left);\n  if (!predicate(arr[left])) {\n    return null;\n  }\n  return left;\n}\nfunction nearestIndexFromBeginning(arr, predicate) {\n  return nearestIndex(\n    arr,\n    predicate,\n    \"BEGINNING\"\n    /* NearestSearchStart.BEGINNING */\n  );\n}\nfunction nearestIndexFromEnd(arr, predicate) {\n  return nearestIndex(\n    arr,\n    predicate,\n    \"END\"\n    /* NearestSearchStart.END */\n  );\n}\nfunction arrayDoesNotContainNullOrUndefined(arr) {\n  return !arr.includes(null) && !arr.includes(void 0);\n}\nvar removeElement, binaryIndexOf, intersectOrdered, mergeOrdered, DEFAULT_COMPARATOR;\nvar init_ArrayUtilities = __esm({\n  \"node_modules/@paulirish/trace_engine/core/platform/ArrayUtilities.js\"() {\n    init_process_global();\n    removeElement = /* @__PURE__ */ __name((array, element, firstOnly) => {\n      let index = array.indexOf(element);\n      if (index === -1) {\n        return false;\n      }\n      if (firstOnly) {\n        array.splice(index, 1);\n        return true;\n      }\n      for (let i = index + 1, n = array.length; i < n; ++i) {\n        if (array[i] !== element) {\n          array[index++] = array[i];\n        }\n      }\n      array.length = index;\n      return true;\n    }, \"removeElement\");\n    __name(swap, \"swap\");\n    __name(partition, \"partition\");\n    __name(quickSortRange, \"quickSortRange\");\n    __name(sortRange, \"sortRange\");\n    binaryIndexOf = /* @__PURE__ */ __name((array, value, comparator) => {\n      const index = lowerBound(array, value, comparator);\n      return index < array.length && comparator(value, array[index]) === 0 ? index : -1;\n    }, \"binaryIndexOf\");\n    __name(mergeOrIntersect, \"mergeOrIntersect\");\n    intersectOrdered = /* @__PURE__ */ __name((array1, array2, comparator) => {\n      return mergeOrIntersect(array1, array2, comparator, false);\n    }, \"intersectOrdered\");\n    mergeOrdered = /* @__PURE__ */ __name((array1, array2, comparator) => {\n      return mergeOrIntersect(array1, array2, comparator, true);\n    }, \"mergeOrdered\");\n    DEFAULT_COMPARATOR = /* @__PURE__ */ __name((a, b) => {\n      return a < b ? -1 : a > b ? 1 : 0;\n    }, \"DEFAULT_COMPARATOR\");\n    __name(lowerBound, \"lowerBound\");\n    __name(upperBound, \"upperBound\");\n    __name(nearestIndex, \"nearestIndex\");\n    __name(nearestIndexFromBeginning, \"nearestIndexFromBeginning\");\n    __name(nearestIndexFromEnd, \"nearestIndexFromEnd\");\n    __name(arrayDoesNotContainNullOrUndefined, \"arrayDoesNotContainNullOrUndefined\");\n  }\n});\n\n// node_modules/@paulirish/trace_engine/core/platform/Brand.js\nvar init_Brand = __esm({\n  \"node_modules/@paulirish/trace_engine/core/platform/Brand.js\"() {\n    init_process_global();\n  }\n});\n\n// node_modules/@paulirish/trace_engine/core/platform/Constructor.js\nvar init_Constructor = __esm({\n  \"node_modules/@paulirish/trace_engine/core/platform/Constructor.js\"() {\n    init_process_global();\n  }\n});\n\n// node_modules/@paulirish/trace_engine/core/platform/DateUtilities.js\nvar init_DateUtilities = __esm({\n  \"node_modules/@paulirish/trace_engine/core/platform/DateUtilities.js\"() {\n    init_process_global();\n  }\n});\n\n// node_modules/@paulirish/trace_engine/core/platform/DevToolsPath.js\nvar init_DevToolsPath = __esm({\n  \"node_modules/@paulirish/trace_engine/core/platform/DevToolsPath.js\"() {\n    init_process_global();\n  }\n});\n\n// node_modules/@paulirish/trace_engine/core/platform/DOMUtilities.js\nvar init_DOMUtilities = __esm({\n  \"node_modules/@paulirish/trace_engine/core/platform/DOMUtilities.js\"() {\n    init_process_global();\n  }\n});\n\n// node_modules/@paulirish/trace_engine/core/platform/KeyboardUtilities.js\nvar init_KeyboardUtilities = __esm({\n  \"node_modules/@paulirish/trace_engine/core/platform/KeyboardUtilities.js\"() {\n    init_process_global();\n  }\n});\n\n// node_modules/@paulirish/trace_engine/core/platform/MapUtilities.js\nvar MapUtilities_exports = {};\n__export(MapUtilities_exports, {\n  Multimap: () => Multimap,\n  getWithDefault: () => getWithDefault,\n  inverse: () => inverse\n});\nfunction getWithDefault(map, key, defaultValueFactory) {\n  let value = map.get(key);\n  if (value === void 0 || value === null) {\n    value = defaultValueFactory(key);\n    map.set(key, value);\n  }\n  return value;\n}\nvar inverse, Multimap;\nvar init_MapUtilities = __esm({\n  \"node_modules/@paulirish/trace_engine/core/platform/MapUtilities.js\"() {\n    init_process_global();\n    inverse = /* @__PURE__ */ __name(function(map) {\n      const result = new Multimap();\n      for (const [key, value] of map.entries()) {\n        result.set(value, key);\n      }\n      return result;\n    }, \"inverse\");\n    Multimap = class {\n      static {\n        __name(this, \"Multimap\");\n      }\n      map = /* @__PURE__ */ new Map();\n      set(key, value) {\n        let set = this.map.get(key);\n        if (!set) {\n          set = /* @__PURE__ */ new Set();\n          this.map.set(key, set);\n        }\n        set.add(value);\n      }\n      get(key) {\n        return this.map.get(key) || /* @__PURE__ */ new Set();\n      }\n      has(key) {\n        return this.map.has(key);\n      }\n      hasValue(key, value) {\n        const set = this.map.get(key);\n        if (!set) {\n          return false;\n        }\n        return set.has(value);\n      }\n      get size() {\n        return this.map.size;\n      }\n      delete(key, value) {\n        const values = this.get(key);\n        if (!values) {\n          return false;\n        }\n        const result = values.delete(value);\n        if (!values.size) {\n          this.map.delete(key);\n        }\n        return result;\n      }\n      deleteAll(key) {\n        this.map.delete(key);\n      }\n      keysArray() {\n        return [...this.map.keys()];\n      }\n      keys() {\n        return this.map.keys();\n      }\n      valuesArray() {\n        const result = [];\n        for (const set of this.map.values()) {\n          result.push(...set.values());\n        }\n        return result;\n      }\n      clear() {\n        this.map.clear();\n      }\n    };\n    __name(getWithDefault, \"getWithDefault\");\n  }\n});\n\n// node_modules/@paulirish/trace_engine/core/platform/MimeType.js\nvar init_MimeType = __esm({\n  \"node_modules/@paulirish/trace_engine/core/platform/MimeType.js\"() {\n    init_process_global();\n  }\n});\n\n// node_modules/@paulirish/trace_engine/core/platform/NumberUtilities.js\nvar NumberUtilities_exports = {};\n__export(NumberUtilities_exports, {\n  aspectRatio: () => aspectRatio,\n  clamp: () => clamp,\n  floor: () => floor,\n  greatestCommonDivisor: () => greatestCommonDivisor,\n  mod: () => mod,\n  toFixedIfFloating: () => toFixedIfFloating,\n  withThousandsSeparator: () => withThousandsSeparator\n});\nvar clamp, mod, toFixedIfFloating, floor, greatestCommonDivisor, commonRatios, aspectRatio, withThousandsSeparator;\nvar init_NumberUtilities = __esm({\n  \"node_modules/@paulirish/trace_engine/core/platform/NumberUtilities.js\"() {\n    init_process_global();\n    clamp = /* @__PURE__ */ __name((num, min, max) => {\n      let clampedNumber = num;\n      if (num < min) {\n        clampedNumber = min;\n      } else if (num > max) {\n        clampedNumber = max;\n      }\n      return clampedNumber;\n    }, \"clamp\");\n    mod = /* @__PURE__ */ __name((m, n) => {\n      return (m % n + n) % n;\n    }, \"mod\");\n    toFixedIfFloating = /* @__PURE__ */ __name((value) => {\n      if (!value || Number.isNaN(Number(value))) {\n        return value;\n      }\n      const number = Number(value);\n      return number % 1 ? number.toFixed(3) : String(number);\n    }, \"toFixedIfFloating\");\n    floor = /* @__PURE__ */ __name((value, precision = 0) => {\n      if (precision > 0 && precision < 1) {\n        precision = 1 / precision;\n        return Math.floor(value / precision) * precision;\n      }\n      const mult = Math.pow(10, precision);\n      return Math.floor(value * mult) / mult;\n    }, \"floor\");\n    greatestCommonDivisor = /* @__PURE__ */ __name((a, b) => {\n      a = Math.round(a);\n      b = Math.round(b);\n      while (b !== 0) {\n        const t = b;\n        b = a % b;\n        a = t;\n      }\n      return a;\n    }, \"greatestCommonDivisor\");\n    commonRatios = /* @__PURE__ */ new Map([\n      [\"8∶5\", \"16∶10\"]\n    ]);\n    aspectRatio = /* @__PURE__ */ __name((width, height) => {\n      const divisor = greatestCommonDivisor(width, height);\n      if (divisor !== 0) {\n        width /= divisor;\n        height /= divisor;\n      }\n      const result = `${width}∶${height}`;\n      return commonRatios.get(result) || result;\n    }, \"aspectRatio\");\n    withThousandsSeparator = /* @__PURE__ */ __name(function(num) {\n      let str = String(num);\n      const re = /(\\d+)(\\d{3})/;\n      while (str.match(re)) {\n        str = str.replace(re, \"$1 $2\");\n      }\n      return str;\n    }, \"withThousandsSeparator\");\n  }\n});\n\n// node_modules/@paulirish/trace_engine/core/platform/StringUtilities.js\nvar init_StringUtilities = __esm({\n  \"node_modules/@paulirish/trace_engine/core/platform/StringUtilities.js\"() {\n    init_process_global();\n  }\n});\n\n// node_modules/@paulirish/trace_engine/core/platform/Timing.js\nvar init_Timing2 = __esm({\n  \"node_modules/@paulirish/trace_engine/core/platform/Timing.js\"() {\n    init_process_global();\n  }\n});\n\n// node_modules/@paulirish/trace_engine/core/platform/TypedArrayUtilities.js\nvar init_TypedArrayUtilities = __esm({\n  \"node_modules/@paulirish/trace_engine/core/platform/TypedArrayUtilities.js\"() {\n    init_process_global();\n  }\n});\n\n// node_modules/@paulirish/trace_engine/core/platform/TypescriptUtilities.js\nvar TypescriptUtilities_exports = {};\n__export(TypescriptUtilities_exports, {\n  assertNever: () => assertNever,\n  assertNotNullOrUndefined: () => assertNotNullOrUndefined,\n  assertUnhandled: () => assertUnhandled\n});\nfunction assertNotNullOrUndefined(val, message) {\n  if (val === null || val === void 0) {\n    throw new Error(`Expected given value to not be null/undefined but it was: ${val}${message ? `\n${message}` : \"\"}`);\n  }\n}\nfunction assertNever(_type, message) {\n  throw new Error(message);\n}\nfunction assertUnhandled(_caseVariable) {\n  return _caseVariable;\n}\nvar init_TypescriptUtilities = __esm({\n  \"node_modules/@paulirish/trace_engine/core/platform/TypescriptUtilities.js\"() {\n    init_process_global();\n    __name(assertNotNullOrUndefined, \"assertNotNullOrUndefined\");\n    __name(assertNever, \"assertNever\");\n    __name(assertUnhandled, \"assertUnhandled\");\n  }\n});\n\n// node_modules/@paulirish/trace_engine/core/platform/UIString.js\nvar init_UIString = __esm({\n  \"node_modules/@paulirish/trace_engine/core/platform/UIString.js\"() {\n    init_process_global();\n  }\n});\n\n// node_modules/@paulirish/trace_engine/core/platform/UserVisibleError.js\nvar init_UserVisibleError = __esm({\n  \"node_modules/@paulirish/trace_engine/core/platform/UserVisibleError.js\"() {\n    init_process_global();\n  }\n});\n\n// node_modules/@paulirish/trace_engine/core/platform/platform.js\nvar init_platform = __esm({\n  \"node_modules/@paulirish/trace_engine/core/platform/platform.js\"() {\n    init_process_global();\n    init_ArrayUtilities();\n    init_Brand();\n    init_Constructor();\n    init_DateUtilities();\n    init_DevToolsPath();\n    init_DOMUtilities();\n    init_KeyboardUtilities();\n    init_MapUtilities();\n    init_MimeType();\n    init_NumberUtilities();\n    init_StringUtilities();\n    init_Timing2();\n    init_TypedArrayUtilities();\n    init_TypescriptUtilities();\n    init_UIString();\n    init_UserVisibleError();\n    init_TypescriptUtilities();\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/helpers/SyntheticEvents.js\nvar SyntheticEvents_exports = {};\n__export(SyntheticEvents_exports, {\n  SyntheticEventsManager: () => SyntheticEventsManager\n});\nvar activeManager, SyntheticEventsManager;\nvar init_SyntheticEvents = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/helpers/SyntheticEvents.js\"() {\n    init_process_global();\n    activeManager = null;\n    SyntheticEventsManager = class _SyntheticEventsManager {\n      static {\n        __name(this, \"SyntheticEventsManager\");\n      }\n      /**\n       * All synthetic entries created in a trace from a corresponding trace events.\n       * (ProfileCalls are excluded because they are not based on a real trace event)\n       */\n      #syntheticTraces = [];\n      /**\n       * All raw entries from a trace.\n       */\n      #rawTraceEvents = [];\n      static activate(manager) {\n        activeManager = manager;\n      }\n      static createAndActivate(rawEvents) {\n        const manager = new _SyntheticEventsManager(rawEvents);\n        _SyntheticEventsManager.activate(manager);\n        return manager;\n      }\n      static getActiveManager() {\n        if (!activeManager) {\n          throw new Error(\"Attempted to get a SyntheticEventsManager without initializing\");\n        }\n        return activeManager;\n      }\n      static reset() {\n        activeManager = null;\n      }\n      static registerSyntheticEvent(syntheticEvent) {\n        try {\n          return _SyntheticEventsManager.getActiveManager().#registerSyntheticEvent(syntheticEvent);\n        } catch {\n          return syntheticEvent;\n        }\n      }\n      constructor(rawEvents) {\n        this.#rawTraceEvents = rawEvents;\n      }\n      /**\n       * Registers and returns a branded synthetic event. Synthetic events need to\n       * be created with this method to ensure they are registered and made\n       * available to load events using serialized keys.\n       */\n      #registerSyntheticEvent(syntheticEvent) {\n        const rawIndex = this.#rawTraceEvents.indexOf(syntheticEvent.rawSourceEvent);\n        if (rawIndex < 0) {\n          throw new Error(\"Attempted to register a synthetic event paired to an unknown raw event.\");\n        }\n        const eventAsSynthetic = syntheticEvent;\n        this.#syntheticTraces[rawIndex] = eventAsSynthetic;\n        return eventAsSynthetic;\n      }\n      syntheticEventForRawEventIndex(rawEventIndex) {\n        const syntheticEvent = this.#syntheticTraces.at(rawEventIndex);\n        if (!syntheticEvent) {\n          throw new Error(`Attempted to get a synthetic event from an unknown raw event index: ${rawEventIndex}`);\n        }\n        return syntheticEvent;\n      }\n      getSyntheticTraces() {\n        return this.#syntheticTraces;\n      }\n      getRawTraceEvents() {\n        return this.#rawTraceEvents;\n      }\n    };\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/helpers/Timing.js\nvar Timing_exports3 = {};\n__export(Timing_exports3, {\n  boundsIncludeTimeRange: () => boundsIncludeTimeRange,\n  combineTraceWindowsMicro: () => combineTraceWindowsMicro,\n  eventIsInBounds: () => eventIsInBounds,\n  eventTimingsMicroSeconds: () => eventTimingsMicroSeconds,\n  eventTimingsMilliSeconds: () => eventTimingsMilliSeconds,\n  expandWindowByPercentOrToOneMillisecond: () => expandWindowByPercentOrToOneMillisecond,\n  microToMilli: () => microToMilli,\n  microToSeconds: () => microToSeconds,\n  milliToMicro: () => milliToMicro,\n  secondsToMicro: () => secondsToMicro,\n  secondsToMilli: () => secondsToMilli,\n  timeStampForEventAdjustedByClosestNavigation: () => timeStampForEventAdjustedByClosestNavigation,\n  timestampIsInBounds: () => timestampIsInBounds,\n  traceWindowFromEvent: () => traceWindowFromEvent,\n  traceWindowFromMicroSeconds: () => traceWindowFromMicroSeconds,\n  traceWindowFromMilliSeconds: () => traceWindowFromMilliSeconds,\n  traceWindowFromOverlay: () => traceWindowFromOverlay,\n  traceWindowMicroSecondsToMilliSeconds: () => traceWindowMicroSecondsToMilliSeconds,\n  traceWindowMilliSeconds: () => traceWindowMilliSeconds,\n  windowFitsInsideBounds: () => windowFitsInsideBounds,\n  windowsEqual: () => windowsEqual\n});\nfunction timeStampForEventAdjustedByClosestNavigation(event, traceBounds2, navigationsByNavigationId2, navigationsByFrameId2) {\n  let eventTimeStamp = event.ts - traceBounds2.min;\n  if (event.args?.data?.navigationId) {\n    const navigationForEvent = navigationsByNavigationId2.get(event.args.data.navigationId);\n    if (navigationForEvent) {\n      eventTimeStamp = event.ts - navigationForEvent.ts;\n    }\n  } else if (event.args?.data?.frame) {\n    const navigationForEvent = getNavigationForTraceEvent(event, event.args.data.frame, navigationsByFrameId2);\n    if (navigationForEvent) {\n      eventTimeStamp = event.ts - navigationForEvent.ts;\n    }\n  }\n  return Timing_exports.Micro(eventTimeStamp);\n}\nfunction expandWindowByPercentOrToOneMillisecond(annotationWindow, maxTraceWindow, percentage) {\n  let newMin = annotationWindow.min - annotationWindow.range * (percentage / 100) / 2;\n  let newMax = annotationWindow.max + annotationWindow.range * (percentage / 100) / 2;\n  if (newMax - newMin < 1e3) {\n    const rangeMiddle = (annotationWindow.min + annotationWindow.max) / 2;\n    newMin = rangeMiddle - 500;\n    newMax = rangeMiddle + 500;\n  }\n  newMin = Math.max(newMin, maxTraceWindow.min);\n  newMax = Math.min(newMax, maxTraceWindow.max);\n  const expandedWindow = {\n    min: Timing_exports.Micro(newMin),\n    max: Timing_exports.Micro(newMax),\n    range: Timing_exports.Micro(newMax - newMin)\n  };\n  return expandedWindow;\n}\nfunction eventTimingsMicroSeconds(event) {\n  return {\n    startTime: event.ts,\n    endTime: event.ts + (event.dur ?? 0),\n    duration: event.dur || 0\n  };\n}\nfunction eventTimingsMilliSeconds(event) {\n  return {\n    startTime: event.ts / 1e3,\n    endTime: (event.ts + (event.dur ?? 0)) / 1e3,\n    duration: (event.dur || 0) / 1e3\n  };\n}\nfunction traceWindowMilliSeconds(bounds) {\n  return {\n    min: microToMilli(bounds.min),\n    max: microToMilli(bounds.max),\n    range: microToMilli(bounds.range)\n  };\n}\nfunction traceWindowMicroSecondsToMilliSeconds(bounds) {\n  return {\n    min: microToMilli(bounds.min),\n    max: microToMilli(bounds.max),\n    range: microToMilli(bounds.range)\n  };\n}\nfunction traceWindowFromMilliSeconds(min, max) {\n  const traceWindow = {\n    min: milliToMicro(min),\n    max: milliToMicro(max),\n    range: Timing_exports.Micro(milliToMicro(max) - milliToMicro(min))\n  };\n  return traceWindow;\n}\nfunction traceWindowFromMicroSeconds(min, max) {\n  const traceWindow = {\n    min,\n    max,\n    range: max - min\n  };\n  return traceWindow;\n}\nfunction traceWindowFromEvent(event) {\n  return {\n    min: event.ts,\n    max: event.ts + (event.dur ?? 0),\n    range: event.dur ?? 0\n  };\n}\nfunction traceWindowFromOverlay(overlay) {\n  switch (overlay.type) {\n    case \"ENTRY_LABEL\":\n    case \"ENTRY_OUTLINE\":\n    case \"ENTRY_SELECTED\": {\n      return traceWindowFromEvent(overlay.entry);\n    }\n    case \"TIMESPAN_BREAKDOWN\": {\n      const windows = overlay.sections.map((s) => s.bounds);\n      if (overlay.entry) {\n        windows.push(traceWindowFromEvent(overlay.entry));\n      }\n      return combineTraceWindowsMicro(windows);\n    }\n    case \"CANDY_STRIPED_TIME_RANGE\":\n    case \"TIME_RANGE\": {\n      return structuredClone(overlay.bounds);\n    }\n    case \"ENTRIES_LINK\": {\n      const from = traceWindowFromEvent(overlay.entryFrom);\n      if (!overlay.entryTo) {\n        return from;\n      }\n      const to = traceWindowFromEvent(overlay.entryTo);\n      return combineTraceWindowsMicro([from, to]);\n    }\n    case \"TIMESTAMP_MARKER\":\n      return traceWindowFromMicroSeconds(overlay.timestamp, overlay.timestamp);\n    case \"TIMINGS_MARKER\":\n      return traceWindowFromMicroSeconds(overlay.adjustedTimestamp, overlay.adjustedTimestamp);\n    case \"BOTTOM_INFO_BAR\":\n      return null;\n    default:\n      TypescriptUtilities_exports.assertNever(overlay, `Unexpected overlay ${overlay}`);\n  }\n}\nfunction combineTraceWindowsMicro(windows) {\n  if (!windows.length) {\n    return null;\n  }\n  const result = structuredClone(windows[0]);\n  for (const bounds of windows.slice(1)) {\n    result.min = Math.min(result.min, bounds.min);\n    result.max = Math.max(result.max, bounds.max);\n  }\n  result.range = result.max - result.min;\n  return result;\n}\nfunction boundsIncludeTimeRange(data31) {\n  const { min: visibleMin, max: visibleMax } = data31.bounds;\n  const { min: rangeMin, max: rangeMax } = data31.timeRange;\n  return visibleMin <= rangeMax && visibleMax >= rangeMin;\n}\nfunction eventIsInBounds(event, bounds) {\n  const startTime = event.ts;\n  return startTime <= bounds.max && bounds.min < startTime + (event.dur ?? 0);\n}\nfunction timestampIsInBounds(bounds, timestamp) {\n  return timestamp >= bounds.min && timestamp <= bounds.max;\n}\nfunction windowFitsInsideBounds(data31) {\n  return data31.window.min >= data31.bounds.min && data31.window.max <= data31.bounds.max;\n}\nfunction windowsEqual(w1, w2) {\n  return w1.min === w2.min && w1.max === w2.max;\n}\nvar milliToMicro, secondsToMilli, secondsToMicro, microToMilli, microToSeconds;\nvar init_Timing3 = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/helpers/Timing.js\"() {\n    init_process_global();\n    init_platform();\n    init_types2();\n    init_Trace();\n    milliToMicro = /* @__PURE__ */ __name((value) => Timing_exports.Micro(value * 1e3), \"milliToMicro\");\n    secondsToMilli = /* @__PURE__ */ __name((value) => Timing_exports.Milli(value * 1e3), \"secondsToMilli\");\n    secondsToMicro = /* @__PURE__ */ __name((value) => milliToMicro(secondsToMilli(value)), \"secondsToMicro\");\n    microToMilli = /* @__PURE__ */ __name((value) => Timing_exports.Milli(value / 1e3), \"microToMilli\");\n    microToSeconds = /* @__PURE__ */ __name((value) => Timing_exports.Seconds(value / 1e3 / 1e3), \"microToSeconds\");\n    __name(timeStampForEventAdjustedByClosestNavigation, \"timeStampForEventAdjustedByClosestNavigation\");\n    __name(expandWindowByPercentOrToOneMillisecond, \"expandWindowByPercentOrToOneMillisecond\");\n    __name(eventTimingsMicroSeconds, \"eventTimingsMicroSeconds\");\n    __name(eventTimingsMilliSeconds, \"eventTimingsMilliSeconds\");\n    __name(traceWindowMilliSeconds, \"traceWindowMilliSeconds\");\n    __name(traceWindowMicroSecondsToMilliSeconds, \"traceWindowMicroSecondsToMilliSeconds\");\n    __name(traceWindowFromMilliSeconds, \"traceWindowFromMilliSeconds\");\n    __name(traceWindowFromMicroSeconds, \"traceWindowFromMicroSeconds\");\n    __name(traceWindowFromEvent, \"traceWindowFromEvent\");\n    __name(traceWindowFromOverlay, \"traceWindowFromOverlay\");\n    __name(combineTraceWindowsMicro, \"combineTraceWindowsMicro\");\n    __name(boundsIncludeTimeRange, \"boundsIncludeTimeRange\");\n    __name(eventIsInBounds, \"eventIsInBounds\");\n    __name(timestampIsInBounds, \"timestampIsInBounds\");\n    __name(windowFitsInsideBounds, \"windowFitsInsideBounds\");\n    __name(windowsEqual, \"windowsEqual\");\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/helpers/Trace.js\nvar Trace_exports = {};\n__export(Trace_exports, {\n  VISIBLE_TRACE_EVENT_TYPES: () => VISIBLE_TRACE_EVENT_TYPES,\n  activeURLForFrameAtTime: () => activeURLForFrameAtTime,\n  addEventToProcessThread: () => addEventToProcessThread,\n  compareBeginAndEnd: () => compareBeginAndEnd,\n  createMatchedSortedSyntheticEvents: () => createMatchedSortedSyntheticEvents,\n  eventContainsTimestamp: () => eventContainsTimestamp,\n  eventHasCategory: () => eventHasCategory,\n  eventTimeComparator: () => eventTimeComparator,\n  extractId: () => extractId,\n  extractOriginFromTrace: () => extractOriginFromTrace,\n  extractSampleTraceId: () => extractSampleTraceId,\n  findNextEventAfterTimestamp: () => findNextEventAfterTimestamp,\n  findPreviousEventBeforeTimestamp: () => findPreviousEventBeforeTimestamp,\n  findRecalcStyleEvents: () => findRecalcStyleEvents,\n  forEachEvent: () => forEachEvent,\n  frameIDForEvent: () => frameIDForEvent,\n  getNavigationForTraceEvent: () => getNavigationForTraceEvent,\n  getStackTraceTopCallFrameInEventPayload: () => getStackTraceTopCallFrameInEventPayload,\n  getSyntheticId: () => getSyntheticId,\n  getZeroIndexedLineAndColumnForEvent: () => getZeroIndexedLineAndColumnForEvent,\n  getZeroIndexedStackTraceInEventPayload: () => getZeroIndexedStackTraceInEventPayload,\n  isExtensionUrl: () => isExtensionUrl,\n  isMatchingCallFrame: () => isMatchingCallFrame,\n  isTopLevelEvent: () => isTopLevelEvent,\n  makeProfileCall: () => makeProfileCall,\n  makeZeroBasedCallFrame: () => makeZeroBasedCallFrame,\n  mergeEventsInOrder: () => mergeEventsInOrder,\n  parseDevtoolsDetails: () => parseDevtoolsDetails,\n  sortTraceEventsInPlace: () => sortTraceEventsInPlace,\n  stackTraceInEvent: () => stackTraceInEvent\n});\nfunction stackTraceInEvent(event) {\n  if (event.args?.data?.stackTrace) {\n    return event.args.data.stackTrace;\n  }\n  if (event.args?.stackTrace) {\n    return event.args.stackTrace;\n  }\n  if (TraceEvents_exports.isRecalcStyle(event)) {\n    return event.args.beginData?.stackTrace || null;\n  }\n  if (TraceEvents_exports.isLayout(event)) {\n    return event.args.beginData.stackTrace ?? null;\n  }\n  if (TraceEvents_exports.isFunctionCall(event)) {\n    const data31 = event.args.data;\n    if (!data31) {\n      return null;\n    }\n    const { columnNumber, lineNumber, url, scriptId, functionName } = data31;\n    if (lineNumber === void 0 || functionName === void 0 || columnNumber === void 0 || scriptId === void 0 || url === void 0) {\n      return null;\n    }\n    return [{ columnNumber, lineNumber, url, scriptId, functionName }];\n  }\n  if (TraceEvents_exports.isProfileCall(event)) {\n    const callFrame = event.callFrame;\n    if (!callFrame) {\n      return null;\n    }\n    const { columnNumber, lineNumber, url, scriptId, functionName } = callFrame;\n    if (lineNumber === void 0 || functionName === void 0 || columnNumber === void 0 || scriptId === void 0 || url === void 0) {\n      return null;\n    }\n    return [{ columnNumber, lineNumber, url, scriptId, functionName }];\n  }\n  return null;\n}\nfunction extractOriginFromTrace(firstNavigationURL) {\n  const url = new URL(firstNavigationURL);\n  if (url) {\n    if (url.host.startsWith(\"www.\")) {\n      return url.host.slice(4);\n    }\n    return url.host;\n  }\n  return null;\n}\nfunction addEventToProcessThread(event, eventsInProcessThread2) {\n  const { tid, pid } = event;\n  let eventsInThread = eventsInProcessThread2.get(pid);\n  if (!eventsInThread) {\n    eventsInThread = /* @__PURE__ */ new Map();\n  }\n  let events = eventsInThread.get(tid);\n  if (!events) {\n    events = [];\n  }\n  events.push(event);\n  eventsInThread.set(event.tid, events);\n  eventsInProcessThread2.set(event.pid, eventsInThread);\n}\nfunction compareBeginAndEnd(aBeginTime, bBeginTime, aEndTime, bEndTime) {\n  if (aBeginTime < bBeginTime) {\n    return -1;\n  }\n  if (aBeginTime > bBeginTime) {\n    return 1;\n  }\n  if (aEndTime > bEndTime) {\n    return -1;\n  }\n  if (aEndTime < bEndTime) {\n    return 1;\n  }\n  return 0;\n}\nfunction eventTimeComparator(a, b) {\n  const aBeginTime = a.ts;\n  const bBeginTime = b.ts;\n  const aDuration = a.dur ?? 0;\n  const bDuration = b.dur ?? 0;\n  const aEndTime = aBeginTime + aDuration;\n  const bEndTime = bBeginTime + bDuration;\n  const timeDifference = compareBeginAndEnd(aBeginTime, bBeginTime, aEndTime, bEndTime);\n  if (timeDifference) {\n    return timeDifference;\n  }\n  if (TraceEvents_exports.isProfileCall(a) && !TraceEvents_exports.isProfileCall(b)) {\n    return -1;\n  }\n  if (TraceEvents_exports.isProfileCall(b) && !TraceEvents_exports.isProfileCall(a)) {\n    return 1;\n  }\n  return 0;\n}\nfunction sortTraceEventsInPlace(events) {\n  events.sort(eventTimeComparator);\n}\nfunction mergeEventsInOrder(eventsArray1, eventsArray2) {\n  const result = [];\n  let i = 0;\n  let j = 0;\n  while (i < eventsArray1.length && j < eventsArray2.length) {\n    const event1 = eventsArray1[i];\n    const event2 = eventsArray2[j];\n    const compareValue = eventTimeComparator(event1, event2);\n    if (compareValue <= 0) {\n      result.push(event1);\n      i++;\n    }\n    if (compareValue === 1) {\n      result.push(event2);\n      j++;\n    }\n  }\n  while (i < eventsArray1.length) {\n    result.push(eventsArray1[i++]);\n  }\n  while (j < eventsArray2.length) {\n    result.push(eventsArray2[j++]);\n  }\n  return result;\n}\nfunction parseDevtoolsDetails(timingDetail, key) {\n  try {\n    const detailObj = JSON.parse(timingDetail);\n    if (!(key in detailObj)) {\n      return null;\n    }\n    if (!Extensions_exports.isValidExtensionPayload(detailObj[key])) {\n      return null;\n    }\n    return detailObj[key];\n  } catch {\n    return null;\n  }\n}\nfunction getNavigationForTraceEvent(event, eventFrameId, navigationsByFrameId2) {\n  const navigations = navigationsByFrameId2.get(eventFrameId);\n  if (!navigations || eventFrameId === \"\") {\n    return null;\n  }\n  const eventNavigationIndex = ArrayUtilities_exports.nearestIndexFromEnd(navigations, (navigation2) => navigation2.ts <= event.ts);\n  if (eventNavigationIndex === null) {\n    return null;\n  }\n  return navigations[eventNavigationIndex];\n}\nfunction extractId(event) {\n  return event.id ?? event.id2?.global ?? event.id2?.local;\n}\nfunction activeURLForFrameAtTime(frameId, time, rendererProcessesByFrame) {\n  const processData = rendererProcessesByFrame.get(frameId);\n  if (!processData) {\n    return null;\n  }\n  for (const processes2 of processData.values()) {\n    for (const processInfo of processes2) {\n      if (processInfo.window.min > time || processInfo.window.max < time) {\n        continue;\n      }\n      return processInfo.frame.url;\n    }\n  }\n  return null;\n}\nfunction makeProfileCall(node, profileId, sampleIndex, ts, pid, tid) {\n  return {\n    cat: \"\",\n    name: \"ProfileCall\",\n    nodeId: node.id,\n    args: {},\n    ph: TraceEvents_exports.Phase.COMPLETE,\n    pid,\n    tid,\n    ts,\n    dur: Timing_exports.Micro(0),\n    callFrame: node.callFrame,\n    sampleIndex,\n    profileId\n  };\n}\nfunction matchEvents(unpairedEvents) {\n  sortTraceEventsInPlace(unpairedEvents);\n  const matches = [];\n  const beginEventsById = /* @__PURE__ */ new Map();\n  const instantEventsById = /* @__PURE__ */ new Map();\n  for (const event of unpairedEvents) {\n    const id = getSyntheticId(event);\n    if (id === void 0) {\n      continue;\n    }\n    if (TraceEvents_exports.isPairableAsyncBegin(event)) {\n      const existingEvents = beginEventsById.get(id) ?? [];\n      existingEvents.push(event);\n      beginEventsById.set(id, existingEvents);\n    } else if (TraceEvents_exports.isPairableAsyncInstant(event)) {\n      const existingEvents = instantEventsById.get(id) ?? [];\n      existingEvents.push(event);\n      instantEventsById.set(id, existingEvents);\n    } else if (TraceEvents_exports.isPairableAsyncEnd(event)) {\n      const beginEventsWithMatchingId = beginEventsById.get(id) ?? [];\n      const beginEvent = beginEventsWithMatchingId.pop();\n      if (!beginEvent) {\n        continue;\n      }\n      const instantEventsWithMatchingId = instantEventsById.get(id) ?? [];\n      const instantEventsForThisGroup = [];\n      while (instantEventsWithMatchingId.length > 0) {\n        if (instantEventsWithMatchingId[0].ts >= beginEvent.ts) {\n          const event2 = instantEventsWithMatchingId.pop();\n          if (event2) {\n            instantEventsForThisGroup.push(event2);\n          }\n        } else {\n          break;\n        }\n      }\n      const matchingGroup = {\n        begin: beginEvent,\n        end: event,\n        instant: instantEventsForThisGroup,\n        syntheticId: id\n      };\n      matches.push(matchingGroup);\n    }\n  }\n  for (const [id, beginEvents] of beginEventsById) {\n    const beginEvent = beginEvents.pop();\n    if (!beginEvent) {\n      continue;\n    }\n    const matchingInstantEvents = instantEventsById.get(id);\n    if (matchingInstantEvents?.length) {\n      matches.push({\n        syntheticId: id,\n        begin: beginEvent,\n        end: null,\n        instant: matchingInstantEvents\n      });\n    }\n  }\n  return matches;\n}\nfunction getSyntheticId(event) {\n  const id = extractId(event);\n  return id && `${event.cat}:${id}:${event.name}`;\n}\nfunction createSortedSyntheticEvents(matchedPairs) {\n  const syntheticEvents2 = [];\n  for (const eventsTriplet of matchedPairs) {\n    let eventsArePairable = function(data31) {\n      const instantEventsMatch = data31.instantEvents ? data31.instantEvents.some((e) => id === getSyntheticId(e)) : false;\n      const endEventMatch = data31.endEvent ? id === getSyntheticId(data31.endEvent) : false;\n      return Boolean(id) && (instantEventsMatch || endEventMatch);\n    };\n    __name(eventsArePairable, \"eventsArePairable\");\n    const id = eventsTriplet.syntheticId;\n    const beginEvent = eventsTriplet.begin;\n    const endEvent = eventsTriplet.end;\n    const instantEvents = eventsTriplet.instant;\n    if (!beginEvent || !(endEvent || instantEvents)) {\n      continue;\n    }\n    const triplet = { beginEvent, endEvent, instantEvents };\n    if (!eventsArePairable(triplet)) {\n      continue;\n    }\n    const targetEvent = endEvent || beginEvent;\n    const event = SyntheticEventsManager.registerSyntheticEvent({\n      rawSourceEvent: triplet.beginEvent,\n      cat: targetEvent.cat,\n      ph: targetEvent.ph,\n      pid: targetEvent.pid,\n      tid: targetEvent.tid,\n      id,\n      // Both events have the same name, so it doesn't matter which we pick to\n      // use as the description\n      name: beginEvent.name,\n      dur: Timing_exports.Micro(targetEvent.ts - beginEvent.ts),\n      ts: beginEvent.ts,\n      args: {\n        data: triplet\n      }\n    });\n    if (event.dur < 0) {\n      continue;\n    }\n    syntheticEvents2.push(event);\n  }\n  sortTraceEventsInPlace(syntheticEvents2);\n  return syntheticEvents2;\n}\nfunction createMatchedSortedSyntheticEvents(unpairedAsyncEvents2) {\n  const matchedPairs = matchEvents(unpairedAsyncEvents2);\n  const syntheticEvents2 = createSortedSyntheticEvents(matchedPairs);\n  return syntheticEvents2;\n}\nfunction getZeroIndexedLineAndColumnForEvent(event) {\n  const numbers = getRawLineAndColumnNumbersForEvent(event);\n  const { lineNumber, columnNumber } = numbers;\n  switch (event.name) {\n    // All these events have line/column numbers which are 1 indexed; so we\n    // subtract to make them 0 indexed.\n    case TraceEvents_exports.Name.FUNCTION_CALL:\n    case TraceEvents_exports.Name.EVALUATE_SCRIPT:\n    case TraceEvents_exports.Name.COMPILE:\n    case TraceEvents_exports.Name.CACHE_SCRIPT: {\n      return {\n        lineNumber: typeof lineNumber === \"number\" ? lineNumber - 1 : void 0,\n        columnNumber: typeof columnNumber === \"number\" ? columnNumber - 1 : void 0\n      };\n    }\n    case TraceEvents_exports.Name.PROFILE_CALL: {\n      const callFrame = event.callFrame;\n      return {\n        lineNumber: typeof lineNumber === \"number\" ? callFrame.lineNumber - 1 : void 0,\n        columnNumber: typeof columnNumber === \"number\" ? callFrame.columnNumber - 1 : void 0\n      };\n    }\n    default: {\n      return numbers;\n    }\n  }\n}\nfunction getZeroIndexedStackTraceInEventPayload(event) {\n  const stack = stackTraceInEvent(event);\n  if (!stack) {\n    return null;\n  }\n  switch (event.name) {\n    case TraceEvents_exports.Name.SCHEDULE_STYLE_RECALCULATION:\n    case TraceEvents_exports.Name.INVALIDATE_LAYOUT:\n    case TraceEvents_exports.Name.FUNCTION_CALL:\n    case TraceEvents_exports.Name.LAYOUT:\n    case TraceEvents_exports.Name.RECALC_STYLE: {\n      return stack.map(makeZeroBasedCallFrame);\n    }\n    default: {\n      if (TraceEvents_exports.isUserTiming(event) || Extensions_exports.isSyntheticExtensionEntry(event)) {\n        return stack.map(makeZeroBasedCallFrame);\n      }\n      return stack;\n    }\n  }\n}\nfunction getStackTraceTopCallFrameInEventPayload(event) {\n  const stack = stackTraceInEvent(event);\n  if (!stack || stack.length === 0) {\n    return null;\n  }\n  switch (event.name) {\n    case TraceEvents_exports.Name.SCHEDULE_STYLE_RECALCULATION:\n    case TraceEvents_exports.Name.INVALIDATE_LAYOUT:\n    case TraceEvents_exports.Name.FUNCTION_CALL:\n    case TraceEvents_exports.Name.LAYOUT:\n    case TraceEvents_exports.Name.RECALC_STYLE: {\n      return makeZeroBasedCallFrame(stack[0]);\n    }\n    default: {\n      if (TraceEvents_exports.isUserTiming(event) || Extensions_exports.isSyntheticExtensionEntry(event)) {\n        return makeZeroBasedCallFrame(stack[0]);\n      }\n      return stack[0];\n    }\n  }\n}\nfunction makeZeroBasedCallFrame(callFrame) {\n  const normalizedCallFrame = { ...callFrame };\n  normalizedCallFrame.lineNumber = callFrame.lineNumber && callFrame.lineNumber - 1;\n  normalizedCallFrame.columnNumber = callFrame.columnNumber && callFrame.columnNumber - 1;\n  return normalizedCallFrame;\n}\nfunction getRawLineAndColumnNumbersForEvent(event) {\n  if (!event.args?.data) {\n    return {\n      lineNumber: void 0,\n      columnNumber: void 0\n    };\n  }\n  let lineNumber = void 0;\n  let columnNumber = void 0;\n  if (\"lineNumber\" in event.args.data && typeof event.args.data.lineNumber === \"number\") {\n    lineNumber = event.args.data.lineNumber;\n  }\n  if (\"columnNumber\" in event.args.data && typeof event.args.data.columnNumber === \"number\") {\n    columnNumber = event.args.data.columnNumber;\n  }\n  return { lineNumber, columnNumber };\n}\nfunction frameIDForEvent(event) {\n  if (event.args && \"beginData\" in event.args && typeof event.args.beginData === \"object\" && event.args.beginData !== null && \"frame\" in event.args.beginData && typeof event.args.beginData.frame === \"string\") {\n    return event.args.beginData.frame;\n  }\n  if (event.args?.data?.frame) {\n    return event.args.data.frame;\n  }\n  return null;\n}\nfunction isTopLevelEvent(event) {\n  return event.cat.includes(DevToolsTimelineEventCategory) && event.name === TraceEvents_exports.Name.RUN_TASK;\n}\nfunction isExtensionUrl(url) {\n  return url.startsWith(\"extensions:\") || url.startsWith(\"chrome-extension:\");\n}\nfunction topLevelEventIndexEndingAfter(events, time) {\n  let index = ArrayUtilities_exports.upperBound(events, time, (time2, event) => time2 - event.ts) - 1;\n  while (index > 0 && !isTopLevelEvent(events[index])) {\n    index--;\n  }\n  return Math.max(index, 0);\n}\nfunction findRecalcStyleEvents(events, startTime, endTime) {\n  const foundEvents = [];\n  const startEventIndex = topLevelEventIndexEndingAfter(events, startTime);\n  for (let i = startEventIndex; i < events.length; i++) {\n    const event = events[i];\n    if (!TraceEvents_exports.isRecalcStyle(event)) {\n      continue;\n    }\n    if (event.ts >= (endTime || Infinity)) {\n      continue;\n    }\n    foundEvents.push(event);\n  }\n  return foundEvents;\n}\nfunction findNextEventAfterTimestamp(candidates, ts) {\n  const index = ArrayUtilities_exports.nearestIndexFromBeginning(candidates, (candidate) => ts < candidate.ts);\n  return index === null ? null : candidates[index];\n}\nfunction findPreviousEventBeforeTimestamp(candidates, ts) {\n  const index = ArrayUtilities_exports.nearestIndexFromEnd(candidates, (candidate) => candidate.ts < ts);\n  return index === null ? null : candidates[index];\n}\nfunction forEachEvent(events, config3) {\n  const globalStartTime = config3.startTime ?? Timing_exports.Micro(0);\n  const globalEndTime = config3.endTime || Timing_exports.Micro(Infinity);\n  const ignoreAsyncEvents = config3.ignoreAsyncEvents === false ? false : true;\n  const stack = [];\n  const startEventIndex = topLevelEventIndexEndingAfter(events, globalStartTime);\n  for (let i = startEventIndex; i < events.length; i++) {\n    const currentEvent = events[i];\n    const currentEventTimings = eventTimingsMicroSeconds(currentEvent);\n    if (currentEventTimings.endTime < globalStartTime) {\n      continue;\n    }\n    if (currentEventTimings.startTime > globalEndTime) {\n      break;\n    }\n    const isIgnoredAsyncEvent = ignoreAsyncEvents && TraceEvents_exports.isPhaseAsync(currentEvent.ph);\n    if (isIgnoredAsyncEvent || TraceEvents_exports.isFlowPhase(currentEvent.ph)) {\n      continue;\n    }\n    let lastEventOnStack = stack.at(-1);\n    let lastEventEndTime = lastEventOnStack ? eventTimingsMicroSeconds(lastEventOnStack).endTime : null;\n    while (lastEventOnStack && lastEventEndTime && lastEventEndTime <= currentEventTimings.startTime) {\n      stack.pop();\n      config3.onEndEvent(lastEventOnStack);\n      lastEventOnStack = stack.at(-1);\n      lastEventEndTime = lastEventOnStack ? eventTimingsMicroSeconds(lastEventOnStack).endTime : null;\n    }\n    if (config3.eventFilter && !config3.eventFilter(currentEvent)) {\n      continue;\n    }\n    if (currentEventTimings.duration) {\n      config3.onStartEvent(currentEvent);\n      stack.push(currentEvent);\n    } else if (config3.onInstantEvent) {\n      config3.onInstantEvent(currentEvent);\n    }\n  }\n  while (stack.length) {\n    const last = stack.pop();\n    if (last) {\n      config3.onEndEvent(last);\n    }\n  }\n}\nfunction eventHasCategory(event, category) {\n  let parsedCategoriesForEvent = parsedCategories.get(event.cat);\n  if (!parsedCategoriesForEvent) {\n    parsedCategoriesForEvent = new Set(event.cat.split(\",\") || []);\n  }\n  return parsedCategoriesForEvent.has(category);\n}\nfunction isMatchingCallFrame(eventFrame, nodeFrame) {\n  return eventFrame.columnNumber === nodeFrame.columnNumber && eventFrame.lineNumber === nodeFrame.lineNumber && String(eventFrame.scriptId) === nodeFrame.scriptId && eventFrame.url === nodeFrame.url && eventFrame.functionName === nodeFrame.functionName;\n}\nfunction eventContainsTimestamp(event, ts) {\n  return event.ts <= ts && event.ts + (event.dur || 0) >= ts;\n}\nfunction extractSampleTraceId(event) {\n  if (!event.args) {\n    return null;\n  }\n  if (\"beginData\" in event.args) {\n    const beginData = event.args[\"beginData\"];\n    return beginData.sampleTraceId ?? null;\n  }\n  return event.args?.sampleTraceId ?? event.args?.data?.sampleTraceId ?? null;\n}\nvar DevToolsTimelineEventCategory, parsedCategories, VISIBLE_TRACE_EVENT_TYPES;\nvar init_Trace = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/helpers/Trace.js\"() {\n    init_process_global();\n    init_platform();\n    init_types2();\n    init_SyntheticEvents();\n    init_Timing3();\n    __name(stackTraceInEvent, \"stackTraceInEvent\");\n    __name(extractOriginFromTrace, \"extractOriginFromTrace\");\n    __name(addEventToProcessThread, \"addEventToProcessThread\");\n    __name(compareBeginAndEnd, \"compareBeginAndEnd\");\n    __name(eventTimeComparator, \"eventTimeComparator\");\n    __name(sortTraceEventsInPlace, \"sortTraceEventsInPlace\");\n    __name(mergeEventsInOrder, \"mergeEventsInOrder\");\n    __name(parseDevtoolsDetails, \"parseDevtoolsDetails\");\n    __name(getNavigationForTraceEvent, \"getNavigationForTraceEvent\");\n    __name(extractId, \"extractId\");\n    __name(activeURLForFrameAtTime, \"activeURLForFrameAtTime\");\n    __name(makeProfileCall, \"makeProfileCall\");\n    __name(matchEvents, \"matchEvents\");\n    __name(getSyntheticId, \"getSyntheticId\");\n    __name(createSortedSyntheticEvents, \"createSortedSyntheticEvents\");\n    __name(createMatchedSortedSyntheticEvents, \"createMatchedSortedSyntheticEvents\");\n    __name(getZeroIndexedLineAndColumnForEvent, \"getZeroIndexedLineAndColumnForEvent\");\n    __name(getZeroIndexedStackTraceInEventPayload, \"getZeroIndexedStackTraceInEventPayload\");\n    __name(getStackTraceTopCallFrameInEventPayload, \"getStackTraceTopCallFrameInEventPayload\");\n    __name(makeZeroBasedCallFrame, \"makeZeroBasedCallFrame\");\n    __name(getRawLineAndColumnNumbersForEvent, \"getRawLineAndColumnNumbersForEvent\");\n    __name(frameIDForEvent, \"frameIDForEvent\");\n    DevToolsTimelineEventCategory = \"disabled-by-default-devtools.timeline\";\n    __name(isTopLevelEvent, \"isTopLevelEvent\");\n    __name(isExtensionUrl, \"isExtensionUrl\");\n    __name(topLevelEventIndexEndingAfter, \"topLevelEventIndexEndingAfter\");\n    __name(findRecalcStyleEvents, \"findRecalcStyleEvents\");\n    __name(findNextEventAfterTimestamp, \"findNextEventAfterTimestamp\");\n    __name(findPreviousEventBeforeTimestamp, \"findPreviousEventBeforeTimestamp\");\n    __name(forEachEvent, \"forEachEvent\");\n    parsedCategories = /* @__PURE__ */ new Map();\n    __name(eventHasCategory, \"eventHasCategory\");\n    __name(isMatchingCallFrame, \"isMatchingCallFrame\");\n    __name(eventContainsTimestamp, \"eventContainsTimestamp\");\n    __name(extractSampleTraceId, \"extractSampleTraceId\");\n    VISIBLE_TRACE_EVENT_TYPES = /* @__PURE__ */ new Set([\n      TraceEvents_exports.Name.ABORT_POST_TASK_CALLBACK,\n      TraceEvents_exports.Name.ANIMATION,\n      TraceEvents_exports.Name.ASYNC_TASK,\n      TraceEvents_exports.Name.BACKGROUND_DESERIALIZE,\n      TraceEvents_exports.Name.CACHE_MODULE,\n      TraceEvents_exports.Name.CACHE_SCRIPT,\n      TraceEvents_exports.Name.CANCEL_ANIMATION_FRAME,\n      TraceEvents_exports.Name.CANCEL_IDLE_CALLBACK,\n      TraceEvents_exports.Name.COMMIT,\n      TraceEvents_exports.Name.COMPILE_CODE,\n      TraceEvents_exports.Name.COMPILE_MODULE,\n      TraceEvents_exports.Name.COMPILE,\n      TraceEvents_exports.Name.COMPOSITE_LAYERS,\n      TraceEvents_exports.Name.COMPUTE_INTERSECTION,\n      TraceEvents_exports.Name.CONSOLE_TIME,\n      TraceEvents_exports.Name.CPPGC_SWEEP,\n      TraceEvents_exports.Name.CRYPTO_DO_DECRYPT_REPLY,\n      TraceEvents_exports.Name.CRYPTO_DO_DECRYPT,\n      TraceEvents_exports.Name.CRYPTO_DO_DIGEST_REPLY,\n      TraceEvents_exports.Name.CRYPTO_DO_DIGEST,\n      TraceEvents_exports.Name.CRYPTO_DO_ENCRYPT_REPLY,\n      TraceEvents_exports.Name.CRYPTO_DO_ENCRYPT,\n      TraceEvents_exports.Name.CRYPTO_DO_SIGN_REPLY,\n      TraceEvents_exports.Name.CRYPTO_DO_SIGN,\n      TraceEvents_exports.Name.CRYPTO_DO_VERIFY_REPLY,\n      TraceEvents_exports.Name.CRYPTO_DO_VERIFY,\n      TraceEvents_exports.Name.DECODE_IMAGE,\n      TraceEvents_exports.Name.EMBEDDER_CALLBACK,\n      TraceEvents_exports.Name.EVALUATE_MODULE,\n      TraceEvents_exports.Name.EVALUATE_SCRIPT,\n      TraceEvents_exports.Name.EVENT_DISPATCH,\n      TraceEvents_exports.Name.EVENT_TIMING,\n      TraceEvents_exports.Name.FINALIZE_DESERIALIZATION,\n      TraceEvents_exports.Name.FIRE_ANIMATION_FRAME,\n      TraceEvents_exports.Name.FIRE_IDLE_CALLBACK,\n      TraceEvents_exports.Name.FUNCTION_CALL,\n      TraceEvents_exports.Name.GC_COLLECT_GARBARGE,\n      TraceEvents_exports.Name.GC,\n      TraceEvents_exports.Name.GPU_TASK,\n      TraceEvents_exports.Name.HANDLE_POST_MESSAGE,\n      TraceEvents_exports.Name.HIT_TEST,\n      TraceEvents_exports.Name.JS_SAMPLE,\n      TraceEvents_exports.Name.LAYERIZE,\n      TraceEvents_exports.Name.LAYOUT,\n      TraceEvents_exports.Name.MAJOR_GC,\n      TraceEvents_exports.Name.MINOR_GC,\n      TraceEvents_exports.Name.OPTIMIZE_CODE,\n      TraceEvents_exports.Name.PAINT_SETUP,\n      TraceEvents_exports.Name.PAINT,\n      TraceEvents_exports.Name.PARSE_AUTHOR_STYLE_SHEET,\n      TraceEvents_exports.Name.PARSE_HTML,\n      TraceEvents_exports.Name.PRE_PAINT,\n      TraceEvents_exports.Name.PROFILE_CALL,\n      TraceEvents_exports.Name.PROGRAM,\n      TraceEvents_exports.Name.RASTER_TASK,\n      TraceEvents_exports.Name.REQUEST_ANIMATION_FRAME,\n      TraceEvents_exports.Name.REQUEST_IDLE_CALLBACK,\n      TraceEvents_exports.Name.RESOURCE_FINISH,\n      TraceEvents_exports.Name.RESOURCE_RECEIVE_DATA,\n      TraceEvents_exports.Name.RESOURCE_RECEIVE_RESPONSE,\n      TraceEvents_exports.Name.RESOURCE_SEND_REQUEST,\n      TraceEvents_exports.Name.RESOURCE_WILL_SEND_REQUEST,\n      TraceEvents_exports.Name.RUN_MICROTASKS,\n      TraceEvents_exports.Name.RUN_POST_TASK_CALLBACK,\n      TraceEvents_exports.Name.RUN_TASK,\n      TraceEvents_exports.Name.SCHEDULE_POST_MESSAGE,\n      TraceEvents_exports.Name.SCHEDULE_POST_TASK_CALLBACK,\n      TraceEvents_exports.Name.SCHEDULE_STYLE_RECALCULATION,\n      TraceEvents_exports.Name.SCROLL_LAYER,\n      TraceEvents_exports.Name.START_PROFILING,\n      TraceEvents_exports.Name.STREAMING_COMPILE_SCRIPT_PARSING,\n      TraceEvents_exports.Name.STREAMING_COMPILE_SCRIPT_WAITING,\n      TraceEvents_exports.Name.STREAMING_COMPILE_SCRIPT,\n      TraceEvents_exports.Name.SYNTHETIC_LAYOUT_SHIFT_CLUSTER,\n      TraceEvents_exports.Name.SYNTHETIC_LAYOUT_SHIFT,\n      TraceEvents_exports.Name.TIME_STAMP,\n      TraceEvents_exports.Name.TIMER_FIRE,\n      TraceEvents_exports.Name.TIMER_INSTALL,\n      TraceEvents_exports.Name.TIMER_REMOVE,\n      TraceEvents_exports.Name.UPDATE_LAYER_TREE,\n      TraceEvents_exports.Name.RECALC_STYLE,\n      TraceEvents_exports.Name.USER_TIMING,\n      TraceEvents_exports.Name.V8_CONSOLE_RUN_TASK,\n      TraceEvents_exports.Name.WASM_CACHED_MODULE,\n      TraceEvents_exports.Name.WASM_COMPILED_MODULE,\n      TraceEvents_exports.Name.WASM_MODULE_CACHE_HIT,\n      TraceEvents_exports.Name.WASM_MODULE_CACHE_INVALID,\n      TraceEvents_exports.Name.WASM_STREAM_FROM_RESPONSE_CALLBACK,\n      TraceEvents_exports.Name.WEB_SOCKET_CREATE,\n      TraceEvents_exports.Name.WEB_SOCKET_DESTROY,\n      TraceEvents_exports.Name.WEB_SOCKET_RECEIVE_HANDSHAKE_REQUEST,\n      TraceEvents_exports.Name.WEB_SOCKET_RECEIVE,\n      TraceEvents_exports.Name.WEB_SOCKET_SEND_HANDSHAKE_REQUEST,\n      TraceEvents_exports.Name.WEB_SOCKET_SEND,\n      TraceEvents_exports.Name.XHR_LOAD,\n      TraceEvents_exports.Name.XHR_READY_STATE_CHANGED\n    ]);\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/helpers/TreeHelpers.js\nvar TreeHelpers_exports = {};\n__export(TreeHelpers_exports, {\n  canBuildTreesFromEvents: () => canBuildTreesFromEvents,\n  makeEmptyTraceEntryNode: () => makeEmptyTraceEntryNode,\n  makeEmptyTraceEntryTree: () => makeEmptyTraceEntryTree,\n  makeTraceEntryNodeId: () => makeTraceEntryNodeId,\n  treify: () => treify,\n  walkEntireTree: () => walkEntireTree,\n  walkTreeFromEntry: () => walkTreeFromEntry\n});\nfunction treify(entries, options) {\n  const entryToNode4 = /* @__PURE__ */ new Map();\n  const stack = [];\n  nodeIdCount = -1;\n  const tree = makeEmptyTraceEntryTree();\n  for (let i = 0; i < entries.length; i++) {\n    const event = entries[i];\n    if (options && !options.filter.has(event.name)) {\n      continue;\n    }\n    const duration = event.dur || 0;\n    const nodeId = makeTraceEntryNodeId();\n    const node = makeEmptyTraceEntryNode(event, nodeId);\n    if (stack.length === 0) {\n      tree.roots.add(node);\n      node.selfTime = Timing_exports.Micro(duration);\n      stack.push(node);\n      tree.maxDepth = Math.max(tree.maxDepth, stack.length);\n      entryToNode4.set(event, node);\n      continue;\n    }\n    const parentNode = stack.at(-1);\n    if (parentNode === void 0) {\n      throw new Error(\"Impossible: no parent node found in the stack\");\n    }\n    const parentEvent = parentNode.entry;\n    const begin = event.ts;\n    const parentBegin = parentEvent.ts;\n    const parentDuration = parentEvent.dur || 0;\n    const end = begin + duration;\n    const parentEnd = parentBegin + parentDuration;\n    const startsBeforeParent = begin < parentBegin;\n    if (startsBeforeParent) {\n      throw new Error(\"Impossible: current event starts before the parent event\");\n    }\n    const startsAfterParent = begin >= parentEnd;\n    if (startsAfterParent) {\n      stack.pop();\n      i--;\n      nodeIdCount--;\n      continue;\n    }\n    const endsAfterParent = end > parentEnd;\n    if (endsAfterParent) {\n      continue;\n    }\n    node.depth = stack.length;\n    node.parent = parentNode;\n    parentNode.children.push(node);\n    node.selfTime = Timing_exports.Micro(duration);\n    if (parentNode.selfTime !== void 0) {\n      parentNode.selfTime = Timing_exports.Micro(parentNode.selfTime - (event.dur || 0));\n    }\n    stack.push(node);\n    tree.maxDepth = Math.max(tree.maxDepth, stack.length);\n    entryToNode4.set(event, node);\n  }\n  return { tree, entryToNode: entryToNode4 };\n}\nfunction walkTreeFromEntry(entryToNode4, rootEntry, onEntryStart, onEntryEnd) {\n  const startNode = entryToNode4.get(rootEntry);\n  if (!startNode) {\n    return;\n  }\n  walkTreeByNode(entryToNode4, startNode, onEntryStart, onEntryEnd);\n}\nfunction walkEntireTree(entryToNode4, tree, onEntryStart, onEntryEnd, traceWindowToInclude, minDuration) {\n  for (const rootNode of tree.roots) {\n    walkTreeByNode(entryToNode4, rootNode, onEntryStart, onEntryEnd, traceWindowToInclude, minDuration);\n  }\n}\nfunction walkTreeByNode(entryToNode4, rootNode, onEntryStart, onEntryEnd, traceWindowToInclude, minDuration) {\n  if (traceWindowToInclude && !treeNodeIsInWindow(rootNode, traceWindowToInclude)) {\n    return;\n  }\n  if (typeof minDuration !== \"undefined\") {\n    const duration = Timing_exports.Micro(rootNode.entry.ts + Timing_exports.Micro(rootNode.entry.dur ?? 0));\n    if (duration < minDuration) {\n      return;\n    }\n  }\n  onEntryStart(rootNode.entry);\n  for (const child of rootNode.children) {\n    walkTreeByNode(entryToNode4, child, onEntryStart, onEntryEnd, traceWindowToInclude, minDuration);\n  }\n  onEntryEnd(rootNode.entry);\n}\nfunction treeNodeIsInWindow(node, traceWindow) {\n  return eventIsInBounds(node.entry, traceWindow);\n}\nfunction canBuildTreesFromEvents(events) {\n  const stack = [];\n  for (const event of events) {\n    const startTime = event.ts;\n    const endTime = event.ts + (event.dur ?? 0);\n    let parent = stack.at(-1);\n    if (parent === void 0) {\n      stack.push(event);\n      continue;\n    }\n    let parentEndTime = parent.ts + (parent.dur ?? 0);\n    while (stack.length && startTime >= parentEndTime) {\n      stack.pop();\n      parent = stack.at(-1);\n      if (parent === void 0) {\n        break;\n      }\n      parentEndTime = parent.ts + (parent.dur ?? 0);\n    }\n    if (stack.length && endTime > parentEndTime) {\n      return false;\n    }\n    stack.push(event);\n  }\n  return true;\n}\nvar nodeIdCount, makeTraceEntryNodeId, makeEmptyTraceEntryTree, makeEmptyTraceEntryNode;\nvar init_TreeHelpers = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/helpers/TreeHelpers.js\"() {\n    init_process_global();\n    init_types2();\n    init_Timing3();\n    nodeIdCount = 0;\n    makeTraceEntryNodeId = /* @__PURE__ */ __name(() => ++nodeIdCount, \"makeTraceEntryNodeId\");\n    makeEmptyTraceEntryTree = /* @__PURE__ */ __name(() => ({\n      roots: /* @__PURE__ */ new Set(),\n      maxDepth: 0\n    }), \"makeEmptyTraceEntryTree\");\n    makeEmptyTraceEntryNode = /* @__PURE__ */ __name((entry, id) => ({\n      entry,\n      id,\n      parent: null,\n      children: [],\n      depth: 0\n    }), \"makeEmptyTraceEntryNode\");\n    __name(treify, \"treify\");\n    __name(walkTreeFromEntry, \"walkTreeFromEntry\");\n    __name(walkEntireTree, \"walkEntireTree\");\n    __name(walkTreeByNode, \"walkTreeByNode\");\n    __name(treeNodeIsInWindow, \"treeNodeIsInWindow\");\n    __name(canBuildTreesFromEvents, \"canBuildTreesFromEvents\");\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/helpers/Extensions.js\nvar Extensions_exports2 = {};\n__export(Extensions_exports2, {\n  buildTrackDataFromExtensionEntries: () => buildTrackDataFromExtensionEntries\n});\nfunction buildTrackDataFromExtensionEntries(extensionEntries, extensionTrackData2, entryToNode4) {\n  const dataByTrack = /* @__PURE__ */ new Map();\n  for (const entry of extensionEntries) {\n    const key = entry.devtoolsObj.trackGroup || `track-name-${entry.devtoolsObj.track}`;\n    const batchedData = MapUtilities_exports.getWithDefault(dataByTrack, key, () => ({\n      name: entry.devtoolsObj.trackGroup || entry.devtoolsObj.track,\n      isTrackGroup: Boolean(entry.devtoolsObj.trackGroup),\n      entriesByTrack: { [entry.devtoolsObj.track]: [] }\n    }));\n    if (!batchedData.entriesByTrack[entry.devtoolsObj.track]) {\n      batchedData.entriesByTrack[entry.devtoolsObj.track] = [];\n    }\n    const entriesInTrack = batchedData.entriesByTrack[entry.devtoolsObj.track];\n    entriesInTrack.push(entry);\n  }\n  for (const trackData of dataByTrack.values()) {\n    for (const entries of Object.values(trackData.entriesByTrack)) {\n      sortTraceEventsInPlace(entries);\n      if (canBuildTreesFromEvents(entries)) {\n        for (const [entry, node] of treify(entries).entryToNode) {\n          entryToNode4.set(entry, node);\n        }\n      }\n    }\n    extensionTrackData2.push(trackData);\n  }\n  return { extensionTrackData: extensionTrackData2, entryToNode: entryToNode4 };\n}\nvar init_Extensions2 = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/helpers/Extensions.js\"() {\n    init_process_global();\n    init_platform();\n    init_Trace();\n    init_TreeHelpers();\n    __name(buildTrackDataFromExtensionEntries, \"buildTrackDataFromExtensionEntries\");\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/helpers/Network.js\nvar Network_exports = {};\n__export(Network_exports, {\n  CACHEABLE_STATUS_CODES: () => CACHEABLE_STATUS_CODES,\n  NON_NETWORK_SCHEMES: () => NON_NETWORK_SCHEMES2,\n  STATIC_RESOURCE_TYPES: () => STATIC_RESOURCE_TYPES,\n  isSyntheticNetworkRequestEventRenderBlocking: () => isSyntheticNetworkRequestEventRenderBlocking,\n  isSyntheticNetworkRequestHighPriority: () => isSyntheticNetworkRequestHighPriority,\n  isSyntheticNetworkRequestLocalhost: () => isSyntheticNetworkRequestLocalhost,\n  parseCacheControl: () => parseCacheControl\n});\nfunction isSyntheticNetworkRequestEventRenderBlocking(event) {\n  return !NON_RENDER_BLOCKING_VALUES.has(event.args.data.renderBlocking);\n}\nfunction isSyntheticNetworkRequestHighPriority(event) {\n  return HIGH_NETWORK_PRIORITIES.has(event.args.data.priority);\n}\nfunction parseCacheControl(header) {\n  if (!header) {\n    return null;\n  }\n  const directives = header.split(\",\").map((directive) => directive.trim());\n  const cacheControlOptions = {};\n  for (const directive of directives) {\n    const [key, value] = directive.split(\"=\").map((part) => part.trim());\n    switch (key) {\n      case \"max-age\": {\n        const maxAge = parseInt(value, 10);\n        if (!isNaN(maxAge)) {\n          cacheControlOptions[\"max-age\"] = maxAge;\n        }\n        break;\n      }\n      case \"no-cache\":\n        cacheControlOptions[\"no-cache\"] = true;\n        break;\n      case \"no-store\":\n        cacheControlOptions[\"no-store\"] = true;\n        break;\n      case \"must-revalidate\":\n        cacheControlOptions[\"must-revalidate\"] = true;\n        break;\n      case \"private\":\n        cacheControlOptions[\"private\"] = true;\n        break;\n      default:\n        break;\n    }\n  }\n  return cacheControlOptions;\n}\nfunction isSyntheticNetworkRequestLocalhost(event) {\n  try {\n    const hostname = new URL(event.args.data.url).hostname;\n    return SECURE_LOCALHOST_DOMAINS.includes(hostname) || hostname.endsWith(\".localhost\");\n  } catch {\n    return false;\n  }\n}\nvar NON_RENDER_BLOCKING_VALUES, HIGH_NETWORK_PRIORITIES, CACHEABLE_STATUS_CODES, STATIC_RESOURCE_TYPES, NON_NETWORK_SCHEMES2, SECURE_LOCALHOST_DOMAINS;\nvar init_Network = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/helpers/Network.js\"() {\n    init_process_global();\n    NON_RENDER_BLOCKING_VALUES = /* @__PURE__ */ new Set([\n      \"non_blocking\",\n      \"dynamically_injected_non_blocking\",\n      \"potentially_blocking\"\n    ]);\n    __name(isSyntheticNetworkRequestEventRenderBlocking, \"isSyntheticNetworkRequestEventRenderBlocking\");\n    HIGH_NETWORK_PRIORITIES = /* @__PURE__ */ new Set([\n      \"VeryHigh\",\n      \"High\",\n      \"Medium\"\n    ]);\n    __name(isSyntheticNetworkRequestHighPriority, \"isSyntheticNetworkRequestHighPriority\");\n    CACHEABLE_STATUS_CODES = /* @__PURE__ */ new Set([200, 203, 206]);\n    STATIC_RESOURCE_TYPES = /* @__PURE__ */ new Set([\n      \"Font\",\n      \"Image\",\n      \"Media\",\n      \"Script\",\n      \"Stylesheet\"\n    ]);\n    NON_NETWORK_SCHEMES2 = [\n      \"blob\",\n      // @see https://developer.mozilla.org/en-US/docs/Web/API/URL/createObjectURL\n      \"data\",\n      // @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs\n      \"intent\",\n      // @see https://developer.chrome.com/docs/multidevice/android/intents/\n      \"file\",\n      // @see https://en.wikipedia.org/wiki/File_URI_scheme\n      \"filesystem\",\n      // @see https://developer.mozilla.org/en-US/docs/Web/API/FileSystem\n      \"chrome-extension\"\n    ];\n    __name(parseCacheControl, \"parseCacheControl\");\n    SECURE_LOCALHOST_DOMAINS = [\"localhost\", \"127.0.0.1\"];\n    __name(isSyntheticNetworkRequestLocalhost, \"isSyntheticNetworkRequestLocalhost\");\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/helpers/SamplesIntegrator.js\nvar SamplesIntegrator_exports = {};\n__export(SamplesIntegrator_exports, {\n  SamplesIntegrator: () => SamplesIntegrator\n});\nvar _a, SamplesIntegrator;\nvar init_SamplesIntegrator = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/helpers/SamplesIntegrator.js\"() {\n    init_process_global();\n    init_types2();\n    init_Timing3();\n    init_Trace();\n    SamplesIntegrator = class {\n      static {\n        __name(this, \"SamplesIntegrator\");\n      }\n      /**\n       * The result of running the samples integrator. Holds the JS calls\n       * with their approximated duration after integrating samples into the\n       * trace event tree.\n       */\n      #constructedProfileCalls = [];\n      /**\n       * tracks the state of the JS stack at each point in time to update\n       * the profile call durations as new events arrive. This doesn't only\n       * happen with new profile calls (in which case we would compare the\n       * stack in them) but also with trace events (in which case we would\n       * update the duration of the events we are tracking at the moment).\n       */\n      #currentJSStack = [];\n      /**\n       * Process holding the CPU profile and trace events.\n       */\n      #processId;\n      /**\n       * Thread holding the CPU profile and trace events.\n       */\n      #threadId;\n      /**\n       * Tracks the depth of the JS stack at the moment a trace event starts\n       * or ends. It is assumed that for the duration of a trace event, the\n       * JS stack's depth cannot decrease, since JS calls that started\n       * before a trace event cannot end during the trace event. So as trace\n       * events arrive, we store the \"locked\" amount of JS frames that were\n       * in the stack before the event came.\n       */\n      #lockedJsStackDepth = [];\n      /**\n       * Used to keep track when samples should be integrated even if they\n       * are not children of invocation trace events. This is useful in\n       * cases where we can be missing the start of JS invocation events if\n       * we start tracing half-way through.\n       */\n      #fakeJSInvocation = false;\n      /**\n       * The parsed CPU profile, holding the tree hierarchy of JS frames and\n       * the sample data.\n       */\n      #profileModel;\n      /**\n       * Because GC nodes don't have a stack, we artificially add a stack to\n       * them which corresponds to that of the previous sample. This map\n       * tracks which node is used for the stack of a GC call.\n       * Note that GC samples are not shown in the flamechart, however they\n       * are used during the construction of for profile calls, as we can\n       * infer information about the duration of the executed code when a\n       * GC node is sampled.\n       */\n      #nodeForGC = /* @__PURE__ */ new Map();\n      #engineConfig;\n      #profileId;\n      /**\n       * Keeps track of the individual samples from the CPU Profile.\n       * Only used with Debug Mode experiment enabled.\n       */\n      jsSampleEvents = [];\n      constructor(profileModel, profileId, pid, tid, configuration) {\n        this.#profileModel = profileModel;\n        this.#threadId = tid;\n        this.#processId = pid;\n        this.#engineConfig = configuration || Configuration_exports.defaults();\n        this.#profileId = profileId;\n      }\n      buildProfileCalls(traceEvents) {\n        const mergedEvents = mergeEventsInOrder(traceEvents, this.callsFromProfileSamples());\n        const stack = [];\n        for (let i = 0; i < mergedEvents.length; i++) {\n          const event = mergedEvents[i];\n          if (event.ph === TraceEvents_exports.Phase.INSTANT && !extractSampleTraceId(event)) {\n            continue;\n          }\n          if (stack.length === 0) {\n            if (TraceEvents_exports.isProfileCall(event)) {\n              this.#onProfileCall(event);\n              continue;\n            }\n            stack.push(event);\n            this.#onTraceEventStart(event);\n            continue;\n          }\n          const parentEvent = stack.at(-1);\n          if (parentEvent === void 0) {\n            continue;\n          }\n          const begin = event.ts;\n          const parentBegin = parentEvent.ts;\n          const parentDuration = parentEvent.dur || 0;\n          const parentEnd = parentBegin + parentDuration;\n          const startsAfterParent = begin >= parentEnd;\n          if (startsAfterParent) {\n            this.#onTraceEventEnd(parentEvent);\n            stack.pop();\n            i--;\n            continue;\n          }\n          if (TraceEvents_exports.isProfileCall(event)) {\n            this.#onProfileCall(event, parentEvent);\n            continue;\n          }\n          this.#onTraceEventStart(event);\n          stack.push(event);\n        }\n        while (stack.length) {\n          const last = stack.pop();\n          if (last) {\n            this.#onTraceEventEnd(last);\n          }\n        }\n        sortTraceEventsInPlace(this.jsSampleEvents);\n        return this.#constructedProfileCalls;\n      }\n      #onTraceEventStart(event) {\n        if (event.name === TraceEvents_exports.Name.RUN_MICROTASKS || event.name === TraceEvents_exports.Name.RUN_TASK) {\n          this.#lockedJsStackDepth = [];\n          this.#truncateJSStack(0, event.ts);\n          this.#fakeJSInvocation = false;\n        }\n        if (this.#fakeJSInvocation) {\n          this.#truncateJSStack(this.#lockedJsStackDepth.pop() || 0, event.ts);\n          this.#fakeJSInvocation = false;\n        }\n        this.#extractStackTrace(event);\n        this.#lockedJsStackDepth.push(this.#currentJSStack.length);\n      }\n      #onProfileCall(event, parent) {\n        if (parent && TraceEvents_exports.isJSInvocationEvent(parent) || this.#fakeJSInvocation) {\n          this.#extractStackTrace(event);\n        } else if (TraceEvents_exports.isProfileCall(event) && this.#currentJSStack.length === 0) {\n          this.#fakeJSInvocation = true;\n          const stackDepthBefore = this.#currentJSStack.length;\n          this.#extractStackTrace(event);\n          this.#lockedJsStackDepth.push(stackDepthBefore);\n        }\n      }\n      #onTraceEventEnd(event) {\n        const endTime = Timing_exports.Micro(event.ts + (event.dur ?? 0));\n        this.#truncateJSStack(this.#lockedJsStackDepth.pop() || 0, endTime);\n      }\n      /**\n       * Builds the initial calls with no duration from samples. Their\n       * purpose is to be merged with the trace event array being parsed so\n       * that they can be traversed in order with them and their duration\n       * can be updated as the SampleIntegrator callbacks are invoked.\n       */\n      callsFromProfileSamples() {\n        const samples = this.#profileModel.samples;\n        const timestamps = this.#profileModel.timestamps;\n        if (!samples) {\n          return [];\n        }\n        const calls = [];\n        let prevNode;\n        for (let i = 0; i < samples.length; i++) {\n          const node = this.#profileModel.nodeByIndex(i);\n          const timestamp = milliToMicro(Timing_exports.Milli(timestamps[i]));\n          if (!node) {\n            continue;\n          }\n          const call = makeProfileCall(node, this.#profileId, i, timestamp, this.#processId, this.#threadId);\n          calls.push(call);\n          if (this.#engineConfig.debugMode) {\n            const traceId = this.#profileModel.traceIds?.[i];\n            this.jsSampleEvents.push(this.#makeJSSampleEvent(call, timestamp, traceId));\n          }\n          if (node.id === this.#profileModel.gcNode?.id && prevNode) {\n            this.#nodeForGC.set(call, prevNode);\n            continue;\n          }\n          prevNode = node;\n        }\n        return calls;\n      }\n      /**\n       * Given a synthetic profile call, returns an array of profile calls\n       * representing the stack trace that profile call belongs to based on\n       * its nodeId. The input profile call will be at the top of the\n       * returned stack (last position), meaning that any other frames that\n       * were effectively above it are omitted.\n       * @param profileCall\n       * @param overrideTimeStamp a custom timestamp to use for the returned\n       * profile calls. If not defined, the timestamp of the input\n       * profileCall is used instead. This param is useful for example when\n       * creating the profile calls for a sample with a trace id, since the\n       * timestamp of the corresponding trace event should be used instead\n       * of the sample's.\n       */\n      #makeProfileCallsForStack(profileCall, overrideTimeStamp) {\n        let node = this.#profileModel.nodeById(profileCall.nodeId);\n        const isGarbageCollection = node?.id === this.#profileModel.gcNode?.id;\n        if (isGarbageCollection) {\n          node = this.#nodeForGC.get(profileCall) || null;\n        }\n        if (!node) {\n          return [];\n        }\n        const callFrames = new Array(node.depth + 1 + Number(isGarbageCollection));\n        let i = callFrames.length - 1;\n        if (isGarbageCollection) {\n          callFrames[i--] = profileCall;\n        }\n        while (node) {\n          callFrames[i--] = makeProfileCall(node, profileCall.profileId, profileCall.sampleIndex, overrideTimeStamp ?? profileCall.ts, this.#processId, this.#threadId);\n          node = node.parent;\n        }\n        return callFrames;\n      }\n      #getStackForSampleTraceId(traceId, timestamp) {\n        const nodeId = this.#profileModel.traceIds?.[traceId];\n        const node = nodeId && this.#profileModel.nodeById(nodeId);\n        const maybeCallForTraceId = node && makeProfileCall(node, this.#profileId, -1, timestamp, this.#processId, this.#threadId);\n        if (!maybeCallForTraceId) {\n          return null;\n        }\n        if (this.#engineConfig.debugMode) {\n          this.jsSampleEvents.push(this.#makeJSSampleEvent(maybeCallForTraceId, timestamp, traceId));\n        }\n        return this.#makeProfileCallsForStack(maybeCallForTraceId);\n      }\n      /**\n       * Update tracked stack using this event's call stack.\n       */\n      #extractStackTrace(event) {\n        let stackTrace = this.#currentJSStack;\n        if (TraceEvents_exports.isProfileCall(event)) {\n          stackTrace = this.#makeProfileCallsForStack(event);\n        }\n        const traceId = extractSampleTraceId(event);\n        const maybeCallForTraceId = traceId && this.#getStackForSampleTraceId(traceId, event.ts);\n        if (maybeCallForTraceId) {\n          stackTrace = maybeCallForTraceId;\n        }\n        _a.filterStackFrames(stackTrace, this.#engineConfig);\n        const endTime = event.ts + (event.dur || 0);\n        const minFrames = Math.min(stackTrace.length, this.#currentJSStack.length);\n        let i;\n        for (i = this.#lockedJsStackDepth.at(-1) || 0; i < minFrames; ++i) {\n          const newFrame = stackTrace[i].callFrame;\n          const oldFrame = this.#currentJSStack[i].callFrame;\n          if (!_a.framesAreEqual(newFrame, oldFrame)) {\n            break;\n          }\n          this.#currentJSStack[i].dur = Timing_exports.Micro(Math.max(this.#currentJSStack[i].dur || 0, endTime - this.#currentJSStack[i].ts));\n        }\n        this.#truncateJSStack(i, event.ts);\n        for (; i < stackTrace.length; ++i) {\n          const call = stackTrace[i];\n          if (call.nodeId === this.#profileModel.programNode?.id || call.nodeId === this.#profileModel.root?.id || call.nodeId === this.#profileModel.idleNode?.id || call.nodeId === this.#profileModel.gcNode?.id) {\n            continue;\n          }\n          this.#currentJSStack.push(call);\n          this.#constructedProfileCalls.push(call);\n        }\n      }\n      /**\n       * When a call stack that differs from the one we are tracking has\n       * been detected in the samples, the latter is \"truncated\" by\n       * setting the ending time of its call frames and removing the top\n       * call frames that aren't shared with the new call stack. This way,\n       * we can update the tracked stack with the new call frames on top.\n       * @param depth the amount of call frames from bottom to top that\n       * should be kept in the tracking stack trace. AKA amount of shared\n       * call frames between two stacks.\n       * @param time the new end of the call frames in the stack.\n       */\n      #truncateJSStack(depth, time) {\n        if (this.#lockedJsStackDepth.length) {\n          const lockedDepth = this.#lockedJsStackDepth.at(-1);\n          if (lockedDepth && depth < lockedDepth) {\n            console.error(`Child stack is shallower (${depth}) than the parent stack (${lockedDepth}) at ${time}`);\n            depth = lockedDepth;\n          }\n        }\n        if (this.#currentJSStack.length < depth) {\n          console.error(`Trying to truncate higher than the current stack size at ${time}`);\n          depth = this.#currentJSStack.length;\n        }\n        for (let k = 0; k < this.#currentJSStack.length; ++k) {\n          this.#currentJSStack[k].dur = Timing_exports.Micro(Math.max(time - this.#currentJSStack[k].ts, 0));\n        }\n        this.#currentJSStack.length = depth;\n      }\n      #makeJSSampleEvent(call, timestamp, traceId) {\n        const JSSampleEvent = {\n          name: TraceEvents_exports.Name.JS_SAMPLE,\n          cat: \"devtools.timeline\",\n          args: {\n            data: { traceId, stackTrace: this.#makeProfileCallsForStack(call).map((e) => e.callFrame) }\n          },\n          ph: TraceEvents_exports.Phase.INSTANT,\n          ts: timestamp,\n          dur: Timing_exports.Micro(0),\n          pid: this.#processId,\n          tid: this.#threadId\n        };\n        return JSSampleEvent;\n      }\n      static framesAreEqual(frame1, frame2) {\n        return frame1.scriptId === frame2.scriptId && frame1.functionName === frame2.functionName && frame1.lineNumber === frame2.lineNumber;\n      }\n      static showNativeName(name, runtimeCallStatsEnabled) {\n        return runtimeCallStatsEnabled && Boolean(_a.nativeGroup(name));\n      }\n      static nativeGroup(nativeName) {\n        if (nativeName.startsWith(\"Parse\")) {\n          return _a.NativeGroups.PARSE;\n        }\n        if (nativeName.startsWith(\"Compile\") || nativeName.startsWith(\"Recompile\")) {\n          return _a.NativeGroups.COMPILE;\n        }\n        return null;\n      }\n      static isNativeRuntimeFrame(frame) {\n        return frame.url === \"native V8Runtime\";\n      }\n      static filterStackFrames(stack, engineConfig) {\n        const showAllEvents = engineConfig.showAllEvents;\n        if (showAllEvents) {\n          return;\n        }\n        let previousNativeFrameName = null;\n        let j = 0;\n        for (let i = 0; i < stack.length; ++i) {\n          const frame = stack[i].callFrame;\n          const nativeRuntimeFrame = _a.isNativeRuntimeFrame(frame);\n          if (nativeRuntimeFrame && !_a.showNativeName(frame.functionName, engineConfig.includeRuntimeCallStats)) {\n            continue;\n          }\n          const nativeFrameName = nativeRuntimeFrame ? _a.nativeGroup(frame.functionName) : null;\n          if (previousNativeFrameName && previousNativeFrameName === nativeFrameName) {\n            continue;\n          }\n          previousNativeFrameName = nativeFrameName;\n          stack[j++] = stack[i];\n        }\n        stack.length = j;\n      }\n      static createFakeTraceFromCpuProfile(profile, tid) {\n        if (!profile) {\n          return { traceEvents: [], metadata: {} };\n        }\n        const cpuProfileEvent = {\n          cat: \"disabled-by-default-devtools.timeline\",\n          name: TraceEvents_exports.Name.CPU_PROFILE,\n          ph: TraceEvents_exports.Phase.COMPLETE,\n          pid: TraceEvents_exports.ProcessID(1),\n          tid,\n          ts: Timing_exports.Micro(profile.startTime),\n          dur: Timing_exports.Micro(profile.endTime - profile.startTime),\n          args: { data: { cpuProfile: profile } },\n          // Create an arbitrary profile id.\n          id: \"0x1\"\n        };\n        return {\n          traceEvents: [cpuProfileEvent],\n          metadata: {\n            dataOrigin: File_exports.DataOrigin.CPU_PROFILE\n          }\n        };\n      }\n      static extractCpuProfileFromFakeTrace(traceEvents) {\n        const profileEvent = traceEvents.find((e) => TraceEvents_exports.isSyntheticCpuProfile(e));\n        const profile = profileEvent?.args.data.cpuProfile;\n        if (!profile) {\n          throw new Error(\"Missing cpuProfile data\");\n        }\n        return profile;\n      }\n    };\n    _a = SamplesIntegrator;\n    (function(SamplesIntegrator2) {\n      let NativeGroups;\n      (function(NativeGroups2) {\n        NativeGroups2[\"COMPILE\"] = \"Compile\";\n        NativeGroups2[\"PARSE\"] = \"Parse\";\n      })(NativeGroups = SamplesIntegrator2.NativeGroups || (SamplesIntegrator2.NativeGroups = {}));\n    })(SamplesIntegrator || (SamplesIntegrator = {}));\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/helpers/helpers.js\nvar init_helpers2 = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/helpers/helpers.js\"() {\n    init_process_global();\n    init_Extensions2();\n    init_Network();\n    init_SamplesIntegrator();\n    init_SyntheticEvents();\n    init_Timing3();\n    init_Trace();\n    init_TreeHelpers();\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/handlers/AnimationFramesHandler.js\nvar AnimationFramesHandler_exports = {};\n__export(AnimationFramesHandler_exports, {\n  data: () => data,\n  deps: () => deps,\n  finalize: () => finalize,\n  handleEvent: () => handleEvent,\n  handleUserConfig: () => handleUserConfig,\n  reset: () => reset\n});\nfunction threadKey(data31) {\n  return `${data31.pid}-${data31.tid}`;\n}\nfunction reset() {\n  animationFrameStarts = /* @__PURE__ */ new Map();\n  animationFrameEnds = /* @__PURE__ */ new Map();\n  animationFrames = [];\n  presentationForFrame = /* @__PURE__ */ new Map();\n  animationFramePresentations = /* @__PURE__ */ new Map();\n  isEnabled = false;\n}\nfunction handleUserConfig(config3) {\n  isEnabled = config3.enableAnimationsFrameHandler;\n}\nfunction handleEvent(event) {\n  if (!isEnabled) {\n    return;\n  }\n  if (TraceEvents_exports.isAnimationFrameAsyncStart(event)) {\n    const key = threadKey(event);\n    const existing = animationFrameStarts.get(key) ?? [];\n    existing.push(event);\n    animationFrameStarts.set(key, existing);\n  } else if (TraceEvents_exports.isAnimationFrameAsyncEnd(event)) {\n    const key = threadKey(event);\n    const existing = animationFrameEnds.get(key) ?? [];\n    existing.push(event);\n    animationFrameEnds.set(key, existing);\n  } else if (TraceEvents_exports.isAnimationFramePresentation(event) && event.args?.id) {\n    animationFramePresentations.set(event.args.id, event);\n  }\n}\nasync function finalize() {\n  for (const [key, startEvents] of animationFrameStarts.entries()) {\n    const endEvents = animationFrameEnds.get(key);\n    if (!endEvents) {\n      continue;\n    }\n    Trace_exports.sortTraceEventsInPlace(startEvents);\n    Trace_exports.sortTraceEventsInPlace(endEvents);\n    for (let i = 0; i < startEvents.length; i++) {\n      const endEvent = endEvents.at(i);\n      if (!endEvent) {\n        break;\n      }\n      const startEvent = startEvents[i];\n      const syntheticEvent = SyntheticEvents_exports.SyntheticEventsManager.registerSyntheticEvent({\n        rawSourceEvent: startEvent,\n        ...startEvent,\n        dur: Timing_exports.Micro(endEvent.ts - startEvent.ts),\n        args: {\n          data: {\n            beginEvent: startEvent,\n            endEvent\n          }\n        }\n      });\n      animationFrames.push(syntheticEvent);\n      const id = startEvent.args?.id;\n      if (id) {\n        const presentationEvent = animationFramePresentations.get(id);\n        if (presentationEvent) {\n          presentationForFrame.set(syntheticEvent, presentationEvent);\n        }\n      }\n    }\n  }\n}\nfunction data() {\n  return {\n    animationFrames,\n    presentationForFrame\n  };\n}\nfunction deps() {\n  return [\"Meta\"];\n}\nvar animationFrameStarts, animationFrameEnds, animationFramePresentations, animationFrames, presentationForFrame, isEnabled;\nvar init_AnimationFramesHandler = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/handlers/AnimationFramesHandler.js\"() {\n    init_process_global();\n    init_helpers2();\n    init_types2();\n    __name(threadKey, \"threadKey\");\n    animationFrameStarts = /* @__PURE__ */ new Map();\n    animationFrameEnds = /* @__PURE__ */ new Map();\n    animationFramePresentations = /* @__PURE__ */ new Map();\n    animationFrames = [];\n    presentationForFrame = /* @__PURE__ */ new Map();\n    __name(reset, \"reset\");\n    isEnabled = false;\n    __name(handleUserConfig, \"handleUserConfig\");\n    __name(handleEvent, \"handleEvent\");\n    __name(finalize, \"finalize\");\n    __name(data, \"data\");\n    __name(deps, \"deps\");\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/handlers/AnimationHandler.js\nvar AnimationHandler_exports = {};\n__export(AnimationHandler_exports, {\n  data: () => data2,\n  finalize: () => finalize2,\n  handleEvent: () => handleEvent2,\n  reset: () => reset2\n});\nfunction reset2() {\n  animations = [];\n  animationsSyntheticEvents = [];\n}\nfunction handleEvent2(event) {\n  if (TraceEvents_exports.isAnimation(event)) {\n    animations.push(event);\n    return;\n  }\n}\nasync function finalize2() {\n  const syntheticEvents2 = Trace_exports.createMatchedSortedSyntheticEvents(animations);\n  animationsSyntheticEvents.push(...syntheticEvents2);\n}\nfunction data2() {\n  return {\n    animations: animationsSyntheticEvents\n  };\n}\nvar animations, animationsSyntheticEvents;\nvar init_AnimationHandler = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/handlers/AnimationHandler.js\"() {\n    init_process_global();\n    init_helpers2();\n    init_types2();\n    animations = [];\n    animationsSyntheticEvents = [];\n    __name(reset2, \"reset\");\n    __name(handleEvent2, \"handleEvent\");\n    __name(finalize2, \"finalize\");\n    __name(data2, \"data\");\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/handlers/FlowsHandler.js\nvar FlowsHandler_exports = {};\n__export(FlowsHandler_exports, {\n  data: () => data3,\n  finalize: () => finalize3,\n  handleEvent: () => handleEvent3,\n  reset: () => reset3\n});\nfunction reset3() {\n  flows = [];\n  flowEvents = [];\n  nonFlowEvents = [];\n  flowDataByGroupToken = /* @__PURE__ */ new Map();\n  boundFlowData = /* @__PURE__ */ new Map();\n  flowsById = /* @__PURE__ */ new Map();\n}\nfunction handleEvent3(event) {\n  if (TraceEvents_exports.isFlowPhaseEvent(event)) {\n    flowEvents.push(event);\n    return;\n  }\n  nonFlowEvents.push(event);\n}\nfunction processNonFlowEvent(event) {\n  const flowDataForEvent = boundFlowData.get(event.ts)?.get(event.pid)?.get(event.tid)?.get(event.cat);\n  if (!flowDataForEvent) {\n    return;\n  }\n  const { flows: flows2, bindingParsed } = flowDataForEvent;\n  if (bindingParsed) {\n    return;\n  }\n  for (const flowId of flows2) {\n    const flow = MapUtilities_exports.getWithDefault(flowsById, flowId, () => /* @__PURE__ */ new Map());\n    flow.set(event.ts, event);\n  }\n  flowDataForEvent.bindingParsed = true;\n}\nfunction processFlowEvent(flowPhaseEvent) {\n  const flowGroup = flowGroupTokenForFlowPhaseEvent(flowPhaseEvent);\n  switch (flowPhaseEvent.ph) {\n    case TraceEvents_exports.Phase.FLOW_START: {\n      const flowMetadata = { flowId: flowPhaseEvent.id, times: /* @__PURE__ */ new Map([[flowPhaseEvent.ts, void 0]]) };\n      flowDataByGroupToken.set(flowGroup, flowPhaseEvent.id);\n      addFlowIdToEventBinding(flowPhaseEvent, flowMetadata.flowId);\n      return;\n    }\n    case TraceEvents_exports.Phase.FLOW_STEP: {\n      const flowId = flowDataByGroupToken.get(flowGroup);\n      if (flowId === void 0) {\n        return;\n      }\n      addFlowIdToEventBinding(flowPhaseEvent, flowId);\n      return;\n    }\n    case TraceEvents_exports.Phase.FLOW_END: {\n      const flowId = flowDataByGroupToken.get(flowGroup);\n      if (flowId === void 0) {\n        return;\n      }\n      addFlowIdToEventBinding(flowPhaseEvent, flowId);\n      flowDataByGroupToken.delete(flowGroup);\n    }\n  }\n}\nfunction addFlowIdToEventBinding(event, flowId) {\n  const flowsByPid = MapUtilities_exports.getWithDefault(boundFlowData, event.ts, () => /* @__PURE__ */ new Map());\n  const flowsByTid = MapUtilities_exports.getWithDefault(flowsByPid, event.pid, () => /* @__PURE__ */ new Map());\n  const flowsByCat = MapUtilities_exports.getWithDefault(flowsByTid, event.tid, () => /* @__PURE__ */ new Map());\n  const flowData = MapUtilities_exports.getWithDefault(flowsByCat, event.cat, () => ({ flows: /* @__PURE__ */ new Set(), bindingParsed: false }));\n  flowData.flows.add(flowId);\n}\nfunction flowGroupTokenForFlowPhaseEvent(event) {\n  return `${event.cat}${ID_COMPONENT_SEPARATOR}${event.name}${ID_COMPONENT_SEPARATOR}${event.id}`;\n}\nasync function finalize3() {\n  flowEvents.forEach(processFlowEvent);\n  nonFlowEvents.forEach(processNonFlowEvent);\n  flows = [...flowsById.values()].map((flowMapping) => [...flowMapping.values()]).map((flow) => flow.filter((event) => event !== void 0)).filter((flow) => flow.length > 1);\n}\nfunction data3() {\n  return {\n    flows\n  };\n}\nvar flowDataByGroupToken, boundFlowData, flowsById, flowEvents, nonFlowEvents, flows, ID_COMPONENT_SEPARATOR;\nvar init_FlowsHandler = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/handlers/FlowsHandler.js\"() {\n    init_process_global();\n    init_platform();\n    init_types2();\n    flowDataByGroupToken = /* @__PURE__ */ new Map();\n    boundFlowData = /* @__PURE__ */ new Map();\n    flowsById = /* @__PURE__ */ new Map();\n    flowEvents = [];\n    nonFlowEvents = [];\n    flows = [];\n    ID_COMPONENT_SEPARATOR = \"-$-\";\n    __name(reset3, \"reset\");\n    __name(handleEvent3, \"handleEvent\");\n    __name(processNonFlowEvent, \"processNonFlowEvent\");\n    __name(processFlowEvent, \"processFlowEvent\");\n    __name(addFlowIdToEventBinding, \"addFlowIdToEventBinding\");\n    __name(flowGroupTokenForFlowPhaseEvent, \"flowGroupTokenForFlowPhaseEvent\");\n    __name(finalize3, \"finalize\");\n    __name(data3, \"data\");\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/handlers/AuctionWorkletsHandler.js\nvar AuctionWorkletsHandler_exports = {};\n__export(AuctionWorkletsHandler_exports, {\n  data: () => data4,\n  finalize: () => finalize4,\n  handleEvent: () => handleEvent4,\n  reset: () => reset4\n});\nfunction reset4() {\n  runningInProcessEvents = /* @__PURE__ */ new Map();\n  doneWithProcessEvents = /* @__PURE__ */ new Map();\n  createdSyntheticEvents = /* @__PURE__ */ new Map();\n  utilityThreads = /* @__PURE__ */ new Map();\n  v8HelperThreads = /* @__PURE__ */ new Map();\n}\nfunction handleEvent4(event) {\n  if (TraceEvents_exports.isAuctionWorkletRunningInProcess(event)) {\n    runningInProcessEvents.set(event.args.data.pid, event);\n    return;\n  }\n  if (TraceEvents_exports.isAuctionWorkletDoneWithProcess(event)) {\n    doneWithProcessEvents.set(event.args.data.pid, event);\n    return;\n  }\n  if (TraceEvents_exports.isThreadName(event)) {\n    if (event.args.name === \"auction_worklet.CrUtilityMain\") {\n      utilityThreads.set(event.pid, event);\n      return;\n    }\n    if (event.args.name === \"AuctionV8HelperThread\") {\n      v8HelperThreads.set(event.pid, event);\n    }\n  }\n}\nfunction workletType(input) {\n  switch (input) {\n    case \"seller\":\n      return TraceEvents_exports.AuctionWorkletType.SELLER;\n    case \"bidder\":\n      return TraceEvents_exports.AuctionWorkletType.BIDDER;\n    default:\n      return TraceEvents_exports.AuctionWorkletType.UNKNOWN;\n  }\n}\nfunction makeSyntheticEventBase(event) {\n  return SyntheticEvents_exports.SyntheticEventsManager.registerSyntheticEvent({\n    rawSourceEvent: event,\n    name: \"SyntheticAuctionWorklet\",\n    s: TraceEvents_exports.Scope.THREAD,\n    cat: event.cat,\n    tid: event.tid,\n    ts: event.ts,\n    ph: TraceEvents_exports.Phase.INSTANT,\n    pid: event.args.data.pid,\n    host: event.args.data.host,\n    target: event.args.data.target,\n    type: workletType(event.args.data.type)\n  });\n}\nasync function finalize4() {\n  for (const [pid, utilityThreadNameEvent] of utilityThreads) {\n    const v8HelperEvent = v8HelperThreads.get(pid);\n    if (!v8HelperEvent) {\n      continue;\n    }\n    const runningEvent = runningInProcessEvents.get(pid);\n    const doneWithEvent = doneWithProcessEvents.get(pid);\n    let syntheticEvent = null;\n    if (runningEvent) {\n      syntheticEvent = {\n        ...makeSyntheticEventBase(runningEvent),\n        args: {\n          data: {\n            runningInProcessEvent: runningEvent,\n            utilityThread: utilityThreadNameEvent,\n            v8HelperThread: v8HelperEvent\n          }\n        }\n      };\n      if (doneWithEvent) {\n        syntheticEvent.args.data.doneWithProcessEvent = doneWithEvent;\n      }\n    } else if (doneWithEvent) {\n      syntheticEvent = {\n        ...makeSyntheticEventBase(doneWithEvent),\n        args: {\n          data: {\n            doneWithProcessEvent: doneWithEvent,\n            utilityThread: utilityThreadNameEvent,\n            v8HelperThread: v8HelperEvent\n          }\n        }\n      };\n      if (runningEvent) {\n        syntheticEvent.args.data.runningInProcessEvent = runningEvent;\n      }\n    }\n    if (syntheticEvent === null) {\n      continue;\n    }\n    createdSyntheticEvents.set(pid, syntheticEvent);\n  }\n}\nfunction data4() {\n  return {\n    worklets: createdSyntheticEvents\n  };\n}\nvar runningInProcessEvents, doneWithProcessEvents, createdSyntheticEvents, utilityThreads, v8HelperThreads;\nvar init_AuctionWorkletsHandler = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/handlers/AuctionWorkletsHandler.js\"() {\n    init_process_global();\n    init_helpers2();\n    init_types2();\n    runningInProcessEvents = /* @__PURE__ */ new Map();\n    doneWithProcessEvents = /* @__PURE__ */ new Map();\n    createdSyntheticEvents = /* @__PURE__ */ new Map();\n    utilityThreads = /* @__PURE__ */ new Map();\n    v8HelperThreads = /* @__PURE__ */ new Map();\n    __name(reset4, \"reset\");\n    __name(handleEvent4, \"handleEvent\");\n    __name(workletType, \"workletType\");\n    __name(makeSyntheticEventBase, \"makeSyntheticEventBase\");\n    __name(finalize4, \"finalize\");\n    __name(data4, \"data\");\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/handlers/MetaHandler.js\nvar MetaHandler_exports = {};\n__export(MetaHandler_exports, {\n  data: () => data5,\n  finalize: () => finalize5,\n  handleEvent: () => handleEvent5,\n  reset: () => reset5\n});\nfunction makeNewTraceBounds() {\n  return {\n    min: Timing_exports.Micro(Number.POSITIVE_INFINITY),\n    max: Timing_exports.Micro(Number.NEGATIVE_INFINITY),\n    range: Timing_exports.Micro(Number.POSITIVE_INFINITY)\n  };\n}\nfunction reset5() {\n  navigationsByFrameId = /* @__PURE__ */ new Map();\n  navigationsByNavigationId = /* @__PURE__ */ new Map();\n  finalDisplayUrlByNavigationId = /* @__PURE__ */ new Map();\n  processNames = /* @__PURE__ */ new Map();\n  mainFrameNavigations = [];\n  browserProcessId = TraceEvents_exports.ProcessID(-1);\n  browserThreadId = TraceEvents_exports.ThreadID(-1);\n  gpuProcessId = TraceEvents_exports.ProcessID(-1);\n  gpuThreadId = TraceEvents_exports.ThreadID(-1);\n  viewportRect = null;\n  topLevelRendererIds = /* @__PURE__ */ new Set();\n  threadsInProcess = /* @__PURE__ */ new Map();\n  rendererProcessesByFrameId = /* @__PURE__ */ new Map();\n  framesByProcessId = /* @__PURE__ */ new Map();\n  traceBounds = makeNewTraceBounds();\n  traceStartedTimeFromTracingStartedEvent = Timing_exports.Micro(-1);\n  traceIsGeneric = true;\n}\nfunction updateRendererProcessByFrame(event, frame) {\n  const framesInProcessById = MapUtilities_exports.getWithDefault(framesByProcessId, frame.processId, () => /* @__PURE__ */ new Map());\n  framesInProcessById.set(frame.frame, frame);\n  const rendererProcessInFrame = MapUtilities_exports.getWithDefault(rendererProcessesByFrameId, frame.frame, () => /* @__PURE__ */ new Map());\n  const rendererProcessInfo = MapUtilities_exports.getWithDefault(rendererProcessInFrame, frame.processId, () => {\n    return [];\n  });\n  const lastProcessData = rendererProcessInfo.at(-1);\n  if (lastProcessData && lastProcessData.frame.url === frame.url) {\n    return;\n  }\n  rendererProcessInfo.push({\n    frame,\n    window: {\n      min: event.ts,\n      max: Timing_exports.Micro(0),\n      range: Timing_exports.Micro(0)\n    }\n  });\n}\nfunction handleEvent5(event) {\n  if (traceIsGeneric && CHROME_WEB_TRACE_EVENTS.has(event.name)) {\n    traceIsGeneric = false;\n  }\n  if (TraceEvents_exports.isProcessName(event)) {\n    processNames.set(event.pid, event);\n  }\n  if (event.ts !== 0 && !event.name.endsWith(\"::UMA\") && eventPhasesOfInterestForTraceBounds.has(event.ph)) {\n    traceBounds.min = Timing_exports.Micro(Math.min(event.ts, traceBounds.min));\n    const eventDuration = event.dur ?? Timing_exports.Micro(0);\n    traceBounds.max = Timing_exports.Micro(Math.max(event.ts + eventDuration, traceBounds.max));\n  }\n  if (TraceEvents_exports.isProcessName(event) && (event.args.name === \"Browser\" || event.args.name === \"HeadlessBrowser\")) {\n    browserProcessId = event.pid;\n    return;\n  }\n  if (TraceEvents_exports.isProcessName(event) && (event.args.name === \"Gpu\" || event.args.name === \"GPU Process\")) {\n    gpuProcessId = event.pid;\n    return;\n  }\n  if (TraceEvents_exports.isThreadName(event) && event.args.name === \"CrGpuMain\") {\n    gpuThreadId = event.tid;\n    return;\n  }\n  if (TraceEvents_exports.isThreadName(event) && event.args.name === \"CrBrowserMain\") {\n    browserThreadId = event.tid;\n  }\n  if (TraceEvents_exports.isMainFrameViewport(event) && viewportRect === null) {\n    const rectAsArray = event.args.data.viewport_rect;\n    const viewportX = rectAsArray[0];\n    const viewportY = rectAsArray[1];\n    const viewportWidth = rectAsArray[2];\n    const viewportHeight = rectAsArray[5];\n    viewportRect = { x: viewportX, y: viewportY, width: viewportWidth, height: viewportHeight };\n    devicePixelRatio2 = event.args.data.dpr;\n  }\n  if (TraceEvents_exports.isTracingStartedInBrowser(event)) {\n    traceStartedTimeFromTracingStartedEvent = event.ts;\n    if (!event.args.data) {\n      throw new Error(\"No frames found in trace data\");\n    }\n    for (const frame of event.args.data.frames ?? []) {\n      updateRendererProcessByFrame(event, frame);\n      if (!frame.parent) {\n        topLevelRendererIds.add(frame.processId);\n      }\n      const traceHasPrimaryMainFrameFlag = \"isInPrimaryMainFrame\" in frame;\n      const traceHasOutermostMainFrameFlag = \"isOutermostMainFrame\" in frame;\n      if (traceHasPrimaryMainFrameFlag && traceHasOutermostMainFrameFlag) {\n        if (frame.isInPrimaryMainFrame && frame.isOutermostMainFrame) {\n          mainFrameId = frame.frame;\n          mainFrameURL = frame.url;\n        }\n      } else if (traceHasOutermostMainFrameFlag) {\n        if (frame.isOutermostMainFrame) {\n          mainFrameId = frame.frame;\n          mainFrameURL = frame.url;\n        }\n      } else if (!frame.parent && frame.url) {\n        mainFrameId = frame.frame;\n        mainFrameURL = frame.url;\n      }\n    }\n    return;\n  }\n  if (TraceEvents_exports.isFrameCommittedInBrowser(event)) {\n    const frame = event.args.data;\n    if (!frame) {\n      return;\n    }\n    updateRendererProcessByFrame(event, frame);\n    if (frame.parent) {\n      return;\n    }\n    topLevelRendererIds.add(frame.processId);\n    return;\n  }\n  if (TraceEvents_exports.isCommitLoad(event)) {\n    const frameData = event.args.data;\n    if (!frameData) {\n      return;\n    }\n    const { frame, name, url } = frameData;\n    updateRendererProcessByFrame(event, { processId: event.pid, frame, name, url });\n    return;\n  }\n  if (TraceEvents_exports.isThreadName(event)) {\n    const threads = MapUtilities_exports.getWithDefault(threadsInProcess, event.pid, () => /* @__PURE__ */ new Map());\n    threads.set(event.tid, event);\n    return;\n  }\n  if (TraceEvents_exports.isNavigationStart(event) && event.args.data) {\n    const navigationId = event.args.data.navigationId;\n    if (navigationsByNavigationId.has(navigationId)) {\n      return;\n    }\n    navigationsByNavigationId.set(navigationId, event);\n    finalDisplayUrlByNavigationId.set(navigationId, event.args.data.documentLoaderURL);\n    const frameId = event.args.frame;\n    const existingFrameNavigations = navigationsByFrameId.get(frameId) || [];\n    existingFrameNavigations.push(event);\n    navigationsByFrameId.set(frameId, existingFrameNavigations);\n    if (frameId === mainFrameId) {\n      mainFrameNavigations.push(event);\n    }\n    return;\n  }\n  if (TraceEvents_exports.isResourceSendRequest(event)) {\n    if (event.args.data.resourceType !== \"Document\") {\n      return;\n    }\n    const maybeNavigationId = event.args.data.requestId;\n    const navigation2 = navigationsByNavigationId.get(maybeNavigationId);\n    if (!navigation2) {\n      return;\n    }\n    finalDisplayUrlByNavigationId.set(maybeNavigationId, event.args.data.url);\n    return;\n  }\n  if (TraceEvents_exports.isDidCommitSameDocumentNavigation(event)) {\n    if (event.args.render_frame_host.frame_type !== \"PRIMARY_MAIN_FRAME\") {\n      return;\n    }\n    const navigation2 = mainFrameNavigations.at(-1);\n    const key = navigation2?.args.data?.navigationId ?? \"\";\n    finalDisplayUrlByNavigationId.set(key, event.args.url);\n    return;\n  }\n}\nasync function finalize5() {\n  if (traceStartedTimeFromTracingStartedEvent >= 0) {\n    traceBounds.min = traceStartedTimeFromTracingStartedEvent;\n  }\n  traceBounds.range = Timing_exports.Micro(traceBounds.max - traceBounds.min);\n  for (const [, processWindows] of rendererProcessesByFrameId) {\n    const processWindowValues = [...processWindows.values()].flat().sort((a, b) => {\n      return a.window.min - b.window.min;\n    });\n    for (let i = 0; i < processWindowValues.length; i++) {\n      const currentWindow = processWindowValues[i];\n      const nextWindow = processWindowValues[i + 1];\n      if (!nextWindow) {\n        currentWindow.window.max = Timing_exports.Micro(traceBounds.max);\n        currentWindow.window.range = Timing_exports.Micro(traceBounds.max - currentWindow.window.min);\n      } else {\n        currentWindow.window.max = Timing_exports.Micro(nextWindow.window.min - 1);\n        currentWindow.window.range = Timing_exports.Micro(currentWindow.window.max - currentWindow.window.min);\n      }\n    }\n  }\n  for (const [frameId, navigations] of navigationsByFrameId) {\n    if (rendererProcessesByFrameId.has(frameId)) {\n      continue;\n    }\n    navigationsByFrameId.delete(frameId);\n    for (const navigation2 of navigations) {\n      if (!navigation2.args.data) {\n        continue;\n      }\n      navigationsByNavigationId.delete(navigation2.args.data.navigationId);\n    }\n  }\n  const firstMainFrameNav = mainFrameNavigations.at(0);\n  const firstNavTimeThreshold = Timing_exports3.secondsToMicro(Timing_exports.Seconds(0.5));\n  if (firstMainFrameNav) {\n    const navigationIsWithinThreshold = firstMainFrameNav.ts - traceBounds.min < firstNavTimeThreshold;\n    if (firstMainFrameNav.args.data?.isOutermostMainFrame && firstMainFrameNav.args.data?.documentLoaderURL && navigationIsWithinThreshold) {\n      mainFrameURL = firstMainFrameNav.args.data.documentLoaderURL;\n    }\n  }\n}\nfunction data5() {\n  return {\n    traceBounds,\n    browserProcessId,\n    browserThreadId,\n    processNames,\n    gpuProcessId,\n    gpuThreadId: gpuThreadId === TraceEvents_exports.ThreadID(-1) ? void 0 : gpuThreadId,\n    viewportRect: viewportRect || void 0,\n    devicePixelRatio: devicePixelRatio2 ?? void 0,\n    mainFrameId,\n    mainFrameURL,\n    navigationsByFrameId,\n    navigationsByNavigationId,\n    finalDisplayUrlByNavigationId,\n    threadsInProcess,\n    rendererProcessesByFrame: rendererProcessesByFrameId,\n    topLevelRendererIds,\n    frameByProcessId: framesByProcessId,\n    mainFrameNavigations,\n    traceIsGeneric\n  };\n}\nvar rendererProcessesByFrameId, mainFrameId, mainFrameURL, framesByProcessId, browserProcessId, browserThreadId, gpuProcessId, gpuThreadId, viewportRect, devicePixelRatio2, processNames, topLevelRendererIds, traceBounds, navigationsByFrameId, navigationsByNavigationId, finalDisplayUrlByNavigationId, mainFrameNavigations, threadsInProcess, traceStartedTimeFromTracingStartedEvent, eventPhasesOfInterestForTraceBounds, traceIsGeneric, CHROME_WEB_TRACE_EVENTS;\nvar init_MetaHandler = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/handlers/MetaHandler.js\"() {\n    init_process_global();\n    init_platform();\n    init_helpers2();\n    init_types2();\n    rendererProcessesByFrameId = /* @__PURE__ */ new Map();\n    mainFrameId = \"\";\n    mainFrameURL = \"\";\n    framesByProcessId = /* @__PURE__ */ new Map();\n    browserProcessId = TraceEvents_exports.ProcessID(-1);\n    browserThreadId = TraceEvents_exports.ThreadID(-1);\n    gpuProcessId = TraceEvents_exports.ProcessID(-1);\n    gpuThreadId = TraceEvents_exports.ThreadID(-1);\n    viewportRect = null;\n    devicePixelRatio2 = null;\n    processNames = /* @__PURE__ */ new Map();\n    topLevelRendererIds = /* @__PURE__ */ new Set();\n    __name(makeNewTraceBounds, \"makeNewTraceBounds\");\n    traceBounds = makeNewTraceBounds();\n    navigationsByFrameId = /* @__PURE__ */ new Map();\n    navigationsByNavigationId = /* @__PURE__ */ new Map();\n    finalDisplayUrlByNavigationId = /* @__PURE__ */ new Map();\n    mainFrameNavigations = [];\n    threadsInProcess = /* @__PURE__ */ new Map();\n    traceStartedTimeFromTracingStartedEvent = Timing_exports.Micro(-1);\n    eventPhasesOfInterestForTraceBounds = /* @__PURE__ */ new Set([\n      TraceEvents_exports.Phase.BEGIN,\n      TraceEvents_exports.Phase.END,\n      TraceEvents_exports.Phase.COMPLETE,\n      TraceEvents_exports.Phase.INSTANT\n    ]);\n    traceIsGeneric = true;\n    CHROME_WEB_TRACE_EVENTS = /* @__PURE__ */ new Set([\n      TraceEvents_exports.Name.TRACING_STARTED_IN_PAGE,\n      TraceEvents_exports.Name.TRACING_SESSION_ID_FOR_WORKER,\n      TraceEvents_exports.Name.TRACING_STARTED_IN_BROWSER,\n      TraceEvents_exports.Name.CPU_PROFILE\n    ]);\n    __name(reset5, \"reset\");\n    __name(updateRendererProcessByFrame, \"updateRendererProcessByFrame\");\n    __name(handleEvent5, \"handleEvent\");\n    __name(finalize5, \"finalize\");\n    __name(data5, \"data\");\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/handlers/NetworkRequestsHandler.js\nvar NetworkRequestsHandler_exports = {};\n__export(NetworkRequestsHandler_exports, {\n  data: () => data6,\n  deps: () => deps2,\n  finalize: () => finalize6,\n  handleEvent: () => handleEvent6,\n  reset: () => reset6\n});\nfunction storeTraceEventWithRequestId(requestId, key, value) {\n  if (!requestMap.has(requestId)) {\n    requestMap.set(requestId, {});\n  }\n  const traceEvents = requestMap.get(requestId);\n  if (!traceEvents) {\n    throw new Error(`Unable to locate trace events for request ID ${requestId}`);\n  }\n  if (Array.isArray(traceEvents[key])) {\n    const target = traceEvents[key];\n    const values = value;\n    target.push(...values);\n  } else {\n    traceEvents[key] = value;\n  }\n}\nfunction firstPositiveValueInList(entries) {\n  for (const entry of entries) {\n    if (entry && entry > 0) {\n      return entry;\n    }\n  }\n  return 0;\n}\nfunction reset6() {\n  requestsById = /* @__PURE__ */ new Map();\n  requestMap = /* @__PURE__ */ new Map();\n  requestsByTime = [];\n  networkRequestEventByInitiatorUrl = /* @__PURE__ */ new Map();\n  eventToInitiatorMap = /* @__PURE__ */ new Map();\n  webSocketData = /* @__PURE__ */ new Map();\n  entityMappings = {\n    eventsByEntity: /* @__PURE__ */ new Map(),\n    entityByEvent: /* @__PURE__ */ new Map(),\n    createdEntityCache: /* @__PURE__ */ new Map(),\n    entityByUrlCache: /* @__PURE__ */ new Map()\n  };\n  linkPreconnectEvents = [];\n}\nfunction handleEvent6(event) {\n  if (TraceEvents_exports.isResourceChangePriority(event)) {\n    storeTraceEventWithRequestId(event.args.data.requestId, \"changePriority\", event);\n    return;\n  }\n  if (TraceEvents_exports.isResourceWillSendRequest(event)) {\n    storeTraceEventWithRequestId(event.args.data.requestId, \"willSendRequests\", [event]);\n    return;\n  }\n  if (TraceEvents_exports.isResourceSendRequest(event)) {\n    storeTraceEventWithRequestId(event.args.data.requestId, \"sendRequests\", [event]);\n    return;\n  }\n  if (TraceEvents_exports.isResourceReceiveResponse(event)) {\n    storeTraceEventWithRequestId(event.args.data.requestId, \"receiveResponse\", event);\n    return;\n  }\n  if (TraceEvents_exports.isResourceReceivedData(event)) {\n    storeTraceEventWithRequestId(event.args.data.requestId, \"receivedData\", [event]);\n    return;\n  }\n  if (TraceEvents_exports.isResourceFinish(event)) {\n    storeTraceEventWithRequestId(event.args.data.requestId, \"resourceFinish\", event);\n    return;\n  }\n  if (TraceEvents_exports.isResourceMarkAsCached(event)) {\n    storeTraceEventWithRequestId(event.args.data.requestId, \"resourceMarkAsCached\", event);\n    return;\n  }\n  if (TraceEvents_exports.isWebSocketCreate(event) || TraceEvents_exports.isWebSocketInfo(event) || TraceEvents_exports.isWebSocketTransfer(event)) {\n    const identifier = event.args.data.identifier;\n    if (!webSocketData.has(identifier)) {\n      if (event.args.data.frame) {\n        webSocketData.set(identifier, {\n          frame: event.args.data.frame,\n          webSocketIdentifier: identifier,\n          events: [],\n          syntheticConnection: null\n        });\n      } else if (event.args.data.workerId) {\n        webSocketData.set(identifier, {\n          workerId: event.args.data.workerId,\n          webSocketIdentifier: identifier,\n          events: [],\n          syntheticConnection: null\n        });\n      }\n    }\n    webSocketData.get(identifier)?.events.push(event);\n  }\n  if (TraceEvents_exports.isLinkPreconnect(event)) {\n    linkPreconnectEvents.push(event);\n    return;\n  }\n}\nasync function finalize6() {\n  const { rendererProcessesByFrame } = data5();\n  for (const [requestId, request] of requestMap.entries()) {\n    if (!request.sendRequests) {\n      continue;\n    }\n    const redirects = [];\n    for (let i = 0; i < request.sendRequests.length - 1; i++) {\n      const sendRequest = request.sendRequests[i];\n      const nextSendRequest = request.sendRequests[i + 1];\n      let ts = sendRequest.ts;\n      let dur = Timing_exports.Micro(nextSendRequest.ts - sendRequest.ts);\n      if (request.willSendRequests?.[i] && request.willSendRequests[i + 1]) {\n        const willSendRequest = request.willSendRequests[i];\n        const nextWillSendRequest = request.willSendRequests[i + 1];\n        ts = willSendRequest.ts;\n        dur = Timing_exports.Micro(nextWillSendRequest.ts - willSendRequest.ts);\n      }\n      redirects.push({\n        url: sendRequest.args.data.url,\n        priority: sendRequest.args.data.priority,\n        requestMethod: sendRequest.args.data.requestMethod,\n        ts,\n        dur\n      });\n    }\n    const firstSendRequest = request.sendRequests[0];\n    const finalSendRequest = request.sendRequests[request.sendRequests.length - 1];\n    if (finalSendRequest.args.data.url.startsWith(\"data:\")) {\n      continue;\n    }\n    const isLightrider = globalThis.isLightrider;\n    if (isLightrider && request.resourceFinish && request.receiveResponse?.args.data.headers) {\n      const lrSizeHeader = request.receiveResponse.args.data.headers.find((h) => h.name === \"X-TotalFetchedSize\");\n      if (lrSizeHeader) {\n        const size = parseFloat(lrSizeHeader.value);\n        if (!isNaN(size)) {\n          request.resourceFinish.args.data.encodedDataLength = size;\n        }\n      }\n    }\n    const isPushedResource = request.resourceFinish?.args.data.encodedDataLength !== 0;\n    const isDiskCached = !!request.receiveResponse && request.receiveResponse.args.data.fromCache && !request.receiveResponse.args.data.fromServiceWorker && !isPushedResource;\n    const isMemoryCached = request.resourceMarkAsCached !== void 0;\n    let timing = isMemoryCached ? void 0 : request.receiveResponse?.args.data.timing;\n    let lrServerResponseTime;\n    if (isLightrider && request.receiveResponse?.args.data.headers) {\n      timing = {\n        requestTime: Timing_exports3.microToSeconds(request.sendRequests.at(0)?.ts ?? 0),\n        connectEnd: 0,\n        connectStart: 0,\n        dnsEnd: 0,\n        dnsStart: 0,\n        proxyEnd: 0,\n        proxyStart: 0,\n        pushEnd: 0,\n        pushStart: 0,\n        receiveHeadersEnd: 0,\n        receiveHeadersStart: 0,\n        sendEnd: 0,\n        sendStart: 0,\n        sslEnd: 0,\n        sslStart: 0,\n        workerReady: 0,\n        workerStart: 0,\n        ...timing\n      };\n      const TCPMsHeader = request.receiveResponse.args.data.headers.find((h) => h.name === \"X-TCPMs\");\n      const TCPMs = TCPMsHeader ? Math.max(0, parseInt(TCPMsHeader.value, 10)) : 0;\n      if (request.receiveResponse.args.data.protocol.startsWith(\"h3\")) {\n        timing.connectStart = 0;\n        timing.connectEnd = TCPMs;\n      } else {\n        timing.connectStart = 0;\n        timing.sslStart = TCPMs / 2;\n        timing.connectEnd = TCPMs;\n        timing.sslEnd = TCPMs;\n      }\n      const ResponseMsHeader = request.receiveResponse.args.data.headers.find((h) => h.name === \"X-ResponseMs\");\n      if (ResponseMsHeader) {\n        lrServerResponseTime = Math.max(0, parseInt(ResponseMsHeader.value, 10));\n      }\n    }\n    const allowedProtocols2 = [\n      \"blob:\",\n      \"file:\",\n      \"filesystem:\",\n      \"http:\",\n      \"https:\"\n    ];\n    if (!allowedProtocols2.some((p) => firstSendRequest.args.data.url.startsWith(p))) {\n      continue;\n    }\n    const initialPriority = finalSendRequest.args.data.priority;\n    let finalPriority = initialPriority;\n    if (request.changePriority) {\n      finalPriority = request.changePriority.args.data.priority;\n    }\n    const startTime = request.willSendRequests?.length ? Timing_exports.Micro(request.willSendRequests[0].ts) : Timing_exports.Micro(firstSendRequest.ts);\n    const endRedirectTime = request.willSendRequests?.length ? Timing_exports.Micro(request.willSendRequests[request.willSendRequests.length - 1].ts) : Timing_exports.Micro(finalSendRequest.ts);\n    const endTime = request.resourceFinish ? request.resourceFinish.ts : endRedirectTime;\n    const finishTime = request.resourceFinish?.args.data.finishTime ? Timing_exports.Micro(request.resourceFinish.args.data.finishTime * SECONDS_TO_MICROSECONDS) : Timing_exports.Micro(endTime);\n    const networkDuration = Timing_exports.Micro(timing ? (finishTime || endRedirectTime) - endRedirectTime : 0);\n    const processingDuration = Timing_exports.Micro(endTime - (finishTime || endTime));\n    const redirectionDuration = Timing_exports.Micro(endRedirectTime - startTime);\n    const queueingFromTraceData = timing ? timing.requestTime * SECONDS_TO_MICROSECONDS - endRedirectTime : 0;\n    const queueing = Timing_exports.Micro(NumberUtilities_exports.clamp(queueingFromTraceData, 0, Number.MAX_VALUE));\n    const stalled = timing ? Timing_exports.Micro(firstPositiveValueInList([\n      timing.dnsStart * MILLISECONDS_TO_MICROSECONDS,\n      timing.connectStart * MILLISECONDS_TO_MICROSECONDS,\n      timing.sendStart * MILLISECONDS_TO_MICROSECONDS,\n      request.receiveResponse ? request.receiveResponse.ts - endRedirectTime : null\n    ])) : request.receiveResponse ? Timing_exports.Micro(request.receiveResponse.ts - startTime) : Timing_exports.Micro(0);\n    const sendStartTime = timing ? Timing_exports.Micro(timing.requestTime * SECONDS_TO_MICROSECONDS + timing.sendStart * MILLISECONDS_TO_MICROSECONDS) : startTime;\n    const waiting = timing ? Timing_exports.Micro((timing.receiveHeadersEnd - timing.sendEnd) * MILLISECONDS_TO_MICROSECONDS) : Timing_exports.Micro(0);\n    const serverResponseTime = timing ? Timing_exports.Micro(((timing.receiveHeadersStart ?? timing.receiveHeadersEnd) - timing.sendEnd) * MILLISECONDS_TO_MICROSECONDS) : Timing_exports.Micro(0);\n    const downloadStart = timing ? Timing_exports.Micro(timing.requestTime * SECONDS_TO_MICROSECONDS + timing.receiveHeadersEnd * MILLISECONDS_TO_MICROSECONDS) : startTime;\n    const download = timing ? Timing_exports.Micro((finishTime || downloadStart) - downloadStart) : request.receiveResponse ? Timing_exports.Micro(endTime - request.receiveResponse.ts) : Timing_exports.Micro(0);\n    const totalTime = Timing_exports.Micro(networkDuration + processingDuration);\n    const dnsLookup = timing ? Timing_exports.Micro((timing.dnsEnd - timing.dnsStart) * MILLISECONDS_TO_MICROSECONDS) : Timing_exports.Micro(0);\n    const ssl = timing ? Timing_exports.Micro((timing.sslEnd - timing.sslStart) * MILLISECONDS_TO_MICROSECONDS) : Timing_exports.Micro(0);\n    const proxyNegotiation = timing ? Timing_exports.Micro((timing.proxyEnd - timing.proxyStart) * MILLISECONDS_TO_MICROSECONDS) : Timing_exports.Micro(0);\n    const requestSent = timing ? Timing_exports.Micro((timing.sendEnd - timing.sendStart) * MILLISECONDS_TO_MICROSECONDS) : Timing_exports.Micro(0);\n    const initialConnection = timing ? Timing_exports.Micro((timing.connectEnd - timing.connectStart) * MILLISECONDS_TO_MICROSECONDS) : Timing_exports.Micro(0);\n    const { frame, url, renderBlocking } = finalSendRequest.args.data;\n    const { encodedDataLength, decodedBodyLength } = request.resourceFinish ? request.resourceFinish.args.data : { encodedDataLength: 0, decodedBodyLength: 0 };\n    const parsedUrl = new URL(url);\n    const isHttps = parsedUrl.protocol === \"https:\";\n    const requestingFrameUrl = Trace_exports.activeURLForFrameAtTime(frame, finalSendRequest.ts, rendererProcessesByFrame) || \"\";\n    const networkEvent = SyntheticEvents_exports.SyntheticEventsManager.registerSyntheticEvent({\n      rawSourceEvent: finalSendRequest,\n      args: {\n        data: {\n          // All data we create from trace events should be added to |syntheticData|.\n          syntheticData: {\n            dnsLookup,\n            download,\n            downloadStart,\n            finishTime,\n            initialConnection,\n            isDiskCached,\n            isHttps,\n            isMemoryCached,\n            isPushedResource,\n            networkDuration,\n            processingDuration,\n            proxyNegotiation,\n            queueing,\n            redirectionDuration,\n            requestSent,\n            sendStartTime,\n            ssl,\n            stalled,\n            totalTime,\n            waiting,\n            serverResponseTime\n          },\n          // All fields below are from TraceEventsForNetworkRequest.\n          decodedBodyLength,\n          encodedDataLength,\n          frame,\n          fromServiceWorker: request.receiveResponse?.args.data.fromServiceWorker,\n          isLinkPreload: finalSendRequest.args.data.isLinkPreload || false,\n          mimeType: request.receiveResponse?.args.data.mimeType ?? \"\",\n          priority: finalPriority,\n          initialPriority,\n          protocol: request.receiveResponse?.args.data.protocol ?? \"unknown\",\n          redirects,\n          // In the event the property isn't set, assume non-blocking.\n          renderBlocking: renderBlocking ?? \"non_blocking\",\n          requestId,\n          requestingFrameUrl,\n          requestMethod: finalSendRequest.args.data.requestMethod,\n          resourceType: finalSendRequest.args.data.resourceType ?? \"Other\",\n          statusCode: request.receiveResponse?.args.data.statusCode ?? 0,\n          responseHeaders: request.receiveResponse?.args.data.headers ?? null,\n          fetchPriorityHint: finalSendRequest.args.data.fetchPriorityHint ?? \"auto\",\n          initiator: finalSendRequest.args.data.initiator,\n          stackTrace: finalSendRequest.args.data.stackTrace,\n          timing,\n          lrServerResponseTime,\n          url,\n          failed: request.resourceFinish?.args.data.didFail ?? false,\n          finished: Boolean(request.resourceFinish),\n          hasResponse: Boolean(request.receiveResponse),\n          connectionId: request.receiveResponse?.args.data.connectionId,\n          connectionReused: request.receiveResponse?.args.data.connectionReused\n        }\n      },\n      cat: \"loading\",\n      name: TraceEvents_exports.Name.SYNTHETIC_NETWORK_REQUEST,\n      ph: TraceEvents_exports.Phase.COMPLETE,\n      dur: Timing_exports.Micro(endTime - startTime),\n      tdur: Timing_exports.Micro(endTime - startTime),\n      ts: Timing_exports.Micro(startTime),\n      tts: Timing_exports.Micro(startTime),\n      pid: finalSendRequest.pid,\n      tid: finalSendRequest.tid\n    });\n    requestsByTime.push(networkEvent);\n    requestsById.set(networkEvent.args.data.requestId, networkEvent);\n    addNetworkRequestToEntityMapping(networkEvent, entityMappings, request);\n    const initiatorUrl = networkEvent.args.data.initiator?.url || Trace_exports.getStackTraceTopCallFrameInEventPayload(networkEvent)?.url;\n    if (initiatorUrl) {\n      const events = networkRequestEventByInitiatorUrl.get(initiatorUrl) ?? [];\n      events.push(networkEvent);\n      networkRequestEventByInitiatorUrl.set(initiatorUrl, events);\n    }\n  }\n  for (const request of requestsByTime) {\n    const initiatedEvents = networkRequestEventByInitiatorUrl.get(request.args.data.url);\n    if (initiatedEvents) {\n      for (const initiatedEvent of initiatedEvents) {\n        eventToInitiatorMap.set(initiatedEvent, request);\n      }\n    }\n  }\n  finalizeWebSocketData();\n}\nfunction data6() {\n  return {\n    byId: requestsById,\n    byTime: requestsByTime,\n    eventToInitiator: eventToInitiatorMap,\n    webSocket: [...webSocketData.values()],\n    entityMappings: {\n      entityByEvent: entityMappings.entityByEvent,\n      eventsByEntity: entityMappings.eventsByEntity,\n      createdEntityCache: entityMappings.createdEntityCache,\n      entityByUrlCache: entityMappings.entityByUrlCache\n    },\n    linkPreconnectEvents\n  };\n}\nfunction deps2() {\n  return [\"Meta\"];\n}\nfunction finalizeWebSocketData() {\n  webSocketData.forEach((data31) => {\n    let startEvent = null;\n    let endEvent = null;\n    for (const event of data31.events) {\n      if (TraceEvents_exports.isWebSocketCreate(event)) {\n        startEvent = event;\n      }\n      if (TraceEvents_exports.isWebSocketDestroy(event)) {\n        endEvent = event;\n      }\n    }\n    data31.syntheticConnection = createSyntheticWebSocketConnection(startEvent, endEvent, data31.events[0]);\n  });\n}\nfunction createSyntheticWebSocketConnection(startEvent, endEvent, firstRecordedEvent) {\n  const { traceBounds: traceBounds2 } = data5();\n  const startTs = startEvent ? startEvent.ts : traceBounds2.min;\n  const endTs = endEvent ? endEvent.ts : traceBounds2.max;\n  const duration = endTs - startTs;\n  const mainEvent = startEvent || endEvent || firstRecordedEvent;\n  return {\n    name: \"SyntheticWebSocketConnection\",\n    cat: mainEvent.cat,\n    ph: TraceEvents_exports.Phase.COMPLETE,\n    ts: startTs,\n    dur: duration,\n    pid: mainEvent.pid,\n    tid: mainEvent.tid,\n    s: mainEvent.s,\n    rawSourceEvent: mainEvent,\n    _tag: \"SyntheticEntryTag\",\n    args: {\n      data: {\n        identifier: mainEvent.args.data.identifier,\n        priority: \"Low\",\n        url: mainEvent.args.data.url || \"\"\n      }\n    }\n  };\n}\nvar MILLISECONDS_TO_MICROSECONDS, SECONDS_TO_MICROSECONDS, webSocketData, linkPreconnectEvents, requestMap, requestsById, requestsByTime, networkRequestEventByInitiatorUrl, eventToInitiatorMap, entityMappings;\nvar init_NetworkRequestsHandler = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/handlers/NetworkRequestsHandler.js\"() {\n    init_process_global();\n    init_platform();\n    init_helpers2();\n    init_types2();\n    init_helpers();\n    init_MetaHandler();\n    MILLISECONDS_TO_MICROSECONDS = 1e3;\n    SECONDS_TO_MICROSECONDS = 1e6;\n    webSocketData = /* @__PURE__ */ new Map();\n    linkPreconnectEvents = [];\n    requestMap = /* @__PURE__ */ new Map();\n    requestsById = /* @__PURE__ */ new Map();\n    requestsByTime = [];\n    networkRequestEventByInitiatorUrl = /* @__PURE__ */ new Map();\n    eventToInitiatorMap = /* @__PURE__ */ new Map();\n    entityMappings = {\n      eventsByEntity: /* @__PURE__ */ new Map(),\n      entityByEvent: /* @__PURE__ */ new Map(),\n      createdEntityCache: /* @__PURE__ */ new Map(),\n      entityByUrlCache: /* @__PURE__ */ new Map()\n    };\n    __name(storeTraceEventWithRequestId, \"storeTraceEventWithRequestId\");\n    __name(firstPositiveValueInList, \"firstPositiveValueInList\");\n    __name(reset6, \"reset\");\n    __name(handleEvent6, \"handleEvent\");\n    __name(finalize6, \"finalize\");\n    __name(data6, \"data\");\n    __name(deps2, \"deps\");\n    __name(finalizeWebSocketData, \"finalizeWebSocketData\");\n    __name(createSyntheticWebSocketConnection, \"createSyntheticWebSocketConnection\");\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/cpu_profile/ProfileTreeModel.js\nvar ProfileNode, ProfileTreeModel;\nvar init_ProfileTreeModel = __esm({\n  \"node_modules/@paulirish/trace_engine/models/cpu_profile/ProfileTreeModel.js\"() {\n    init_process_global();\n    ProfileNode = class {\n      static {\n        __name(this, \"ProfileNode\");\n      }\n      callFrame;\n      callUID;\n      self;\n      total;\n      id;\n      parent;\n      children;\n      functionName;\n      depth;\n      deoptReason;\n      constructor(callFrame) {\n        this.callFrame = callFrame;\n        this.callUID = `${callFrame.functionName}@${callFrame.scriptId}:${callFrame.lineNumber}:${callFrame.columnNumber}`;\n        this.self = 0;\n        this.total = 0;\n        this.id = 0;\n        this.functionName = callFrame.functionName;\n        this.parent = null;\n        this.children = [];\n      }\n      get scriptId() {\n        return String(this.callFrame.scriptId);\n      }\n      get url() {\n        return this.callFrame.url;\n      }\n      get lineNumber() {\n        return this.callFrame.lineNumber;\n      }\n      get columnNumber() {\n        return this.callFrame.columnNumber;\n      }\n      setFunctionName(name) {\n        if (name === null) {\n          return;\n        }\n        this.functionName = name;\n      }\n    };\n    ProfileTreeModel = class {\n      static {\n        __name(this, \"ProfileTreeModel\");\n      }\n      root;\n      total;\n      maxDepth;\n      initialize(root2) {\n        this.root = root2;\n        this.assignDepthsAndParents();\n        this.total = this.calculateTotals(this.root);\n      }\n      assignDepthsAndParents() {\n        const root2 = this.root;\n        root2.depth = -1;\n        root2.parent = null;\n        this.maxDepth = 0;\n        const nodesToTraverse = [root2];\n        while (nodesToTraverse.length) {\n          const parent = nodesToTraverse.pop();\n          const depth = parent.depth + 1;\n          if (depth > this.maxDepth) {\n            this.maxDepth = depth;\n          }\n          const children = parent.children;\n          for (const child of children) {\n            child.depth = depth;\n            child.parent = parent;\n            nodesToTraverse.push(child);\n          }\n        }\n      }\n      calculateTotals(root2) {\n        const nodesToTraverse = [root2];\n        const dfsList = [];\n        while (nodesToTraverse.length) {\n          const node = nodesToTraverse.pop();\n          node.total = node.self;\n          dfsList.push(node);\n          nodesToTraverse.push(...node.children);\n        }\n        while (dfsList.length > 1) {\n          const node = dfsList.pop();\n          if (node.parent) {\n            node.parent.total += node.total;\n          }\n        }\n        return root2.total;\n      }\n    };\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/cpu_profile/CPUProfileDataModel.js\nvar CPUProfileDataModel_exports = {};\n__export(CPUProfileDataModel_exports, {\n  CPUProfileDataModel: () => CPUProfileDataModel,\n  CPUProfileNode: () => CPUProfileNode\n});\nvar CPUProfileNode, CPUProfileDataModel;\nvar init_CPUProfileDataModel = __esm({\n  \"node_modules/@paulirish/trace_engine/models/cpu_profile/CPUProfileDataModel.js\"() {\n    init_process_global();\n    init_platform();\n    init_ProfileTreeModel();\n    CPUProfileNode = class extends ProfileNode {\n      static {\n        __name(this, \"CPUProfileNode\");\n      }\n      id;\n      self;\n      // Position ticks are available in profile nodes coming from CDP\n      // profiles and not in those coming from tracing. They are used to\n      // calculate the line level execution time shown in the Sources panel\n      // after recording a profile. For trace CPU profiles we use the\n      // `lines` array instead.\n      positionTicks;\n      deoptReason;\n      constructor(node, samplingInterval) {\n        const callFrame = node.callFrame || {\n          // TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration\n          // @ts-expect-error\n          functionName: node[\"functionName\"],\n          // TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration\n          // @ts-expect-error\n          scriptId: node[\"scriptId\"],\n          // TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration\n          // @ts-expect-error\n          url: node[\"url\"],\n          // TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration\n          // @ts-expect-error\n          lineNumber: node[\"lineNumber\"] - 1,\n          // TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration\n          // @ts-expect-error\n          columnNumber: node[\"columnNumber\"] - 1\n        };\n        super(callFrame);\n        this.id = node.id;\n        this.self = (node.hitCount || 0) * samplingInterval;\n        this.positionTicks = node.positionTicks;\n        this.deoptReason = node.deoptReason && node.deoptReason !== \"no reason\" ? node.deoptReason : null;\n      }\n    };\n    CPUProfileDataModel = class extends ProfileTreeModel {\n      static {\n        __name(this, \"CPUProfileDataModel\");\n      }\n      profileStartTime;\n      profileEndTime;\n      timestamps;\n      samples;\n      /**\n       * Contains trace ids assigned to samples, if any. Trace ids are\n       * keyed by the sample index in the profile. These are only created\n       * for CPU profiles coming from traces.\n       */\n      traceIds;\n      lines;\n      totalHitCount;\n      profileHead;\n      /**\n       * A cache for the nodes we have parsed.\n       * Note: \"Parsed\" nodes are different from the \"Protocol\" nodes, the\n       * latter being the raw data we receive from the backend.\n       */\n      #idToParsedNode;\n      gcNode;\n      programNode;\n      idleNode;\n      #stackStartTimes;\n      #stackChildrenDuration;\n      constructor(profile) {\n        super();\n        const isLegacyFormat = Boolean(profile[\"head\"]);\n        if (isLegacyFormat) {\n          this.profileStartTime = profile.startTime * 1e3;\n          this.profileEndTime = profile.endTime * 1e3;\n          this.timestamps = profile.timestamps;\n          this.compatibilityConversionHeadToNodes(profile);\n        } else {\n          this.profileStartTime = profile.startTime / 1e3;\n          this.profileEndTime = profile.endTime / 1e3;\n          this.timestamps = this.convertTimeDeltas(profile);\n        }\n        this.traceIds = profile.traceIds;\n        this.samples = profile.samples;\n        this.lines = profile.lines;\n        this.totalHitCount = 0;\n        this.profileHead = this.translateProfileTree(profile.nodes);\n        this.initialize(this.profileHead);\n        this.extractMetaNodes();\n        if (this.samples?.length) {\n          this.sortSamples();\n          this.normalizeTimestamps();\n          this.fixMissingSamples();\n        }\n      }\n      compatibilityConversionHeadToNodes(profile) {\n        if (!profile.head || profile.nodes) {\n          return;\n        }\n        const nodes = [];\n        convertNodesTree(profile.head);\n        profile.nodes = nodes;\n        delete profile.head;\n        function convertNodesTree(node) {\n          nodes.push(node);\n          node.children = node.children.map(convertNodesTree);\n          return node.id;\n        }\n        __name(convertNodesTree, \"convertNodesTree\");\n      }\n      /**\n       * Calculate timestamps using timeDeltas. Some CPU profile formats,\n       * like the ones contained in traces have timeDeltas instead of\n       * timestamps.\n       */\n      convertTimeDeltas(profile) {\n        if (!profile.timeDeltas) {\n          return [];\n        }\n        let lastTimeMicroSec = profile.startTime;\n        const timestamps = new Array(profile.timeDeltas.length);\n        for (let i = 0; i < profile.timeDeltas.length; ++i) {\n          lastTimeMicroSec += profile.timeDeltas[i];\n          timestamps[i] = lastTimeMicroSec;\n        }\n        return timestamps;\n      }\n      /**\n       * Creates a Tree of CPUProfileNodes using the Protocol.Profiler.ProfileNodes.\n       * As the tree is built, samples of native code (prefixed with \"native \") are\n       * filtered out. Samples of filtered nodes are replaced with the parent of the\n       * node being filtered.\n       *\n       * This function supports legacy and new definitions of the CDP Profiler.Profile\n       * type.\n       */\n      translateProfileTree(nodes) {\n        function buildChildrenFromParents(nodes2) {\n          if (nodes2[0].children) {\n            return;\n          }\n          nodes2[0].children = [];\n          for (let i = 1; i < nodes2.length; ++i) {\n            const node = nodes2[i];\n            const parentNode = protocolNodeById.get(node.parent);\n            if (!parentNode) {\n              continue;\n            }\n            if (parentNode.children) {\n              parentNode.children.push(node.id);\n            } else {\n              parentNode.children = [node.id];\n            }\n          }\n        }\n        __name(buildChildrenFromParents, \"buildChildrenFromParents\");\n        function buildHitCountFromSamples(nodes2, samples) {\n          if (typeof nodes2[0].hitCount === \"number\") {\n            return;\n          }\n          if (!samples) {\n            throw new Error(\"Error: Neither hitCount nor samples are present in profile.\");\n          }\n          for (let i = 0; i < nodes2.length; ++i) {\n            nodes2[i].hitCount = 0;\n          }\n          for (let i = 0; i < samples.length; ++i) {\n            const node = protocolNodeById.get(samples[i]);\n            if (node?.hitCount === void 0) {\n              continue;\n            }\n            node.hitCount++;\n          }\n        }\n        __name(buildHitCountFromSamples, \"buildHitCountFromSamples\");\n        const protocolNodeById = /* @__PURE__ */ new Map();\n        for (let i = 0; i < nodes.length; ++i) {\n          const node = nodes[i];\n          protocolNodeById.set(node.id, node);\n        }\n        buildHitCountFromSamples(nodes, this.samples);\n        buildChildrenFromParents(nodes);\n        this.totalHitCount = nodes.reduce((acc, node) => acc + (node.hitCount || 0), 0);\n        const sampleTime = (this.profileEndTime - this.profileStartTime) / this.totalHitCount;\n        const root2 = nodes[0];\n        const idToUseForRemovedNode = /* @__PURE__ */ new Map([[root2.id, root2.id]]);\n        this.#idToParsedNode = /* @__PURE__ */ new Map();\n        const resultRoot = new CPUProfileNode(root2, sampleTime);\n        this.#idToParsedNode.set(root2.id, resultRoot);\n        if (!root2.children) {\n          throw new Error(\"Missing children for root\");\n        }\n        const parentNodeStack = root2.children.map(() => resultRoot);\n        const sourceNodeStack = root2.children.map((id) => protocolNodeById.get(id));\n        while (sourceNodeStack.length) {\n          let parentNode = parentNodeStack.pop();\n          const sourceNode = sourceNodeStack.pop();\n          if (!sourceNode || !parentNode) {\n            continue;\n          }\n          if (!sourceNode.children) {\n            sourceNode.children = [];\n          }\n          const targetNode = new CPUProfileNode(sourceNode, sampleTime);\n          parentNode.children.push(targetNode);\n          parentNode = targetNode;\n          idToUseForRemovedNode.set(sourceNode.id, parentNode.id);\n          parentNodeStack.push.apply(parentNodeStack, sourceNode.children.map(() => parentNode));\n          sourceNodeStack.push.apply(sourceNodeStack, sourceNode.children.map((id) => protocolNodeById.get(id)));\n          this.#idToParsedNode.set(sourceNode.id, targetNode);\n        }\n        if (this.samples) {\n          this.samples = this.samples.map((id) => idToUseForRemovedNode.get(id));\n        }\n        return resultRoot;\n      }\n      /**\n       * Sorts the samples array using the timestamps array (there is a one\n       * to one matching by index between the two).\n       */\n      sortSamples() {\n        if (!this.timestamps || !this.samples) {\n          return;\n        }\n        const timestamps = this.timestamps;\n        const samples = this.samples;\n        const orderedIndices = timestamps.map((_x, index) => index);\n        orderedIndices.sort((a, b) => timestamps[a] - timestamps[b]);\n        this.timestamps = [];\n        this.samples = [];\n        for (let i = 0; i < orderedIndices.length; i++) {\n          const orderedIndex = orderedIndices[i];\n          this.timestamps.push(timestamps[orderedIndex]);\n          this.samples.push(samples[orderedIndex]);\n        }\n      }\n      /**\n       * Fills in timestamps and/or time deltas from legacy profiles where\n       * they could be missing.\n       */\n      normalizeTimestamps() {\n        if (!this.samples) {\n          return;\n        }\n        let timestamps = this.timestamps;\n        if (!timestamps) {\n          const profileStartTime = this.profileStartTime;\n          const interval = (this.profileEndTime - profileStartTime) / this.samples.length;\n          timestamps = new Array(this.samples.length + 1);\n          for (let i = 0; i < timestamps.length; ++i) {\n            timestamps[i] = profileStartTime + i * interval;\n          }\n          this.timestamps = timestamps;\n          return;\n        }\n        for (let i = 0; i < timestamps.length; ++i) {\n          timestamps[i] /= 1e3;\n        }\n        if (this.samples.length === timestamps.length) {\n          const lastTimestamp = timestamps.at(-1) || 0;\n          const averageIntervalTime = (lastTimestamp - timestamps[0]) / (timestamps.length - 1);\n          this.timestamps.push(lastTimestamp + averageIntervalTime);\n        }\n        this.profileStartTime = timestamps.at(0) || this.profileStartTime;\n        this.profileEndTime = timestamps.at(-1) || this.profileEndTime;\n      }\n      /**\n       * Some nodes do not refer to JS samples but to V8 system tasks, AKA\n       * \"meta\" nodes. This function extracts those nodes from the profile.\n       */\n      extractMetaNodes() {\n        const topLevelNodes = this.profileHead.children;\n        for (let i = 0; i < topLevelNodes.length && !(this.gcNode && this.programNode && this.idleNode); i++) {\n          const node = topLevelNodes[i];\n          if (node.functionName === \"(garbage collector)\") {\n            this.gcNode = node;\n          } else if (node.functionName === \"(program)\") {\n            this.programNode = node;\n          } else if (node.functionName === \"(idle)\") {\n            this.idleNode = node;\n          }\n        }\n      }\n      fixMissingSamples() {\n        const samples = this.samples;\n        if (!samples) {\n          return;\n        }\n        const samplesCount = samples.length;\n        if (!this.programNode || samplesCount < 3) {\n          return;\n        }\n        const idToNode = this.#idToParsedNode;\n        const programNodeId = this.programNode.id;\n        const gcNodeId = this.gcNode ? this.gcNode.id : -1;\n        const idleNodeId = this.idleNode ? this.idleNode.id : -1;\n        let prevNodeId = samples[0];\n        let nodeId = samples[1];\n        for (let sampleIndex = 1; sampleIndex < samplesCount - 1; sampleIndex++) {\n          const nextNodeId = samples[sampleIndex + 1];\n          const prevNode = idToNode.get(prevNodeId);\n          const nextNode = idToNode.get(nextNodeId);\n          if (prevNodeId === void 0 || nextNodeId === void 0 || !prevNode || !nextNode) {\n            console.error(`Unexpectedly found undefined nodes: ${prevNodeId} ${nextNodeId}`);\n            continue;\n          }\n          if (nodeId === programNodeId && !isSystemNode(prevNodeId) && !isSystemNode(nextNodeId) && bottomNode(prevNode) === bottomNode(nextNode)) {\n            samples[sampleIndex] = prevNodeId;\n          }\n          prevNodeId = nodeId;\n          nodeId = nextNodeId;\n        }\n        function bottomNode(node) {\n          while (node.parent?.parent) {\n            node = node.parent;\n          }\n          return node;\n        }\n        __name(bottomNode, \"bottomNode\");\n        function isSystemNode(nodeId2) {\n          return nodeId2 === programNodeId || nodeId2 === gcNodeId || nodeId2 === idleNodeId;\n        }\n        __name(isSystemNode, \"isSystemNode\");\n      }\n      /**\n       * Traverses the call tree derived from the samples calling back when a call is opened\n       * and when it's closed\n       */\n      forEachFrame(openFrameCallback, closeFrameCallback, startTime, stopTime) {\n        if (!this.profileHead || !this.samples) {\n          return;\n        }\n        startTime = startTime || 0;\n        stopTime = stopTime || Infinity;\n        const samples = this.samples;\n        const timestamps = this.timestamps;\n        const idToNode = this.#idToParsedNode;\n        const gcNode = this.gcNode;\n        const samplesCount = samples.length;\n        const startIndex = ArrayUtilities_exports.lowerBound(timestamps, startTime, ArrayUtilities_exports.DEFAULT_COMPARATOR);\n        let stackTop = 0;\n        const stackNodes = [];\n        let prevId = this.profileHead.id;\n        let sampleTime;\n        let gcParentNode = null;\n        const stackDepth = this.maxDepth + 3;\n        if (!this.#stackStartTimes) {\n          this.#stackStartTimes = new Array(stackDepth);\n        }\n        const stackStartTimes = this.#stackStartTimes;\n        if (!this.#stackChildrenDuration) {\n          this.#stackChildrenDuration = new Array(stackDepth);\n        }\n        const stackChildrenDuration = this.#stackChildrenDuration;\n        let node;\n        let sampleIndex;\n        for (sampleIndex = startIndex; sampleIndex < samplesCount; sampleIndex++) {\n          sampleTime = timestamps[sampleIndex];\n          if (sampleTime >= stopTime) {\n            break;\n          }\n          const id = samples[sampleIndex];\n          if (id === prevId) {\n            continue;\n          }\n          node = idToNode.get(id);\n          let prevNode = idToNode.get(prevId) || null;\n          if (!prevNode) {\n            continue;\n          }\n          if (gcNode && node === gcNode) {\n            gcParentNode = prevNode;\n            openFrameCallback(gcParentNode.depth + 1, gcNode, sampleIndex, sampleTime);\n            stackStartTimes[++stackTop] = sampleTime;\n            stackChildrenDuration[stackTop] = 0;\n            prevId = id;\n            continue;\n          }\n          if (gcNode && prevNode === gcNode && gcParentNode) {\n            const start = stackStartTimes[stackTop];\n            const duration = sampleTime - start;\n            stackChildrenDuration[stackTop - 1] += duration;\n            closeFrameCallback(gcParentNode.depth + 1, gcNode, sampleIndex, start, duration, duration - stackChildrenDuration[stackTop]);\n            --stackTop;\n            prevNode = gcParentNode;\n            prevId = prevNode.id;\n            gcParentNode = null;\n          }\n          while (node && node.depth > prevNode.depth) {\n            stackNodes.push(node);\n            node = node.parent;\n          }\n          while (prevNode && prevNode !== node) {\n            const start = stackStartTimes[stackTop];\n            const duration = sampleTime - start;\n            stackChildrenDuration[stackTop - 1] += duration;\n            closeFrameCallback(prevNode.depth, prevNode, sampleIndex, start, duration, duration - stackChildrenDuration[stackTop]);\n            --stackTop;\n            if (node && node.depth === prevNode.depth) {\n              stackNodes.push(node);\n              node = node.parent;\n            }\n            prevNode = prevNode.parent;\n          }\n          while (stackNodes.length) {\n            const currentNode = stackNodes.pop();\n            if (!currentNode) {\n              break;\n            }\n            node = currentNode;\n            openFrameCallback(currentNode.depth, currentNode, sampleIndex, sampleTime);\n            stackStartTimes[++stackTop] = sampleTime;\n            stackChildrenDuration[stackTop] = 0;\n          }\n          prevId = id;\n        }\n        sampleTime = timestamps[sampleIndex] || this.profileEndTime;\n        if (node && gcParentNode && idToNode.get(prevId) === gcNode) {\n          const start = stackStartTimes[stackTop];\n          const duration = sampleTime - start;\n          stackChildrenDuration[stackTop - 1] += duration;\n          closeFrameCallback(gcParentNode.depth + 1, node, sampleIndex, start, duration, duration - stackChildrenDuration[stackTop]);\n          --stackTop;\n          prevId = gcParentNode.id;\n        }\n        for (let node2 = idToNode.get(prevId); node2?.parent; node2 = node2.parent) {\n          const start = stackStartTimes[stackTop];\n          const duration = sampleTime - start;\n          stackChildrenDuration[stackTop - 1] += duration;\n          closeFrameCallback(node2.depth, node2, sampleIndex, start, duration, duration - stackChildrenDuration[stackTop]);\n          --stackTop;\n        }\n      }\n      /**\n       * Returns the node that corresponds to a given index of a sample.\n       */\n      nodeByIndex(index) {\n        return this.samples && this.#idToParsedNode.get(this.samples[index]) || null;\n      }\n      /**\n       * Returns the node that corresponds to a given node id.\n       */\n      nodeById(nodeId) {\n        return this.#idToParsedNode.get(nodeId) || null;\n      }\n      nodes() {\n        if (!this.#idToParsedNode) {\n          return null;\n        }\n        return [...this.#idToParsedNode.values()];\n      }\n    };\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/cpu_profile/cpu_profile.js\nvar init_cpu_profile = __esm({\n  \"node_modules/@paulirish/trace_engine/models/cpu_profile/cpu_profile.js\"() {\n    init_process_global();\n    init_CPUProfileDataModel();\n    init_ProfileTreeModel();\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/handlers/SamplesHandler.js\nvar SamplesHandler_exports = {};\n__export(SamplesHandler_exports, {\n  data: () => data7,\n  finalize: () => finalize7,\n  getProfileCallFunctionName: () => getProfileCallFunctionName,\n  handleEvent: () => handleEvent7,\n  reset: () => reset7\n});\nfunction parseCPUProfileData(parseOptions) {\n  for (const [processId, profiles] of preprocessedData) {\n    for (const [profileId, preProcessedData] of profiles) {\n      let buildProfileCallsForCPUProfile = function() {\n        profileModel.forEachFrame(openFrameCallback, closeFrameCallback);\n        function openFrameCallback(depth, node, sampleIndex, timeStampMilliseconds) {\n          if (threadId === void 0) {\n            return;\n          }\n          const ts = Timing_exports3.milliToMicro(Timing_exports.Milli(timeStampMilliseconds));\n          const nodeId = node.id;\n          const profileCall = Trace_exports.makeProfileCall(node, profileId, sampleIndex, ts, processId, threadId);\n          finalizedData.profileCalls.push(profileCall);\n          indexStack.push(finalizedData.profileCalls.length - 1);\n          const traceEntryNode = TreeHelpers_exports.makeEmptyTraceEntryNode(profileCall, nodeId);\n          entryToNode.set(profileCall, traceEntryNode);\n          traceEntryNode.depth = depth;\n          if (indexStack.length === 1) {\n            finalizedData.profileTree?.roots.add(traceEntryNode);\n          }\n        }\n        __name(openFrameCallback, \"openFrameCallback\");\n        function closeFrameCallback(_depth, _node, _sampleIndex, _timeStampMillis, durMs, selfTimeMs) {\n          const profileCallIndex = indexStack.pop();\n          const profileCall = profileCallIndex !== void 0 && finalizedData.profileCalls[profileCallIndex];\n          if (!profileCall) {\n            return;\n          }\n          const { callFrame, ts, pid, tid } = profileCall;\n          const traceEntryNode = entryToNode.get(profileCall);\n          if (callFrame === void 0 || ts === void 0 || pid === void 0 || profileId === void 0 || tid === void 0 || traceEntryNode === void 0) {\n            return;\n          }\n          const dur = Timing_exports3.milliToMicro(Timing_exports.Milli(durMs));\n          const selfTime = Timing_exports3.milliToMicro(Timing_exports.Milli(selfTimeMs));\n          profileCall.dur = dur;\n          traceEntryNode.selfTime = selfTime;\n          const parentIndex = indexStack.at(-1);\n          const parent = parentIndex !== void 0 && finalizedData.profileCalls.at(parentIndex);\n          const parentNode = parent && entryToNode.get(parent);\n          if (!parentNode) {\n            return;\n          }\n          traceEntryNode.parent = parentNode;\n          parentNode.children.push(traceEntryNode);\n        }\n        __name(closeFrameCallback, \"closeFrameCallback\");\n      };\n      __name(buildProfileCallsForCPUProfile, \"buildProfileCallsForCPUProfile\");\n      const threadId = preProcessedData.threadId;\n      if (!preProcessedData.rawProfile.nodes.length || threadId === void 0) {\n        continue;\n      }\n      const indexStack = [];\n      const profileModel = new CPUProfileDataModel_exports.CPUProfileDataModel(preProcessedData.rawProfile);\n      const profileTree = TreeHelpers_exports.makeEmptyTraceEntryTree();\n      profileTree.maxDepth = profileModel.maxDepth;\n      const finalizedData = {\n        rawProfile: preProcessedData.rawProfile,\n        parsedProfile: profileModel,\n        profileCalls: [],\n        profileTree,\n        profileId\n      };\n      const dataByThread = MapUtilities_exports.getWithDefault(profilesInProcess, processId, () => /* @__PURE__ */ new Map());\n      dataByThread.set(threadId, finalizedData);\n      if (parseOptions.isCPUProfile) {\n        buildProfileCallsForCPUProfile();\n      }\n    }\n  }\n}\nfunction reset7() {\n  preprocessedData = /* @__PURE__ */ new Map();\n  profilesInProcess = /* @__PURE__ */ new Map();\n  entryToNode = /* @__PURE__ */ new Map();\n}\nfunction handleEvent7(event) {\n  if (TraceEvents_exports.isSyntheticCpuProfile(event)) {\n    const profileData = getOrCreatePreProcessedData(event.pid, event.id);\n    profileData.rawProfile = event.args.data.cpuProfile;\n    profileData.threadId = event.tid;\n    return;\n  }\n  if (TraceEvents_exports.isProfile(event)) {\n    const profileData = getOrCreatePreProcessedData(event.pid, event.id);\n    profileData.rawProfile.startTime = event.ts;\n    profileData.threadId = event.tid;\n    return;\n  }\n  if (TraceEvents_exports.isProfileChunk(event)) {\n    const profileData = getOrCreatePreProcessedData(event.pid, event.id);\n    const cdpProfile = profileData.rawProfile;\n    const nodesAndSamples = event.args?.data?.cpuProfile || { samples: [] };\n    const samples = nodesAndSamples?.samples || [];\n    const traceIds = event.args?.data?.cpuProfile?.trace_ids;\n    for (const n of nodesAndSamples?.nodes || []) {\n      const lineNumber = typeof n.callFrame.lineNumber === \"undefined\" ? -1 : n.callFrame.lineNumber;\n      const columnNumber = typeof n.callFrame.columnNumber === \"undefined\" ? -1 : n.callFrame.columnNumber;\n      const scriptId = String(n.callFrame.scriptId);\n      const url = n.callFrame.url || \"\";\n      const node = {\n        ...n,\n        callFrame: {\n          ...n.callFrame,\n          url,\n          lineNumber,\n          columnNumber,\n          scriptId\n        }\n      };\n      cdpProfile.nodes.push(node);\n    }\n    const timeDeltas = event.args.data?.timeDeltas || [];\n    const lines = event.args.data?.lines || Array(samples.length).fill(0);\n    cdpProfile.samples?.push(...samples);\n    cdpProfile.timeDeltas?.push(...timeDeltas);\n    cdpProfile.lines?.push(...lines);\n    if (traceIds) {\n      cdpProfile.traceIds ??= {};\n      for (const key in traceIds) {\n        cdpProfile.traceIds[key] = traceIds[key];\n      }\n    }\n    if (cdpProfile.samples && cdpProfile.timeDeltas && cdpProfile.samples.length !== cdpProfile.timeDeltas.length) {\n      console.error(\"Failed to parse CPU profile.\");\n      return;\n    }\n    if (!cdpProfile.endTime && cdpProfile.timeDeltas) {\n      const timeDeltas2 = cdpProfile.timeDeltas;\n      cdpProfile.endTime = timeDeltas2.reduce((x, y) => x + y, cdpProfile.startTime);\n    }\n    return;\n  }\n}\nasync function finalize7(parseOptions = {}) {\n  parseCPUProfileData(parseOptions);\n}\nfunction data7() {\n  return {\n    profilesInProcess,\n    entryToNode\n  };\n}\nfunction getOrCreatePreProcessedData(processId, profileId) {\n  const profileById = MapUtilities_exports.getWithDefault(preprocessedData, processId, () => /* @__PURE__ */ new Map());\n  return MapUtilities_exports.getWithDefault(profileById, profileId, () => ({\n    rawProfile: {\n      startTime: 0,\n      endTime: 0,\n      nodes: [],\n      samples: [],\n      timeDeltas: [],\n      lines: []\n    },\n    profileId\n  }));\n}\nfunction getProfileCallFunctionName(data31, entry) {\n  const profile = data31.profilesInProcess.get(entry.pid)?.get(entry.tid);\n  const node = profile?.parsedProfile.nodeById(entry.nodeId);\n  if (node?.functionName) {\n    return node.functionName;\n  }\n  return entry.callFrame.functionName;\n}\nvar profilesInProcess, entryToNode, preprocessedData;\nvar init_SamplesHandler = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/handlers/SamplesHandler.js\"() {\n    init_process_global();\n    init_platform();\n    init_cpu_profile();\n    init_helpers2();\n    init_types2();\n    profilesInProcess = /* @__PURE__ */ new Map();\n    entryToNode = /* @__PURE__ */ new Map();\n    preprocessedData = /* @__PURE__ */ new Map();\n    __name(parseCPUProfileData, \"parseCPUProfileData\");\n    __name(reset7, \"reset\");\n    __name(handleEvent7, \"handleEvent\");\n    __name(finalize7, \"finalize\");\n    __name(data7, \"data\");\n    __name(getOrCreatePreProcessedData, \"getOrCreatePreProcessedData\");\n    __name(getProfileCallFunctionName, \"getProfileCallFunctionName\");\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/handlers/RendererHandler.js\nvar RendererHandler_exports = {};\n__export(RendererHandler_exports, {\n  assignIsMainFrame: () => assignIsMainFrame,\n  assignMeta: () => assignMeta,\n  assignOrigin: () => assignOrigin,\n  assignThreadName: () => assignThreadName,\n  buildHierarchy: () => buildHierarchy,\n  data: () => data8,\n  deps: () => deps3,\n  finalize: () => finalize8,\n  handleEvent: () => handleEvent8,\n  handleUserConfig: () => handleUserConfig2,\n  makeCompleteEvent: () => makeCompleteEvent,\n  reset: () => reset8,\n  sanitizeProcesses: () => sanitizeProcesses,\n  sanitizeThreads: () => sanitizeThreads\n});\nfunction handleUserConfig2(userConfig) {\n  config = userConfig;\n}\nfunction reset8() {\n  processes = /* @__PURE__ */ new Map();\n  entryToNode2 = /* @__PURE__ */ new Map();\n  entityMappings2 = {\n    eventsByEntity: /* @__PURE__ */ new Map(),\n    entityByEvent: /* @__PURE__ */ new Map(),\n    createdEntityCache: /* @__PURE__ */ new Map(),\n    entityByUrlCache: /* @__PURE__ */ new Map()\n  };\n  completeEventStack = [];\n  compositorTileWorkers = [];\n}\nfunction handleEvent8(event) {\n  if (TraceEvents_exports.isThreadName(event) && event.args.name?.startsWith(\"CompositorTileWorker\")) {\n    compositorTileWorkers.push({\n      pid: event.pid,\n      tid: event.tid\n    });\n  }\n  if (TraceEvents_exports.isBegin(event) || TraceEvents_exports.isEnd(event)) {\n    const process5 = getOrCreateRendererProcess(processes, event.pid);\n    const thread = getOrCreateRendererThread(process5, event.tid);\n    const completeEvent = makeCompleteEvent(event);\n    if (!completeEvent) {\n      return;\n    }\n    thread.entries.push(completeEvent);\n    return;\n  }\n  if (TraceEvents_exports.isInstant(event) || TraceEvents_exports.isComplete(event)) {\n    const process5 = getOrCreateRendererProcess(processes, event.pid);\n    const thread = getOrCreateRendererThread(process5, event.tid);\n    thread.entries.push(event);\n  }\n  if (TraceEvents_exports.isLayout(event)) {\n    const process5 = getOrCreateRendererProcess(processes, event.pid);\n    const thread = getOrCreateRendererThread(process5, event.tid);\n    thread.layoutEvents.push(event);\n  }\n  if (TraceEvents_exports.isRecalcStyle(event)) {\n    const process5 = getOrCreateRendererProcess(processes, event.pid);\n    const thread = getOrCreateRendererThread(process5, event.tid);\n    thread.recalcStyleEvents.push(event);\n  }\n}\nasync function finalize8() {\n  const { mainFrameId: mainFrameId2, rendererProcessesByFrame, threadsInProcess: threadsInProcess2 } = data5();\n  entityMappings2 = data6().entityMappings;\n  assignMeta(processes, mainFrameId2, rendererProcessesByFrame, threadsInProcess2);\n  sanitizeProcesses(processes);\n  buildHierarchy(processes);\n  sanitizeThreads(processes);\n}\nfunction data8() {\n  return {\n    processes,\n    compositorTileWorkers: gatherCompositorThreads(),\n    entryToNode: entryToNode2,\n    entityMappings: {\n      entityByEvent: entityMappings2.entityByEvent,\n      eventsByEntity: entityMappings2.eventsByEntity,\n      createdEntityCache: entityMappings2.createdEntityCache,\n      entityByUrlCache: entityMappings2.entityByUrlCache\n    }\n  };\n}\nfunction gatherCompositorThreads() {\n  const threadsByProcess = /* @__PURE__ */ new Map();\n  for (const worker of compositorTileWorkers) {\n    const byProcess = threadsByProcess.get(worker.pid) || [];\n    byProcess.push(worker.tid);\n    threadsByProcess.set(worker.pid, byProcess);\n  }\n  return threadsByProcess;\n}\nfunction assignMeta(processes2, mainFrameId2, rendererProcessesByFrame, threadsInProcess2) {\n  assignOrigin(processes2, rendererProcessesByFrame);\n  assignIsMainFrame(processes2, mainFrameId2, rendererProcessesByFrame);\n  assignThreadName(processes2, threadsInProcess2);\n}\nfunction assignOrigin(processes2, rendererProcessesByFrame) {\n  for (const renderProcessesByPid of rendererProcessesByFrame.values()) {\n    for (const [pid, processWindows] of renderProcessesByPid) {\n      for (const processInfo of processWindows.flat()) {\n        const process5 = getOrCreateRendererProcess(processes2, pid);\n        if (process5.url === null || process5.url === \"about:blank\") {\n          try {\n            new URL(processInfo.frame.url);\n            process5.url = processInfo.frame.url;\n          } catch {\n            process5.url = null;\n          }\n        }\n      }\n    }\n  }\n}\nfunction assignIsMainFrame(processes2, mainFrameId2, rendererProcessesByFrame) {\n  for (const [frameId, renderProcessesByPid] of rendererProcessesByFrame) {\n    for (const [pid] of renderProcessesByPid) {\n      const process5 = getOrCreateRendererProcess(processes2, pid);\n      if (frameId === mainFrameId2) {\n        process5.isOnMainFrame = true;\n      }\n    }\n  }\n}\nfunction assignThreadName(processes2, threadsInProcess2) {\n  for (const [pid, process5] of processes2) {\n    for (const [tid, threadInfo] of threadsInProcess2.get(pid) ?? []) {\n      const thread = getOrCreateRendererThread(process5, tid);\n      thread.name = threadInfo?.args.name ?? `${tid}`;\n    }\n  }\n}\nfunction sanitizeProcesses(processes2) {\n  const auctionWorklets = data4().worklets;\n  const metaData = data5();\n  if (metaData.traceIsGeneric) {\n    return;\n  }\n  for (const [pid, process5] of processes2) {\n    if (process5.url === null) {\n      const maybeWorklet = auctionWorklets.get(pid);\n      if (maybeWorklet) {\n        process5.url = maybeWorklet.host;\n      } else {\n        processes2.delete(pid);\n      }\n      continue;\n    }\n  }\n}\nfunction sanitizeThreads(processes2) {\n  for (const [, process5] of processes2) {\n    for (const [tid, thread] of process5.threads) {\n      if (!thread.tree?.roots.size) {\n        process5.threads.delete(tid);\n      }\n    }\n  }\n}\nfunction buildHierarchy(processes2, options) {\n  const samplesData = data7();\n  for (const [pid, process5] of processes2) {\n    for (const [tid, thread] of process5.threads) {\n      if (!thread.entries.length) {\n        thread.tree = TreeHelpers_exports.makeEmptyTraceEntryTree();\n        continue;\n      }\n      Trace_exports.sortTraceEventsInPlace(thread.entries);\n      const samplesDataForThread = samplesData.profilesInProcess.get(pid)?.get(tid);\n      if (samplesDataForThread) {\n        const cpuProfile = samplesDataForThread.parsedProfile;\n        const samplesIntegrator = cpuProfile && new SamplesIntegrator_exports.SamplesIntegrator(cpuProfile, samplesDataForThread.profileId, pid, tid, config);\n        const profileCalls = samplesIntegrator?.buildProfileCalls(thread.entries);\n        if (samplesIntegrator && profileCalls) {\n          thread.entries = Trace_exports.mergeEventsInOrder(thread.entries, profileCalls);\n          thread.profileCalls = profileCalls;\n          const jsSamples = samplesIntegrator.jsSampleEvents;\n          if (jsSamples.length) {\n            thread.entries = Trace_exports.mergeEventsInOrder(thread.entries, jsSamples);\n          }\n        }\n      }\n      const treeData = TreeHelpers_exports.treify(thread.entries, options);\n      thread.tree = treeData.tree;\n      for (const [entry, node] of treeData.entryToNode) {\n        entryToNode2.set(entry, node);\n        addEventToEntityMapping(entry, entityMappings2);\n      }\n    }\n  }\n}\nfunction makeCompleteEvent(event) {\n  if (TraceEvents_exports.isEnd(event)) {\n    const beginEvent = completeEventStack.pop();\n    if (!beginEvent) {\n      return null;\n    }\n    if (beginEvent.name !== event.name || beginEvent.cat !== event.cat) {\n      console.error(\"Begin/End events mismatch at \" + beginEvent.ts + \" (\" + beginEvent.name + \") vs. \" + event.ts + \" (\" + event.name + \")\");\n      return null;\n    }\n    beginEvent.dur = Timing_exports.Micro(event.ts - beginEvent.ts);\n    return null;\n  }\n  const syntheticComplete = {\n    ...event,\n    ph: TraceEvents_exports.Phase.COMPLETE,\n    dur: Timing_exports.Micro(0)\n  };\n  completeEventStack.push(syntheticComplete);\n  return syntheticComplete;\n}\nfunction deps3() {\n  return [\"Meta\", \"Samples\", \"AuctionWorklets\", \"NetworkRequests\"];\n}\nvar processes, entityMappings2, compositorTileWorkers, entryToNode2, completeEventStack, config, makeRendererProcess, makeRendererThread, getOrCreateRendererProcess, getOrCreateRendererThread;\nvar init_RendererHandler = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/handlers/RendererHandler.js\"() {\n    init_process_global();\n    init_platform();\n    init_helpers2();\n    init_types2();\n    init_AuctionWorkletsHandler();\n    init_helpers();\n    init_MetaHandler();\n    init_NetworkRequestsHandler();\n    init_SamplesHandler();\n    processes = /* @__PURE__ */ new Map();\n    entityMappings2 = {\n      eventsByEntity: /* @__PURE__ */ new Map(),\n      entityByEvent: /* @__PURE__ */ new Map(),\n      createdEntityCache: /* @__PURE__ */ new Map(),\n      entityByUrlCache: /* @__PURE__ */ new Map()\n    };\n    compositorTileWorkers = Array();\n    entryToNode2 = /* @__PURE__ */ new Map();\n    completeEventStack = [];\n    config = Configuration_exports.defaults();\n    makeRendererProcess = /* @__PURE__ */ __name(() => ({\n      url: null,\n      isOnMainFrame: false,\n      threads: /* @__PURE__ */ new Map()\n    }), \"makeRendererProcess\");\n    makeRendererThread = /* @__PURE__ */ __name(() => ({\n      name: null,\n      entries: [],\n      profileCalls: [],\n      layoutEvents: [],\n      recalcStyleEvents: []\n    }), \"makeRendererThread\");\n    getOrCreateRendererProcess = /* @__PURE__ */ __name((processes2, pid) => {\n      return MapUtilities_exports.getWithDefault(processes2, pid, makeRendererProcess);\n    }, \"getOrCreateRendererProcess\");\n    getOrCreateRendererThread = /* @__PURE__ */ __name((process5, tid) => {\n      return MapUtilities_exports.getWithDefault(process5.threads, tid, makeRendererThread);\n    }, \"getOrCreateRendererThread\");\n    __name(handleUserConfig2, \"handleUserConfig\");\n    __name(reset8, \"reset\");\n    __name(handleEvent8, \"handleEvent\");\n    __name(finalize8, \"finalize\");\n    __name(data8, \"data\");\n    __name(gatherCompositorThreads, \"gatherCompositorThreads\");\n    __name(assignMeta, \"assignMeta\");\n    __name(assignOrigin, \"assignOrigin\");\n    __name(assignIsMainFrame, \"assignIsMainFrame\");\n    __name(assignThreadName, \"assignThreadName\");\n    __name(sanitizeProcesses, \"sanitizeProcesses\");\n    __name(sanitizeThreads, \"sanitizeThreads\");\n    __name(buildHierarchy, \"buildHierarchy\");\n    __name(makeCompleteEvent, \"makeCompleteEvent\");\n    __name(deps3, \"deps\");\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/handlers/AsyncJSCallsHandler.js\nvar AsyncJSCallsHandler_exports = {};\n__export(AsyncJSCallsHandler_exports, {\n  data: () => data9,\n  deps: () => deps4,\n  finalize: () => finalize9,\n  handleEvent: () => handleEvent9,\n  reset: () => reset9\n});\nfunction reset9() {\n  schedulerToRunEntryPoints = /* @__PURE__ */ new Map();\n  asyncCallToScheduler = /* @__PURE__ */ new Map();\n  taskScheduleForTaskRunEvent = /* @__PURE__ */ new Map();\n  runEntryPointToScheduler = /* @__PURE__ */ new Map();\n}\nfunction handleEvent9(_) {\n}\nasync function finalize9() {\n  const { flows: flows2 } = data3();\n  const { entryToNode: entryToNode4 } = data8();\n  for (const flow of flows2) {\n    let maybeAsyncTaskScheduled = flow.at(0);\n    if (!maybeAsyncTaskScheduled) {\n      continue;\n    }\n    if (TraceEvents_exports.isDebuggerAsyncTaskRun(maybeAsyncTaskScheduled)) {\n      maybeAsyncTaskScheduled = taskScheduleForTaskRunEvent.get(maybeAsyncTaskScheduled);\n    }\n    if (!maybeAsyncTaskScheduled || !TraceEvents_exports.isDebuggerAsyncTaskScheduled(maybeAsyncTaskScheduled)) {\n      continue;\n    }\n    const taskName = maybeAsyncTaskScheduled.args.taskName;\n    const asyncTaskRun = flow.at(1);\n    if (!asyncTaskRun || !TraceEvents_exports.isDebuggerAsyncTaskRun(asyncTaskRun)) {\n      continue;\n    }\n    taskScheduleForTaskRunEvent.set(asyncTaskRun, maybeAsyncTaskScheduled);\n    const asyncCaller = findNearestJSAncestor(maybeAsyncTaskScheduled, entryToNode4);\n    const asyncEntryPoint = findFirstJsInvocationForAsyncTaskRun(asyncTaskRun, entryToNode4);\n    runEntryPointToScheduler.set(asyncEntryPoint || asyncTaskRun, { taskName, scheduler: asyncCaller || maybeAsyncTaskScheduled });\n    if (!asyncCaller || !asyncEntryPoint) {\n      continue;\n    }\n    const entryPoints = MapUtilities_exports.getWithDefault(schedulerToRunEntryPoints, asyncCaller, () => []);\n    entryPoints.push(asyncEntryPoint);\n    const scheduledProfileCalls = findFirstJSCallsForAsyncTaskRun(asyncTaskRun, entryToNode4);\n    for (const call of scheduledProfileCalls) {\n      asyncCallToScheduler.set(call, { taskName, scheduler: asyncCaller });\n    }\n  }\n}\nfunction findNearestJSAncestor(asyncTaskScheduled, entryToNode4) {\n  let node = entryToNode4.get(asyncTaskScheduled)?.parent;\n  while (node) {\n    if (TraceEvents_exports.isProfileCall(node.entry) || acceptJSInvocationsPredicate(node.entry)) {\n      return node.entry;\n    }\n    node = node.parent;\n  }\n  return null;\n}\nfunction acceptJSInvocationsPredicate(event) {\n  const eventIsConsoleRunTask = TraceEvents_exports.isConsoleRunTask(event);\n  const eventIsV8EntryPoint = event.name.startsWith(\"v8\") || event.name.startsWith(\"V8\");\n  return TraceEvents_exports.isJSInvocationEvent(event) && (eventIsConsoleRunTask || !eventIsV8EntryPoint);\n}\nfunction findFirstJsInvocationForAsyncTaskRun(asyncTaskRun, entryToNode4) {\n  return findFirstDescendantsOfType(asyncTaskRun, entryToNode4, acceptJSInvocationsPredicate, TraceEvents_exports.isDebuggerAsyncTaskRun).at(0);\n}\nfunction findFirstJSCallsForAsyncTaskRun(asyncTaskRun, entryToNode4) {\n  return findFirstDescendantsOfType(asyncTaskRun, entryToNode4, TraceEvents_exports.isProfileCall, TraceEvents_exports.isDebuggerAsyncTaskRun);\n}\nfunction findFirstDescendantsOfType(root2, entryToNode4, predicateAccept, predicateIgnore) {\n  const node = entryToNode4.get(root2);\n  if (!node) {\n    return [];\n  }\n  const childrenGroups = [[...node.children]];\n  const firstDescendants = [];\n  for (let i = 0; i < childrenGroups.length; i++) {\n    const siblings = childrenGroups[i];\n    for (let j = 0; j < siblings.length; j++) {\n      const node2 = siblings[j];\n      if (predicateAccept(node2.entry)) {\n        firstDescendants.push(node2.entry);\n      } else if (!predicateIgnore(node2.entry)) {\n        childrenGroups.push([...node2.children]);\n      }\n    }\n  }\n  return firstDescendants;\n}\nfunction data9() {\n  return {\n    schedulerToRunEntryPoints,\n    asyncCallToScheduler,\n    runEntryPointToScheduler\n  };\n}\nfunction deps4() {\n  return [\"Renderer\", \"Flows\"];\n}\nvar schedulerToRunEntryPoints, taskScheduleForTaskRunEvent, asyncCallToScheduler, runEntryPointToScheduler;\nvar init_AsyncJSCallsHandler = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/handlers/AsyncJSCallsHandler.js\"() {\n    init_process_global();\n    init_platform();\n    init_types2();\n    init_FlowsHandler();\n    init_RendererHandler();\n    schedulerToRunEntryPoints = /* @__PURE__ */ new Map();\n    taskScheduleForTaskRunEvent = /* @__PURE__ */ new Map();\n    asyncCallToScheduler = /* @__PURE__ */ new Map();\n    runEntryPointToScheduler = /* @__PURE__ */ new Map();\n    __name(reset9, \"reset\");\n    __name(handleEvent9, \"handleEvent\");\n    __name(finalize9, \"finalize\");\n    __name(findNearestJSAncestor, \"findNearestJSAncestor\");\n    __name(acceptJSInvocationsPredicate, \"acceptJSInvocationsPredicate\");\n    __name(findFirstJsInvocationForAsyncTaskRun, \"findFirstJsInvocationForAsyncTaskRun\");\n    __name(findFirstJSCallsForAsyncTaskRun, \"findFirstJSCallsForAsyncTaskRun\");\n    __name(findFirstDescendantsOfType, \"findFirstDescendantsOfType\");\n    __name(data9, \"data\");\n    __name(deps4, \"deps\");\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/handlers/DOMStatsHandler.js\nvar DOMStatsHandler_exports = {};\n__export(DOMStatsHandler_exports, {\n  data: () => data10,\n  finalize: () => finalize10,\n  handleEvent: () => handleEvent10,\n  reset: () => reset10\n});\nfunction reset10() {\n  domStatsByFrameId = /* @__PURE__ */ new Map();\n}\nfunction handleEvent10(event) {\n  if (!TraceEvents_exports.isDOMStats(event)) {\n    return;\n  }\n  const domStatEvents = MapUtilities_exports.getWithDefault(domStatsByFrameId, event.args.data.frame, () => []);\n  domStatEvents.push(event);\n}\nasync function finalize10() {\n}\nfunction data10() {\n  return { domStatsByFrameId };\n}\nvar domStatsByFrameId;\nvar init_DOMStatsHandler = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/handlers/DOMStatsHandler.js\"() {\n    init_process_global();\n    init_platform();\n    init_types2();\n    domStatsByFrameId = /* @__PURE__ */ new Map();\n    __name(reset10, \"reset\");\n    __name(handleEvent10, \"handleEvent\");\n    __name(finalize10, \"finalize\");\n    __name(data10, \"data\");\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/handlers/UserTimingsHandler.js\nvar UserTimingsHandler_exports = {};\n__export(UserTimingsHandler_exports, {\n  data: () => data11,\n  finalize: () => finalize11,\n  handleEvent: () => handleEvent11,\n  reset: () => reset11,\n  userTimingComparator: () => userTimingComparator\n});\nfunction reset11() {\n  syntheticEvents = [];\n  performanceMeasureEvents = [];\n  performanceMarkEvents = [];\n  consoleTimings = [];\n  timestampEvents = [];\n  measureTraceByTraceId = /* @__PURE__ */ new Map();\n}\nfunction getEventTimings(event) {\n  if (\"dur\" in event) {\n    return { start: event.ts, end: Timing_exports.Micro(event.ts + (event.dur ?? 0)) };\n  }\n  if (TraceEvents_exports.isConsoleTimeStamp(event)) {\n    const { start, end } = event.args.data || {};\n    if (typeof start === \"number\" && typeof end === \"number\") {\n      return { start: Timing_exports.Micro(start), end: Timing_exports.Micro(end) };\n    }\n  }\n  return { start: event.ts, end: event.ts };\n}\nfunction getEventTrack(event) {\n  if (event.cat === \"blink.user_timing\") {\n    const detailString = event.args.data.beginEvent.args?.detail;\n    if (detailString) {\n      const details = Trace_exports.parseDevtoolsDetails(detailString, \"devtools\");\n      if (details && \"track\" in details) {\n        return details.track;\n      }\n    }\n  } else if (TraceEvents_exports.isConsoleTimeStamp(event)) {\n    const track = event.args.data?.track;\n    return typeof track === \"string\" ? track : void 0;\n  }\n  return void 0;\n}\nfunction userTimingComparator(a, b, originalArray) {\n  const { start: aStart, end: aEnd } = getEventTimings(a);\n  const { start: bStart, end: bEnd } = getEventTimings(b);\n  const timeDifference = Trace_exports.compareBeginAndEnd(aStart, bStart, aEnd, bEnd);\n  if (timeDifference) {\n    return timeDifference;\n  }\n  const aTrack = getEventTrack(a);\n  const bTrack = getEventTrack(b);\n  if (aTrack !== bTrack) {\n    return 0;\n  }\n  const aIndex = originalArray.indexOf(a);\n  const bIndex = originalArray.indexOf(b);\n  return bIndex - aIndex;\n}\nfunction handleEvent11(event) {\n  if (ignoredNames.includes(event.name)) {\n    return;\n  }\n  if (TraceEvents_exports.isUserTimingMeasure(event)) {\n    measureTraceByTraceId.set(event.args.traceId, event);\n  }\n  if (TraceEvents_exports.isPerformanceMeasure(event)) {\n    performanceMeasureEvents.push(event);\n    return;\n  }\n  if (TraceEvents_exports.isPerformanceMark(event)) {\n    performanceMarkEvents.push(event);\n  }\n  if (TraceEvents_exports.isConsoleTime(event)) {\n    consoleTimings.push(event);\n  }\n  if (TraceEvents_exports.isConsoleTimeStamp(event)) {\n    timestampEvents.push(event);\n  }\n}\nasync function finalize11() {\n  const asyncEvents = [...performanceMeasureEvents, ...consoleTimings];\n  syntheticEvents = Trace_exports.createMatchedSortedSyntheticEvents(asyncEvents);\n  syntheticEvents = syntheticEvents.sort((a, b) => userTimingComparator(a, b, [...syntheticEvents]));\n  timestampEvents = timestampEvents.sort((a, b) => userTimingComparator(a, b, [...timestampEvents]));\n}\nfunction data11() {\n  return {\n    consoleTimings: syntheticEvents.filter((e) => e.cat === \"blink.console\"),\n    performanceMeasures: syntheticEvents.filter((e) => e.cat === \"blink.user_timing\"),\n    performanceMarks: performanceMarkEvents,\n    timestampEvents,\n    measureTraceByTraceId\n  };\n}\nvar syntheticEvents, measureTraceByTraceId, performanceMeasureEvents, performanceMarkEvents, consoleTimings, timestampEvents, resourceTimingNames, navTimingNames, ignoredNames;\nvar init_UserTimingsHandler = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/handlers/UserTimingsHandler.js\"() {\n    init_process_global();\n    init_helpers2();\n    init_types2();\n    syntheticEvents = [];\n    measureTraceByTraceId = /* @__PURE__ */ new Map();\n    performanceMeasureEvents = [];\n    performanceMarkEvents = [];\n    consoleTimings = [];\n    timestampEvents = [];\n    __name(reset11, \"reset\");\n    resourceTimingNames = [\n      \"workerStart\",\n      \"redirectStart\",\n      \"redirectEnd\",\n      \"fetchStart\",\n      \"domainLookupStart\",\n      \"domainLookupEnd\",\n      \"connectStart\",\n      \"connectEnd\",\n      \"secureConnectionStart\",\n      \"requestStart\",\n      \"responseStart\",\n      \"responseEnd\"\n    ];\n    navTimingNames = [\n      \"navigationStart\",\n      \"unloadEventStart\",\n      \"unloadEventEnd\",\n      \"redirectStart\",\n      \"redirectEnd\",\n      \"fetchStart\",\n      \"commitNavigationEnd\",\n      \"domainLookupStart\",\n      \"domainLookupEnd\",\n      \"connectStart\",\n      \"connectEnd\",\n      \"secureConnectionStart\",\n      \"requestStart\",\n      \"responseStart\",\n      \"responseEnd\",\n      \"domLoading\",\n      \"domInteractive\",\n      \"domContentLoadedEventStart\",\n      \"domContentLoadedEventEnd\",\n      \"domComplete\",\n      \"loadEventStart\",\n      \"loadEventEnd\"\n    ];\n    ignoredNames = [...resourceTimingNames, ...navTimingNames];\n    __name(getEventTimings, \"getEventTimings\");\n    __name(getEventTrack, \"getEventTrack\");\n    __name(userTimingComparator, \"userTimingComparator\");\n    __name(handleEvent11, \"handleEvent\");\n    __name(finalize11, \"finalize\");\n    __name(data11, \"data\");\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/handlers/ExtensionTraceDataHandler.js\nvar ExtensionTraceDataHandler_exports = {};\n__export(ExtensionTraceDataHandler_exports, {\n  data: () => data12,\n  deps: () => deps5,\n  extensionDataInConsoleTimeStamp: () => extensionDataInConsoleTimeStamp,\n  extensionDataInPerformanceTiming: () => extensionDataInPerformanceTiming,\n  extractConsoleAPIExtensionEntries: () => extractConsoleAPIExtensionEntries,\n  extractPerformanceAPIExtensionEntries: () => extractPerformanceAPIExtensionEntries,\n  finalize: () => finalize12,\n  handleEvent: () => handleEvent12,\n  reset: () => reset12\n});\nfunction handleEvent12(_event) {\n}\nfunction reset12() {\n  extensionTrackEntries = [];\n  syntheticConsoleEntriesForTimingsTrack = [];\n  extensionTrackData = [];\n  extensionMarkers = [];\n  entryToNode3 = /* @__PURE__ */ new Map();\n  timeStampByName = /* @__PURE__ */ new Map();\n}\nasync function finalize12() {\n  createExtensionFlameChartEntries();\n}\nfunction createExtensionFlameChartEntries() {\n  const pairedMeasures = data11().performanceMeasures;\n  const marks = data11().performanceMarks;\n  const mergedRawExtensionEvents = Trace_exports.mergeEventsInOrder(pairedMeasures, marks);\n  extractPerformanceAPIExtensionEntries(mergedRawExtensionEvents);\n  extractConsoleAPIExtensionEntries();\n  Trace_exports.sortTraceEventsInPlace(extensionTrackEntries);\n  Extensions_exports2.buildTrackDataFromExtensionEntries(extensionTrackEntries, extensionTrackData, entryToNode3);\n}\nfunction extractConsoleAPIExtensionEntries() {\n  const consoleTimeStamps = data11().timestampEvents;\n  for (const currentTimeStamp of consoleTimeStamps) {\n    if (!currentTimeStamp.args.data) {\n      continue;\n    }\n    const timeStampName = String(currentTimeStamp.args.data.name ?? currentTimeStamp.args.data.message);\n    timeStampByName.set(timeStampName, currentTimeStamp);\n    const { devtoolsObj: extensionData, userDetail } = extensionDataInConsoleTimeStamp(currentTimeStamp);\n    const start = currentTimeStamp.args.data.start;\n    const end = currentTimeStamp.args.data.end;\n    if (!extensionData && !start && !end) {\n      continue;\n    }\n    const startTimeStamp = typeof start === \"number\" ? Timing_exports.Micro(start) : timeStampByName.get(String(start))?.ts;\n    const endTimeStamp = typeof end === \"number\" ? Timing_exports.Micro(end) : timeStampByName.get(String(end))?.ts;\n    if (endTimeStamp !== void 0 && startTimeStamp === void 0) {\n      continue;\n    }\n    const entryStartTime = startTimeStamp ?? currentTimeStamp.ts;\n    const entryEndTime = endTimeStamp ?? currentTimeStamp.ts;\n    if (extensionData) {\n      const unregisteredExtensionEntry = {\n        ...currentTimeStamp,\n        name: timeStampName,\n        cat: \"devtools.extension\",\n        devtoolsObj: extensionData,\n        userDetail,\n        rawSourceEvent: currentTimeStamp,\n        dur: Timing_exports.Micro(entryEndTime - entryStartTime),\n        ts: entryStartTime,\n        ph: TraceEvents_exports.Phase.COMPLETE\n      };\n      const extensionEntry = SyntheticEvents_exports.SyntheticEventsManager.registerSyntheticEvent(unregisteredExtensionEntry);\n      extensionTrackEntries.push(extensionEntry);\n      continue;\n    }\n    const unregisteredSyntheticTimeStamp = {\n      ...currentTimeStamp,\n      name: timeStampName,\n      cat: \"disabled-by-default-v8.inspector\",\n      ph: TraceEvents_exports.Phase.COMPLETE,\n      ts: entryStartTime,\n      dur: Timing_exports.Micro(entryEndTime - entryStartTime),\n      rawSourceEvent: currentTimeStamp\n    };\n    const syntheticTimeStamp = SyntheticEvents_exports.SyntheticEventsManager.registerSyntheticEvent(unregisteredSyntheticTimeStamp);\n    syntheticConsoleEntriesForTimingsTrack.push(syntheticTimeStamp);\n  }\n}\nfunction extractPerformanceAPIExtensionEntries(timings) {\n  for (const timing of timings) {\n    const { devtoolsObj, userDetail } = extensionDataInPerformanceTiming(timing);\n    if (!devtoolsObj) {\n      continue;\n    }\n    const extensionSyntheticEntry = {\n      name: timing.name,\n      ph: Extensions_exports.isExtensionPayloadMarker(devtoolsObj) ? TraceEvents_exports.Phase.INSTANT : TraceEvents_exports.Phase.COMPLETE,\n      pid: timing.pid,\n      tid: timing.tid,\n      ts: timing.ts,\n      dur: timing.dur,\n      cat: \"devtools.extension\",\n      devtoolsObj,\n      userDetail,\n      rawSourceEvent: TraceEvents_exports.isSyntheticUserTiming(timing) ? timing.rawSourceEvent : timing\n    };\n    if (Extensions_exports.isExtensionPayloadMarker(devtoolsObj)) {\n      const extensionMarker = SyntheticEvents_exports.SyntheticEventsManager.registerSyntheticEvent(extensionSyntheticEntry);\n      extensionMarkers.push(extensionMarker);\n      continue;\n    }\n    if (Extensions_exports.isExtensionEntryObj(extensionSyntheticEntry.devtoolsObj)) {\n      const extensionTrackEntry = SyntheticEvents_exports.SyntheticEventsManager.registerSyntheticEvent(extensionSyntheticEntry);\n      extensionTrackEntries.push(extensionTrackEntry);\n      continue;\n    }\n  }\n}\nfunction extensionDataInPerformanceTiming(timing) {\n  const timingDetail = TraceEvents_exports.isPerformanceMark(timing) ? timing.args.data?.detail : timing.args.data.beginEvent.args.detail;\n  if (!timingDetail) {\n    return { devtoolsObj: null, userDetail: null };\n  }\n  const devtoolsObj = Trace_exports.parseDevtoolsDetails(timingDetail, \"devtools\");\n  let userDetail = null;\n  try {\n    userDetail = JSON.parse(timingDetail);\n    delete userDetail.devtools;\n  } catch {\n  }\n  return { devtoolsObj, userDetail };\n}\nfunction extensionDataInConsoleTimeStamp(timeStamp) {\n  if (!timeStamp.args.data || !timeStamp.args.data.track) {\n    return { devtoolsObj: null, userDetail: null };\n  }\n  let userDetail = null;\n  try {\n    userDetail = JSON.parse(timeStamp.args.data?.devtools || '\"\"');\n  } catch {\n  }\n  const devtoolsObj = {\n    // the color is defaulted to primary if it's value isn't one from\n    // the defined palette (see ExtensionUI::extensionEntryColor) so\n    // we don't need to check the value is valid here.\n    color: String(timeStamp.args.data.color),\n    track: String(timeStamp.args.data.track),\n    dataType: \"track-entry\",\n    trackGroup: timeStamp.args.data.trackGroup !== void 0 ? String(timeStamp.args.data.trackGroup) : void 0\n  };\n  return { devtoolsObj, userDetail };\n}\nfunction data12() {\n  return {\n    entryToNode: entryToNode3,\n    extensionTrackData,\n    extensionMarkers,\n    syntheticConsoleEntriesForTimingsTrack\n  };\n}\nfunction deps5() {\n  return [\"UserTimings\"];\n}\nvar extensionTrackEntries, extensionTrackData, extensionMarkers, entryToNode3, timeStampByName, syntheticConsoleEntriesForTimingsTrack;\nvar init_ExtensionTraceDataHandler = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/handlers/ExtensionTraceDataHandler.js\"() {\n    init_process_global();\n    init_helpers2();\n    init_types2();\n    init_UserTimingsHandler();\n    extensionTrackEntries = [];\n    extensionTrackData = [];\n    extensionMarkers = [];\n    entryToNode3 = /* @__PURE__ */ new Map();\n    timeStampByName = /* @__PURE__ */ new Map();\n    syntheticConsoleEntriesForTimingsTrack = [];\n    __name(handleEvent12, \"handleEvent\");\n    __name(reset12, \"reset\");\n    __name(finalize12, \"finalize\");\n    __name(createExtensionFlameChartEntries, \"createExtensionFlameChartEntries\");\n    __name(extractConsoleAPIExtensionEntries, \"extractConsoleAPIExtensionEntries\");\n    __name(extractPerformanceAPIExtensionEntries, \"extractPerformanceAPIExtensionEntries\");\n    __name(extensionDataInPerformanceTiming, \"extensionDataInPerformanceTiming\");\n    __name(extensionDataInConsoleTimeStamp, \"extensionDataInConsoleTimeStamp\");\n    __name(data12, \"data\");\n    __name(deps5, \"deps\");\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/handlers/LayerTreeHandler.js\nvar LayerTreeHandler_exports = {};\n__export(LayerTreeHandler_exports, {\n  data: () => data13,\n  deps: () => deps6,\n  finalize: () => finalize13,\n  handleEvent: () => handleEvent13,\n  reset: () => reset13\n});\nfunction reset13() {\n  paintEvents = [];\n  snapshotEvents = [];\n  paintToSnapshotMap = /* @__PURE__ */ new Map();\n  lastPaintForLayerId = {};\n  currentMainFrameLayerTreeId = null;\n  updateLayerEvents = [];\n  relevantEvents = [];\n}\nfunction handleEvent13(event) {\n  if (TraceEvents_exports.isPaint(event) || TraceEvents_exports.isDisplayListItemListSnapshot(event) || TraceEvents_exports.isUpdateLayer(event) || TraceEvents_exports.isSetLayerId(event)) {\n    relevantEvents.push(event);\n  }\n}\nasync function finalize13() {\n  const metaData = data5();\n  Trace_exports.sortTraceEventsInPlace(relevantEvents);\n  for (const event of relevantEvents) {\n    if (TraceEvents_exports.isSetLayerId(event)) {\n      if (metaData.mainFrameId !== event.args.data.frame) {\n        continue;\n      }\n      currentMainFrameLayerTreeId = event.args.data.layerTreeId;\n    } else if (TraceEvents_exports.isUpdateLayer(event)) {\n      updateLayerEvents.push(event);\n    } else if (TraceEvents_exports.isPaint(event)) {\n      if (!event.args.data.layerId) {\n        continue;\n      }\n      paintEvents.push(event);\n      lastPaintForLayerId[event.args.data.layerId] = event;\n      continue;\n    } else if (TraceEvents_exports.isDisplayListItemListSnapshot(event)) {\n      let lastUpdateLayerEventForThread = null;\n      for (let i = updateLayerEvents.length - 1; i > -1; i--) {\n        const updateEvent = updateLayerEvents[i];\n        if (updateEvent.pid === event.pid && updateEvent.tid === event.tid) {\n          lastUpdateLayerEventForThread = updateEvent;\n          break;\n        }\n      }\n      if (!lastUpdateLayerEventForThread) {\n        continue;\n      }\n      if (lastUpdateLayerEventForThread.args.layerTreeId !== currentMainFrameLayerTreeId) {\n        continue;\n      }\n      const paintEvent = lastPaintForLayerId[lastUpdateLayerEventForThread.args.layerId];\n      if (!paintEvent) {\n        continue;\n      }\n      snapshotEvents.push(event);\n      paintToSnapshotMap.set(paintEvent, event);\n    }\n  }\n}\nfunction data13() {\n  return {\n    paints: paintEvents,\n    snapshots: snapshotEvents,\n    paintsToSnapshots: paintToSnapshotMap\n  };\n}\nfunction deps6() {\n  return [\"Meta\"];\n}\nvar paintEvents, snapshotEvents, paintToSnapshotMap, lastPaintForLayerId, currentMainFrameLayerTreeId, updateLayerEvents, relevantEvents;\nvar init_LayerTreeHandler = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/handlers/LayerTreeHandler.js\"() {\n    init_process_global();\n    init_helpers2();\n    init_types2();\n    init_MetaHandler();\n    paintEvents = [];\n    snapshotEvents = [];\n    paintToSnapshotMap = /* @__PURE__ */ new Map();\n    lastPaintForLayerId = {};\n    currentMainFrameLayerTreeId = null;\n    updateLayerEvents = [];\n    relevantEvents = [];\n    __name(reset13, \"reset\");\n    __name(handleEvent13, \"handleEvent\");\n    __name(finalize13, \"finalize\");\n    __name(data13, \"data\");\n    __name(deps6, \"deps\");\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/handlers/Threads.js\nvar Threads_exports = {};\n__export(Threads_exports, {\n  ThreadType: () => ThreadType,\n  threadsInRenderer: () => threadsInRenderer,\n  threadsInTrace: () => threadsInTrace\n});\nfunction getThreadTypeForRendererThread(pid, thread, auctionWorkletsData) {\n  let threadType = ThreadType.OTHER;\n  if (thread.name === \"CrRendererMain\") {\n    threadType = ThreadType.MAIN_THREAD;\n  } else if (thread.name === \"DedicatedWorker thread\") {\n    threadType = ThreadType.WORKER;\n  } else if (thread.name?.startsWith(\"CompositorTileWorker\")) {\n    threadType = ThreadType.RASTERIZER;\n  } else if (auctionWorkletsData.worklets.has(pid)) {\n    threadType = ThreadType.AUCTION_WORKLET;\n  } else if (thread.name?.startsWith(\"ThreadPool\")) {\n    threadType = ThreadType.THREAD_POOL;\n  }\n  return threadType;\n}\nfunction threadsInRenderer(rendererData, auctionWorkletsData) {\n  const foundThreads = [];\n  if (rendererData.processes.size) {\n    for (const [pid, process5] of rendererData.processes) {\n      for (const [tid, thread] of process5.threads) {\n        if (!thread.tree) {\n          continue;\n        }\n        const threadType = getThreadTypeForRendererThread(pid, thread, auctionWorkletsData);\n        foundThreads.push({\n          name: thread.name,\n          pid,\n          tid,\n          processIsOnMainFrame: process5.isOnMainFrame,\n          entries: thread.entries,\n          tree: thread.tree,\n          type: threadType,\n          entryToNode: rendererData.entryToNode\n        });\n      }\n    }\n  }\n  return foundThreads;\n}\nfunction threadsInTrace(handlerData) {\n  const cached = threadsInHandlerDataCache.get(handlerData);\n  if (cached) {\n    return cached;\n  }\n  const threadsFromRenderer = threadsInRenderer(handlerData.Renderer, handlerData.AuctionWorklets);\n  if (threadsFromRenderer.length) {\n    threadsInHandlerDataCache.set(handlerData, threadsFromRenderer);\n    return threadsFromRenderer;\n  }\n  const foundThreads = [];\n  if (handlerData.Samples.profilesInProcess.size) {\n    for (const [pid, process5] of handlerData.Samples.profilesInProcess) {\n      for (const [tid, thread] of process5) {\n        if (!thread.profileTree) {\n          continue;\n        }\n        foundThreads.push({\n          pid,\n          tid,\n          // CPU Profile threads do not have a name.\n          name: null,\n          entries: thread.profileCalls,\n          // There is no concept of a \"Main Frame\" in a CPU profile.\n          processIsOnMainFrame: false,\n          tree: thread.profileTree,\n          type: ThreadType.CPU_PROFILE,\n          entryToNode: handlerData.Samples.entryToNode\n        });\n      }\n    }\n  }\n  threadsInHandlerDataCache.set(handlerData, foundThreads);\n  return foundThreads;\n}\nvar ThreadType, threadsInHandlerDataCache;\nvar init_Threads = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/handlers/Threads.js\"() {\n    init_process_global();\n    (function(ThreadType2) {\n      ThreadType2[\"MAIN_THREAD\"] = \"MAIN_THREAD\";\n      ThreadType2[\"WORKER\"] = \"WORKER\";\n      ThreadType2[\"RASTERIZER\"] = \"RASTERIZER\";\n      ThreadType2[\"AUCTION_WORKLET\"] = \"AUCTION_WORKLET\";\n      ThreadType2[\"OTHER\"] = \"OTHER\";\n      ThreadType2[\"CPU_PROFILE\"] = \"CPU_PROFILE\";\n      ThreadType2[\"THREAD_POOL\"] = \"THREAD_POOL\";\n    })(ThreadType || (ThreadType = {}));\n    __name(getThreadTypeForRendererThread, \"getThreadTypeForRendererThread\");\n    __name(threadsInRenderer, \"threadsInRenderer\");\n    threadsInHandlerDataCache = /* @__PURE__ */ new WeakMap();\n    __name(threadsInTrace, \"threadsInTrace\");\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/handlers/FramesHandler.js\nvar FramesHandler_exports = {};\n__export(FramesHandler_exports, {\n  LayerPaintEvent: () => LayerPaintEvent,\n  PendingFrame: () => PendingFrame,\n  TimelineFrameBeginFrameQueue: () => TimelineFrameBeginFrameQueue,\n  TimelineFrameModel: () => TimelineFrameModel,\n  data: () => data14,\n  deps: () => deps7,\n  finalize: () => finalize14,\n  framesWithinWindow: () => framesWithinWindow,\n  handleEvent: () => handleEvent14,\n  reset: () => reset14\n});\nfunction isFrameEvent(event) {\n  return TraceEvents_exports.isSetLayerId(event) || TraceEvents_exports.isBeginFrame(event) || TraceEvents_exports.isDroppedFrame(event) || TraceEvents_exports.isRequestMainThreadFrame(event) || TraceEvents_exports.isBeginMainThreadFrame(event) || TraceEvents_exports.isNeedsBeginFrameChanged(event) || // Note that \"Commit\" is the replacement for \"CompositeLayers\" so in a trace\n  // we wouldn't expect to see a combination of these. All \"new\" trace\n  // recordings use \"Commit\", but we can easily support \"CompositeLayers\" too\n  // to not break older traces being imported.\n  TraceEvents_exports.isCommit(event) || TraceEvents_exports.isCompositeLayers(event) || TraceEvents_exports.isActivateLayerTree(event) || TraceEvents_exports.isDrawFrame(event);\n}\nfunction entryIsTopLevel(entry) {\n  const devtoolsTimelineCategory = \"disabled-by-default-devtools.timeline\";\n  return entry.name === TraceEvents_exports.Name.RUN_TASK && entry.cat.includes(devtoolsTimelineCategory);\n}\nfunction reset14() {\n  model = null;\n  relevantFrameEvents = [];\n}\nfunction handleEvent14(event) {\n  if (isFrameEvent(event) || TraceEvents_exports.isLayerTreeHostImplSnapshot(event) || entryIsTopLevel(event) || MAIN_FRAME_MARKERS.has(event.name) || TraceEvents_exports.isPaint(event)) {\n    relevantFrameEvents.push(event);\n  }\n}\nasync function finalize14() {\n  Trace_exports.sortTraceEventsInPlace(relevantFrameEvents);\n  const modelForTrace = new TimelineFrameModel(relevantFrameEvents, data8(), data4(), data5(), data13());\n  model = modelForTrace;\n}\nfunction data14() {\n  return {\n    frames: model?.frames() ?? [],\n    framesById: model?.framesById() ?? {}\n  };\n}\nfunction deps7() {\n  return [\"Meta\", \"Renderer\", \"AuctionWorklets\", \"LayerTree\"];\n}\nfunction framesWithinWindow(frames2, startTime, endTime) {\n  const firstFrame = ArrayUtilities_exports.lowerBound(frames2, startTime || 0, (time, frame) => time - frame.endTime);\n  const lastFrame = ArrayUtilities_exports.lowerBound(frames2, endTime || Infinity, (time, frame) => time - frame.startTime);\n  return frames2.slice(firstFrame, lastFrame);\n}\nvar model, relevantFrameEvents, MAIN_FRAME_MARKERS, TimelineFrameModel, TimelineFrame, LayerPaintEvent, PendingFrame, BeginFrameInfo, TimelineFrameBeginFrameQueue;\nvar init_FramesHandler = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/handlers/FramesHandler.js\"() {\n    init_process_global();\n    init_platform();\n    init_helpers2();\n    init_types2();\n    init_AuctionWorkletsHandler();\n    init_LayerTreeHandler();\n    init_MetaHandler();\n    init_RendererHandler();\n    init_Threads();\n    model = null;\n    relevantFrameEvents = [];\n    __name(isFrameEvent, \"isFrameEvent\");\n    __name(entryIsTopLevel, \"entryIsTopLevel\");\n    MAIN_FRAME_MARKERS = /* @__PURE__ */ new Set([\n      TraceEvents_exports.Name.SCHEDULE_STYLE_RECALCULATION,\n      TraceEvents_exports.Name.INVALIDATE_LAYOUT,\n      TraceEvents_exports.Name.BEGIN_MAIN_THREAD_FRAME,\n      TraceEvents_exports.Name.SCROLL_LAYER\n    ]);\n    __name(reset14, \"reset\");\n    __name(handleEvent14, \"handleEvent\");\n    __name(finalize14, \"finalize\");\n    __name(data14, \"data\");\n    __name(deps7, \"deps\");\n    TimelineFrameModel = class {\n      static {\n        __name(this, \"TimelineFrameModel\");\n      }\n      #frames = [];\n      #frameById = {};\n      #beginFrameQueue = new TimelineFrameBeginFrameQueue();\n      #lastFrame = null;\n      #mainFrameCommitted = false;\n      #mainFrameRequested = false;\n      #lastLayerTree = null;\n      #framePendingActivation = null;\n      #framePendingCommit = null;\n      #lastBeginFrame = null;\n      #lastNeedsBeginFrame = null;\n      #lastTaskBeginTime = null;\n      #layerTreeId = null;\n      #activeProcessId = null;\n      #activeThreadId = null;\n      #layerTreeData;\n      constructor(allEvents, rendererData, auctionWorkletsData, metaData, layerTreeData) {\n        const mainThreads = threadsInRenderer(rendererData, auctionWorkletsData).filter((thread) => {\n          return thread.type === ThreadType.MAIN_THREAD && thread.processIsOnMainFrame;\n        });\n        const threadData = mainThreads.map((thread) => {\n          return {\n            tid: thread.tid,\n            pid: thread.pid,\n            startTime: thread.entries[0].ts\n          };\n        });\n        this.#layerTreeData = layerTreeData;\n        this.#addTraceEvents(allEvents, threadData, metaData.mainFrameId);\n      }\n      framesById() {\n        return this.#frameById;\n      }\n      frames() {\n        return this.#frames;\n      }\n      #handleBeginFrame(startTime, seqId) {\n        if (!this.#lastFrame) {\n          this.#startFrame(startTime, seqId);\n        }\n        this.#lastBeginFrame = startTime;\n        this.#beginFrameQueue.addFrameIfNotExists(seqId, startTime, false, false);\n      }\n      #handleDroppedFrame(startTime, seqId, isPartial) {\n        if (!this.#lastFrame) {\n          this.#startFrame(startTime, seqId);\n        }\n        this.#beginFrameQueue.addFrameIfNotExists(seqId, startTime, true, isPartial);\n        this.#beginFrameQueue.setDropped(seqId, true);\n        this.#beginFrameQueue.setPartial(seqId, isPartial);\n      }\n      #handleDrawFrame(startTime, seqId) {\n        if (!this.#lastFrame) {\n          this.#startFrame(startTime, seqId);\n          return;\n        }\n        if (this.#mainFrameCommitted || !this.#mainFrameRequested) {\n          if (this.#lastNeedsBeginFrame) {\n            const idleTimeEnd = this.#framePendingActivation ? this.#framePendingActivation.triggerTime : this.#lastBeginFrame || this.#lastNeedsBeginFrame;\n            if (idleTimeEnd > this.#lastFrame.startTime) {\n              this.#lastFrame.idle = true;\n              this.#lastBeginFrame = null;\n            }\n            this.#lastNeedsBeginFrame = null;\n          }\n          const framesToVisualize = this.#beginFrameQueue.processPendingBeginFramesOnDrawFrame(seqId);\n          for (const frame of framesToVisualize) {\n            const isLastFrameIdle = this.#lastFrame.idle;\n            this.#startFrame(frame.startTime, seqId);\n            if (isLastFrameIdle && this.#framePendingActivation) {\n              this.#commitPendingFrame();\n            }\n            if (frame.isDropped) {\n              this.#lastFrame.dropped = true;\n            }\n            if (frame.isPartial) {\n              this.#lastFrame.isPartial = true;\n            }\n          }\n        }\n        this.#mainFrameCommitted = false;\n      }\n      #handleActivateLayerTree() {\n        if (!this.#lastFrame) {\n          return;\n        }\n        if (this.#framePendingActivation && !this.#lastNeedsBeginFrame) {\n          this.#commitPendingFrame();\n        }\n      }\n      #handleRequestMainThreadFrame() {\n        if (!this.#lastFrame) {\n          return;\n        }\n        this.#mainFrameRequested = true;\n      }\n      #handleCommit() {\n        if (!this.#framePendingCommit) {\n          return;\n        }\n        this.#framePendingActivation = this.#framePendingCommit;\n        this.#framePendingCommit = null;\n        this.#mainFrameRequested = false;\n        this.#mainFrameCommitted = true;\n      }\n      #handleLayerTreeSnapshot(layerTree) {\n        this.#lastLayerTree = layerTree;\n      }\n      #handleNeedFrameChanged(startTime, needsBeginFrame) {\n        if (needsBeginFrame) {\n          this.#lastNeedsBeginFrame = startTime;\n        }\n      }\n      #startFrame(startTime, seqId) {\n        if (this.#lastFrame) {\n          this.#flushFrame(this.#lastFrame, startTime);\n        }\n        this.#lastFrame = new TimelineFrame(seqId, startTime, Timing_exports.Micro(startTime - data5().traceBounds.min));\n      }\n      #flushFrame(frame, endTime) {\n        frame.setLayerTree(this.#lastLayerTree);\n        frame.setEndTime(endTime);\n        if (this.#lastLayerTree) {\n          this.#lastLayerTree.paints = frame.paints;\n        }\n        const lastFrame = this.#frames[this.#frames.length - 1];\n        if (this.#frames.length && lastFrame && (frame.startTime !== lastFrame.endTime || frame.startTime > frame.endTime)) {\n          console.assert(false, `Inconsistent frame time for frame ${this.#frames.length} (${frame.startTime} - ${frame.endTime})`);\n        }\n        const newFramesLength = this.#frames.push(frame);\n        frame.setIndex(newFramesLength - 1);\n        if (typeof frame.mainFrameId === \"number\") {\n          this.#frameById[frame.mainFrameId] = frame;\n        }\n      }\n      #commitPendingFrame() {\n        if (!this.#framePendingActivation || !this.#lastFrame) {\n          return;\n        }\n        this.#lastFrame.paints = this.#framePendingActivation.paints;\n        this.#lastFrame.mainFrameId = this.#framePendingActivation.mainFrameId;\n        this.#framePendingActivation = null;\n      }\n      #addTraceEvents(events, threadData, mainFrameId2) {\n        let j = 0;\n        this.#activeThreadId = threadData.length && threadData[0].tid || null;\n        this.#activeProcessId = threadData.length && threadData[0].pid || null;\n        for (let i = 0; i < events.length; ++i) {\n          while (j + 1 < threadData.length && threadData[j + 1].startTime <= events[i].ts) {\n            this.#activeThreadId = threadData[++j].tid;\n            this.#activeProcessId = threadData[j].pid;\n          }\n          this.#addTraceEvent(events[i], mainFrameId2);\n        }\n        this.#activeThreadId = null;\n        this.#activeProcessId = null;\n      }\n      #addTraceEvent(event, mainFrameId2) {\n        if (TraceEvents_exports.isSetLayerId(event) && event.args.data.frame === mainFrameId2) {\n          this.#layerTreeId = event.args.data.layerTreeId;\n        } else if (TraceEvents_exports.isLayerTreeHostImplSnapshot(event) && Number(event.id) === this.#layerTreeId) {\n          this.#handleLayerTreeSnapshot({\n            entry: event,\n            paints: []\n          });\n        } else {\n          if (isFrameEvent(event)) {\n            this.#processCompositorEvents(event);\n          }\n          if (event.tid === this.#activeThreadId && event.pid === this.#activeProcessId) {\n            this.#addMainThreadTraceEvent(event);\n          }\n        }\n      }\n      #processCompositorEvents(entry) {\n        if (entry.args[\"layerTreeId\"] !== this.#layerTreeId) {\n          return;\n        }\n        if (TraceEvents_exports.isBeginFrame(entry)) {\n          this.#handleBeginFrame(entry.ts, entry.args[\"frameSeqId\"]);\n        } else if (TraceEvents_exports.isDrawFrame(entry)) {\n          this.#handleDrawFrame(entry.ts, entry.args[\"frameSeqId\"]);\n        } else if (TraceEvents_exports.isActivateLayerTree(entry)) {\n          this.#handleActivateLayerTree();\n        } else if (TraceEvents_exports.isRequestMainThreadFrame(entry)) {\n          this.#handleRequestMainThreadFrame();\n        } else if (TraceEvents_exports.isNeedsBeginFrameChanged(entry)) {\n          this.#handleNeedFrameChanged(entry.ts, entry.args[\"data\"] && Boolean(entry.args[\"data\"][\"needsBeginFrame\"]));\n        } else if (TraceEvents_exports.isDroppedFrame(entry)) {\n          this.#handleDroppedFrame(entry.ts, entry.args[\"frameSeqId\"], Boolean(entry.args[\"hasPartialUpdate\"]));\n        }\n      }\n      #addMainThreadTraceEvent(entry) {\n        if (entryIsTopLevel(entry)) {\n          this.#lastTaskBeginTime = entry.ts;\n        }\n        if (!this.#framePendingCommit && MAIN_FRAME_MARKERS.has(entry.name)) {\n          this.#framePendingCommit = new PendingFrame(this.#lastTaskBeginTime || entry.ts);\n        }\n        if (!this.#framePendingCommit) {\n          return;\n        }\n        if (TraceEvents_exports.isBeginMainThreadFrame(entry) && entry.args.data.frameId) {\n          this.#framePendingCommit.mainFrameId = entry.args.data.frameId;\n        }\n        if (TraceEvents_exports.isPaint(entry)) {\n          const snapshot2 = this.#layerTreeData.paintsToSnapshots.get(entry);\n          if (snapshot2) {\n            this.#framePendingCommit.paints.push(new LayerPaintEvent(entry, snapshot2));\n          }\n        }\n        if ((TraceEvents_exports.isCompositeLayers(entry) || TraceEvents_exports.isCommit(entry)) && entry.args[\"layerTreeId\"] === this.#layerTreeId) {\n          this.#handleCommit();\n        }\n      }\n    };\n    TimelineFrame = class {\n      static {\n        __name(this, \"TimelineFrame\");\n      }\n      // These fields exist to satisfy the base Event type which all\n      // \"trace events\" must implement. They aren't used, but doing this means we\n      // can pass `TimelineFrame` instances into places that expect\n      // Types.Events.Event.\n      cat = \"devtools.legacy_frame\";\n      name = \"frame\";\n      ph = TraceEvents_exports.Phase.COMPLETE;\n      ts;\n      pid = TraceEvents_exports.ProcessID(-1);\n      tid = TraceEvents_exports.ThreadID(-1);\n      index = -1;\n      startTime;\n      startTimeOffset;\n      endTime;\n      duration;\n      idle;\n      dropped;\n      isPartial;\n      layerTree;\n      paints;\n      mainFrameId;\n      seqId;\n      constructor(seqId, startTime, startTimeOffset) {\n        this.seqId = seqId;\n        this.startTime = startTime;\n        this.ts = startTime;\n        this.startTimeOffset = startTimeOffset;\n        this.endTime = this.startTime;\n        this.duration = Timing_exports.Micro(0);\n        this.idle = false;\n        this.dropped = false;\n        this.isPartial = false;\n        this.layerTree = null;\n        this.paints = [];\n        this.mainFrameId = void 0;\n      }\n      setIndex(i) {\n        this.index = i;\n      }\n      setEndTime(endTime) {\n        this.endTime = endTime;\n        this.duration = Timing_exports.Micro(this.endTime - this.startTime);\n      }\n      setLayerTree(layerTree) {\n        this.layerTree = layerTree;\n      }\n      /**\n       * Fake the `dur` field to meet the expected value given that we pretend\n       * these TimelineFrame classes are trace events across the codebase.\n       */\n      get dur() {\n        return this.duration;\n      }\n    };\n    LayerPaintEvent = class {\n      static {\n        __name(this, \"LayerPaintEvent\");\n      }\n      #event;\n      #snapshot;\n      constructor(event, snapshot2) {\n        this.#event = event;\n        this.#snapshot = snapshot2;\n      }\n      layerId() {\n        return this.#event.args.data.layerId;\n      }\n      event() {\n        return this.#event;\n      }\n      picture() {\n        const rect = this.#snapshot.args.snapshot.params?.layer_rect;\n        const pictureData = this.#snapshot.args.snapshot.skp64;\n        return rect && pictureData ? { rect, serializedPicture: pictureData } : null;\n      }\n    };\n    PendingFrame = class {\n      static {\n        __name(this, \"PendingFrame\");\n      }\n      paints;\n      mainFrameId;\n      triggerTime;\n      constructor(triggerTime) {\n        this.paints = [];\n        this.mainFrameId = void 0;\n        this.triggerTime = triggerTime;\n      }\n    };\n    BeginFrameInfo = class {\n      static {\n        __name(this, \"BeginFrameInfo\");\n      }\n      seqId;\n      startTime;\n      isDropped;\n      isPartial;\n      constructor(seqId, startTime, isDropped, isPartial) {\n        this.seqId = seqId;\n        this.startTime = startTime;\n        this.isDropped = isDropped;\n        this.isPartial = isPartial;\n      }\n    };\n    TimelineFrameBeginFrameQueue = class {\n      static {\n        __name(this, \"TimelineFrameBeginFrameQueue\");\n      }\n      queueFrames = [];\n      // Maps frameSeqId to BeginFrameInfo.\n      mapFrames = {};\n      // Add a BeginFrame to the queue, if it does not already exit.\n      addFrameIfNotExists(seqId, startTime, isDropped, isPartial) {\n        if (!(seqId in this.mapFrames)) {\n          this.mapFrames[seqId] = new BeginFrameInfo(seqId, startTime, isDropped, isPartial);\n          this.queueFrames.push(seqId);\n        }\n      }\n      // Set a BeginFrame in queue as dropped.\n      setDropped(seqId, isDropped) {\n        if (seqId in this.mapFrames) {\n          this.mapFrames[seqId].isDropped = isDropped;\n        }\n      }\n      setPartial(seqId, isPartial) {\n        if (seqId in this.mapFrames) {\n          this.mapFrames[seqId].isPartial = isPartial;\n        }\n      }\n      processPendingBeginFramesOnDrawFrame(seqId) {\n        const framesToVisualize = [];\n        if (seqId in this.mapFrames) {\n          while (this.queueFrames[0] !== seqId) {\n            const currentSeqId = this.queueFrames[0];\n            if (this.mapFrames[currentSeqId].isDropped) {\n              framesToVisualize.push(this.mapFrames[currentSeqId]);\n            }\n            delete this.mapFrames[currentSeqId];\n            this.queueFrames.shift();\n          }\n          framesToVisualize.push(this.mapFrames[seqId]);\n          delete this.mapFrames[seqId];\n          this.queueFrames.shift();\n        }\n        return framesToVisualize;\n      }\n    };\n    __name(framesWithinWindow, \"framesWithinWindow\");\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/handlers/GPUHandler.js\nvar GPUHandler_exports = {};\n__export(GPUHandler_exports, {\n  data: () => data15,\n  deps: () => deps8,\n  finalize: () => finalize15,\n  handleEvent: () => handleEvent15,\n  reset: () => reset15\n});\nfunction reset15() {\n  eventsInProcessThread = /* @__PURE__ */ new Map();\n  mainGPUThreadTasks = [];\n}\nfunction handleEvent15(event) {\n  if (!TraceEvents_exports.isGPUTask(event)) {\n    return;\n  }\n  Trace_exports.addEventToProcessThread(event, eventsInProcessThread);\n}\nasync function finalize15() {\n  const { gpuProcessId: gpuProcessId2, gpuThreadId: gpuThreadId2 } = data5();\n  const gpuThreadsForProcess = eventsInProcessThread.get(gpuProcessId2);\n  if (gpuThreadsForProcess && gpuThreadId2) {\n    mainGPUThreadTasks = gpuThreadsForProcess.get(gpuThreadId2) || [];\n  }\n}\nfunction data15() {\n  return {\n    mainGPUThreadTasks\n  };\n}\nfunction deps8() {\n  return [\"Meta\"];\n}\nvar eventsInProcessThread, mainGPUThreadTasks;\nvar init_GPUHandler = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/handlers/GPUHandler.js\"() {\n    init_process_global();\n    init_helpers2();\n    init_types2();\n    init_MetaHandler();\n    eventsInProcessThread = /* @__PURE__ */ new Map();\n    mainGPUThreadTasks = [];\n    __name(reset15, \"reset\");\n    __name(handleEvent15, \"handleEvent\");\n    __name(finalize15, \"finalize\");\n    __name(data15, \"data\");\n    __name(deps8, \"deps\");\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/handlers/ImagePaintingHandler.js\nvar ImagePaintingHandler_exports = {};\n__export(ImagePaintingHandler_exports, {\n  data: () => data16,\n  finalize: () => finalize16,\n  handleEvent: () => handleEvent16,\n  reset: () => reset16\n});\nfunction reset16() {\n  paintImageEvents = /* @__PURE__ */ new Map();\n  decodeLazyPixelRefEvents = /* @__PURE__ */ new Map();\n  paintImageByLazyPixelRef = /* @__PURE__ */ new Map();\n  eventToPaintImage = /* @__PURE__ */ new Map();\n  urlToPaintImage = /* @__PURE__ */ new Map();\n  paintEventToCorrectedDisplaySize = /* @__PURE__ */ new Map();\n  didCorrectForHostDpr = false;\n}\nfunction handleEvent16(event) {\n  if (TraceEvents_exports.isPaintImage(event)) {\n    const forProcess = paintImageEvents.get(event.pid) || /* @__PURE__ */ new Map();\n    const forThread = forProcess.get(event.tid) || [];\n    forThread.push(event);\n    forProcess.set(event.tid, forThread);\n    paintImageEvents.set(event.pid, forProcess);\n    if (event.args.data.url) {\n      const paintsForUrl = MapUtilities_exports.getWithDefault(urlToPaintImage, event.args.data.url, () => []);\n      paintsForUrl.push(event);\n    }\n    return;\n  }\n  if (TraceEvents_exports.isDecodeLazyPixelRef(event) && typeof event.args?.LazyPixelRef !== \"undefined\") {\n    const forProcess = decodeLazyPixelRefEvents.get(event.pid) || /* @__PURE__ */ new Map();\n    const forThread = forProcess.get(event.tid) || [];\n    forThread.push(event);\n    forProcess.set(event.tid, forThread);\n    decodeLazyPixelRefEvents.set(event.pid, forProcess);\n  }\n  if (TraceEvents_exports.isDrawLazyPixelRef(event) && typeof event.args?.LazyPixelRef !== \"undefined\") {\n    const lastPaintEvent = paintImageEvents.get(event.pid)?.get(event.tid)?.at(-1);\n    if (!lastPaintEvent) {\n      return;\n    }\n    paintImageByLazyPixelRef.set(event.args.LazyPixelRef, lastPaintEvent);\n    return;\n  }\n  if (TraceEvents_exports.isDecodeImage(event)) {\n    const lastPaintImageEventOnThread = paintImageEvents.get(event.pid)?.get(event.tid)?.at(-1);\n    if (lastPaintImageEventOnThread) {\n      eventToPaintImage.set(event, lastPaintImageEventOnThread);\n      return;\n    }\n    const lastDecodeLazyPixelRef = decodeLazyPixelRefEvents.get(event.pid)?.get(event.tid)?.at(-1);\n    if (typeof lastDecodeLazyPixelRef?.args?.LazyPixelRef === \"undefined\") {\n      return;\n    }\n    const paintEvent = paintImageByLazyPixelRef.get(lastDecodeLazyPixelRef.args.LazyPixelRef);\n    if (!paintEvent) {\n      return;\n    }\n    eventToPaintImage.set(event, paintEvent);\n  }\n}\nasync function finalize16(options) {\n  if (!options.metadata?.hostDPR) {\n    return;\n  }\n  const { devicePixelRatio: emulatedDpr } = data5();\n  if (!emulatedDpr) {\n    return;\n  }\n  for (const byThread of paintImageEvents.values()) {\n    for (const paintEvents2 of byThread.values()) {\n      for (const paintEvent of paintEvents2) {\n        const cssPixelsWidth = paintEvent.args.data.width / options.metadata.hostDPR;\n        const cssPixelsHeight = paintEvent.args.data.height / options.metadata.hostDPR;\n        const width = cssPixelsWidth * emulatedDpr;\n        const height = cssPixelsHeight * emulatedDpr;\n        paintEventToCorrectedDisplaySize.set(paintEvent, { width, height });\n      }\n    }\n  }\n  didCorrectForHostDpr = true;\n}\nfunction data16() {\n  return {\n    paintImageByDrawLazyPixelRef: paintImageByLazyPixelRef,\n    paintImageForEvent: eventToPaintImage,\n    paintImageEventForUrl: urlToPaintImage,\n    paintEventToCorrectedDisplaySize,\n    didCorrectForHostDpr\n  };\n}\nvar paintImageEvents, decodeLazyPixelRefEvents, paintImageByLazyPixelRef, eventToPaintImage, urlToPaintImage, paintEventToCorrectedDisplaySize, didCorrectForHostDpr;\nvar init_ImagePaintingHandler = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/handlers/ImagePaintingHandler.js\"() {\n    init_process_global();\n    init_platform();\n    init_types2();\n    init_MetaHandler();\n    paintImageEvents = /* @__PURE__ */ new Map();\n    decodeLazyPixelRefEvents = /* @__PURE__ */ new Map();\n    paintImageByLazyPixelRef = /* @__PURE__ */ new Map();\n    eventToPaintImage = /* @__PURE__ */ new Map();\n    urlToPaintImage = /* @__PURE__ */ new Map();\n    paintEventToCorrectedDisplaySize = /* @__PURE__ */ new Map();\n    didCorrectForHostDpr = false;\n    __name(reset16, \"reset\");\n    __name(handleEvent16, \"handleEvent\");\n    __name(finalize16, \"finalize\");\n    __name(data16, \"data\");\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/handlers/InitiatorsHandler.js\nvar InitiatorsHandler_exports = {};\n__export(InitiatorsHandler_exports, {\n  data: () => data17,\n  deps: () => deps9,\n  finalize: () => finalize17,\n  handleEvent: () => handleEvent17,\n  reset: () => reset17\n});\nfunction reset17() {\n  lastScheduleStyleRecalcByFrame = /* @__PURE__ */ new Map();\n  lastInvalidationEventForFrame = /* @__PURE__ */ new Map();\n  lastRecalcByFrame = /* @__PURE__ */ new Map();\n  timerInstallEventsById = /* @__PURE__ */ new Map();\n  eventToInitiatorMap2 = /* @__PURE__ */ new Map();\n  initiatorToEventsMap = /* @__PURE__ */ new Map();\n  requestIdleCallbackEventsById = /* @__PURE__ */ new Map();\n  webSocketCreateEventsById = /* @__PURE__ */ new Map();\n  schedulePostTaskCallbackEventsById = /* @__PURE__ */ new Map();\n}\nfunction storeInitiator(data31) {\n  eventToInitiatorMap2.set(data31.event, data31.initiator);\n  const eventsForInitiator = initiatorToEventsMap.get(data31.initiator) || [];\n  eventsForInitiator.push(data31.event);\n  initiatorToEventsMap.set(data31.initiator, eventsForInitiator);\n}\nfunction handleEvent17(event) {\n  if (TraceEvents_exports.isScheduleStyleRecalculation(event)) {\n    lastScheduleStyleRecalcByFrame.set(event.args.data.frame, event);\n  } else if (TraceEvents_exports.isRecalcStyle(event)) {\n    if (event.args.beginData) {\n      lastRecalcByFrame.set(event.args.beginData.frame, event);\n      const scheduledStyleForFrame = lastScheduleStyleRecalcByFrame.get(event.args.beginData.frame);\n      if (scheduledStyleForFrame) {\n        storeInitiator({\n          event,\n          initiator: scheduledStyleForFrame\n        });\n      }\n    }\n  } else if (TraceEvents_exports.isInvalidateLayout(event)) {\n    let invalidationInitiator = event;\n    if (!lastInvalidationEventForFrame.has(event.args.data.frame)) {\n      const lastRecalcStyleForFrame = lastRecalcByFrame.get(event.args.data.frame);\n      if (lastRecalcStyleForFrame) {\n        const { endTime } = Timing_exports3.eventTimingsMicroSeconds(lastRecalcStyleForFrame);\n        const initiatorOfRecalcStyle = eventToInitiatorMap2.get(lastRecalcStyleForFrame);\n        if (initiatorOfRecalcStyle && endTime && endTime > event.ts) {\n          invalidationInitiator = initiatorOfRecalcStyle;\n        }\n      }\n    }\n    lastInvalidationEventForFrame.set(event.args.data.frame, invalidationInitiator);\n  } else if (TraceEvents_exports.isLayout(event)) {\n    const lastInvalidation = lastInvalidationEventForFrame.get(event.args.beginData.frame);\n    if (lastInvalidation) {\n      storeInitiator({\n        event,\n        initiator: lastInvalidation\n      });\n    }\n    lastInvalidationEventForFrame.delete(event.args.beginData.frame);\n  } else if (TraceEvents_exports.isTimerInstall(event)) {\n    timerInstallEventsById.set(event.args.data.timerId, event);\n  } else if (TraceEvents_exports.isTimerFire(event)) {\n    const matchingInstall = timerInstallEventsById.get(event.args.data.timerId);\n    if (matchingInstall) {\n      storeInitiator({ event, initiator: matchingInstall });\n    }\n  } else if (TraceEvents_exports.isRequestIdleCallback(event)) {\n    requestIdleCallbackEventsById.set(event.args.data.id, event);\n  } else if (TraceEvents_exports.isFireIdleCallback(event)) {\n    const matchingRequestEvent = requestIdleCallbackEventsById.get(event.args.data.id);\n    if (matchingRequestEvent) {\n      storeInitiator({\n        event,\n        initiator: matchingRequestEvent\n      });\n    }\n  } else if (TraceEvents_exports.isWebSocketCreate(event)) {\n    webSocketCreateEventsById.set(event.args.data.identifier, event);\n  } else if (TraceEvents_exports.isWebSocketInfo(event) || TraceEvents_exports.isWebSocketTransfer(event)) {\n    const matchingCreateEvent = webSocketCreateEventsById.get(event.args.data.identifier);\n    if (matchingCreateEvent) {\n      storeInitiator({\n        event,\n        initiator: matchingCreateEvent\n      });\n    }\n  } else if (TraceEvents_exports.isSchedulePostTaskCallback(event)) {\n    schedulePostTaskCallbackEventsById.set(event.args.data.taskId, event);\n  } else if (TraceEvents_exports.isRunPostTaskCallback(event) || TraceEvents_exports.isAbortPostTaskCallback(event)) {\n    const matchingSchedule = schedulePostTaskCallbackEventsById.get(event.args.data.taskId);\n    if (matchingSchedule) {\n      storeInitiator({ event, initiator: matchingSchedule });\n    }\n  }\n}\nfunction createRelationshipsFromFlows() {\n  const flows2 = data3().flows;\n  for (let i = 0; i < flows2.length; i++) {\n    const flow = flows2[i];\n    for (let j = 0; j < flow.length - 1; j++) {\n      storeInitiator({ event: flow[j + 1], initiator: flow[j] });\n    }\n  }\n}\nfunction createRelationshipsFromAsyncJSCalls() {\n  const asyncCallEntries = data9().schedulerToRunEntryPoints.entries();\n  for (const [asyncCaller, asyncCallees] of asyncCallEntries) {\n    for (const asyncCallee of asyncCallees) {\n      storeInitiator({ event: asyncCallee, initiator: asyncCaller });\n    }\n  }\n}\nasync function finalize17() {\n  createRelationshipsFromFlows();\n  createRelationshipsFromAsyncJSCalls();\n}\nfunction data17() {\n  return {\n    eventToInitiator: eventToInitiatorMap2,\n    initiatorToEvents: initiatorToEventsMap\n  };\n}\nfunction deps9() {\n  return [\"Flows\", \"AsyncJSCalls\"];\n}\nvar lastScheduleStyleRecalcByFrame, lastInvalidationEventForFrame, lastRecalcByFrame, eventToInitiatorMap2, initiatorToEventsMap, timerInstallEventsById, requestIdleCallbackEventsById, webSocketCreateEventsById, schedulePostTaskCallbackEventsById;\nvar init_InitiatorsHandler = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/handlers/InitiatorsHandler.js\"() {\n    init_process_global();\n    init_helpers2();\n    init_types2();\n    init_AsyncJSCallsHandler();\n    init_FlowsHandler();\n    lastScheduleStyleRecalcByFrame = /* @__PURE__ */ new Map();\n    lastInvalidationEventForFrame = /* @__PURE__ */ new Map();\n    lastRecalcByFrame = /* @__PURE__ */ new Map();\n    eventToInitiatorMap2 = /* @__PURE__ */ new Map();\n    initiatorToEventsMap = /* @__PURE__ */ new Map();\n    timerInstallEventsById = /* @__PURE__ */ new Map();\n    requestIdleCallbackEventsById = /* @__PURE__ */ new Map();\n    webSocketCreateEventsById = /* @__PURE__ */ new Map();\n    schedulePostTaskCallbackEventsById = /* @__PURE__ */ new Map();\n    __name(reset17, \"reset\");\n    __name(storeInitiator, \"storeInitiator\");\n    __name(handleEvent17, \"handleEvent\");\n    __name(createRelationshipsFromFlows, \"createRelationshipsFromFlows\");\n    __name(createRelationshipsFromAsyncJSCalls, \"createRelationshipsFromAsyncJSCalls\");\n    __name(finalize17, \"finalize\");\n    __name(data17, \"data\");\n    __name(deps9, \"deps\");\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/handlers/InvalidationsHandler.js\nvar InvalidationsHandler_exports = {};\n__export(InvalidationsHandler_exports, {\n  data: () => data18,\n  finalize: () => finalize18,\n  handleEvent: () => handleEvent18,\n  handleUserConfig: () => handleUserConfig3,\n  reset: () => reset18\n});\nfunction reset18() {\n  frameStateByFrame.clear();\n  maxInvalidationsPerEvent = null;\n}\nfunction handleUserConfig3(userConfig) {\n  maxInvalidationsPerEvent = userConfig.maxInvalidationEventsPerEvent;\n}\nfunction getState(frameId) {\n  let frameState = frameStateByFrame.get(frameId);\n  if (!frameState) {\n    frameState = {\n      invalidationsForEvent: /* @__PURE__ */ new Map(),\n      invalidationCountForEvent: /* @__PURE__ */ new Map(),\n      lastRecalcStyleEvent: null,\n      pendingInvalidations: [],\n      hasPainted: false\n    };\n    frameStateByFrame.set(frameId, frameState);\n  }\n  return frameState;\n}\nfunction getFrameId(event) {\n  if (TraceEvents_exports.isRecalcStyle(event) || TraceEvents_exports.isLayout(event)) {\n    return event.args.beginData?.frame ?? null;\n  }\n  return event.args?.data?.frame ?? null;\n}\nfunction addInvalidationToEvent(frameState, event, invalidation) {\n  const existingInvalidations = frameState.invalidationsForEvent.get(event) || [];\n  existingInvalidations.push(invalidation);\n  if (maxInvalidationsPerEvent !== null && existingInvalidations.length > maxInvalidationsPerEvent) {\n    existingInvalidations.shift();\n  }\n  frameState.invalidationsForEvent.set(event, existingInvalidations);\n  const count = frameState.invalidationCountForEvent.get(event) ?? 0;\n  frameState.invalidationCountForEvent.set(event, count + 1);\n}\nfunction handleEvent18(event) {\n  if (maxInvalidationsPerEvent === 0) {\n    return;\n  }\n  const frameId = getFrameId(event);\n  if (!frameId) {\n    return;\n  }\n  const thisFrame = getState(frameId);\n  if (TraceEvents_exports.isRecalcStyle(event)) {\n    thisFrame.lastRecalcStyleEvent = event;\n    for (const invalidation of thisFrame.pendingInvalidations) {\n      if (TraceEvents_exports.isLayoutInvalidationTracking(invalidation)) {\n        continue;\n      }\n      addInvalidationToEvent(thisFrame, event, invalidation);\n    }\n    return;\n  }\n  if (TraceEvents_exports.isInvalidationTracking(event)) {\n    if (thisFrame.hasPainted) {\n      thisFrame.pendingInvalidations.length = 0;\n      thisFrame.lastRecalcStyleEvent = null;\n      thisFrame.hasPainted = false;\n    }\n    if (thisFrame.lastRecalcStyleEvent && (TraceEvents_exports.isScheduleStyleInvalidationTracking(event) || TraceEvents_exports.isStyleRecalcInvalidationTracking(event) || TraceEvents_exports.isStyleInvalidatorInvalidationTracking(event))) {\n      const recalcLastRecalc = thisFrame.lastRecalcStyleEvent;\n      const recalcEndTime = recalcLastRecalc.ts + (recalcLastRecalc.dur || 0);\n      if (event.ts >= recalcLastRecalc.ts && event.ts <= recalcEndTime) {\n        addInvalidationToEvent(thisFrame, recalcLastRecalc, event);\n      }\n    }\n    thisFrame.pendingInvalidations.push(event);\n    return;\n  }\n  if (TraceEvents_exports.isPaint(event)) {\n    thisFrame.hasPainted = true;\n    return;\n  }\n  if (TraceEvents_exports.isLayout(event)) {\n    for (const invalidation of thisFrame.pendingInvalidations) {\n      if (!TraceEvents_exports.isLayoutInvalidationTracking(invalidation)) {\n        continue;\n      }\n      addInvalidationToEvent(thisFrame, event, invalidation);\n    }\n  }\n}\nasync function finalize18() {\n}\nfunction data18() {\n  const invalidationsForEvent = /* @__PURE__ */ new Map();\n  const invalidationCountForEvent = /* @__PURE__ */ new Map();\n  for (const frame of frameStateByFrame.values()) {\n    for (const [event, invalidations] of frame.invalidationsForEvent.entries()) {\n      invalidationsForEvent.set(event, invalidations);\n    }\n    for (const [event, count] of frame.invalidationCountForEvent.entries()) {\n      invalidationCountForEvent.set(event, count);\n    }\n  }\n  return {\n    invalidationsForEvent,\n    invalidationCountForEvent\n  };\n}\nvar frameStateByFrame, maxInvalidationsPerEvent;\nvar init_InvalidationsHandler = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/handlers/InvalidationsHandler.js\"() {\n    init_process_global();\n    init_types2();\n    frameStateByFrame = /* @__PURE__ */ new Map();\n    maxInvalidationsPerEvent = null;\n    __name(reset18, \"reset\");\n    __name(handleUserConfig3, \"handleUserConfig\");\n    __name(getState, \"getState\");\n    __name(getFrameId, \"getFrameId\");\n    __name(addInvalidationToEvent, \"addInvalidationToEvent\");\n    __name(handleEvent18, \"handleEvent\");\n    __name(finalize18, \"finalize\");\n    __name(data18, \"data\");\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/handlers/PageLoadMetricsHandler.js\nvar PageLoadMetricsHandler_exports = {};\n__export(PageLoadMetricsHandler_exports, {\n  MetricName: () => MetricName,\n  ScoreClassification: () => ScoreClassification,\n  data: () => data19,\n  deps: () => deps10,\n  finalize: () => finalize19,\n  getFrameIdForPageLoadEvent: () => getFrameIdForPageLoadEvent,\n  handleEvent: () => handleEvent19,\n  metricIsLCP: () => metricIsLCP,\n  reset: () => reset19,\n  scoreClassificationForDOMContentLoaded: () => scoreClassificationForDOMContentLoaded,\n  scoreClassificationForFirstContentfulPaint: () => scoreClassificationForFirstContentfulPaint,\n  scoreClassificationForLargestContentfulPaint: () => scoreClassificationForLargestContentfulPaint,\n  scoreClassificationForTimeToInteractive: () => scoreClassificationForTimeToInteractive,\n  scoreClassificationForTotalBlockingTime: () => scoreClassificationForTotalBlockingTime\n});\nfunction reset19() {\n  metricScoresByFrameId = /* @__PURE__ */ new Map();\n  pageLoadEventsArray = [];\n  allMarkerEvents = [];\n  selectedLCPCandidateEvents = /* @__PURE__ */ new Set();\n}\nfunction handleEvent19(event) {\n  if (!TraceEvents_exports.eventIsPageLoadEvent(event)) {\n    return;\n  }\n  pageLoadEventsArray.push(event);\n}\nfunction storePageLoadMetricAgainstNavigationId(navigation2, event) {\n  const navigationId = navigation2.args.data?.navigationId;\n  if (!navigationId) {\n    throw new Error(\"Navigation event unexpectedly had no navigation ID.\");\n  }\n  const frameId = getFrameIdForPageLoadEvent(event);\n  const { rendererProcessesByFrame } = data5();\n  const rendererProcessesInFrame = rendererProcessesByFrame.get(frameId);\n  if (!rendererProcessesInFrame) {\n    return;\n  }\n  const processData = rendererProcessesInFrame.get(event.pid);\n  if (!processData) {\n    return;\n  }\n  if (TraceEvents_exports.isNavigationStart(event)) {\n    return;\n  }\n  if (TraceEvents_exports.isFirstContentfulPaint(event)) {\n    const fcpTime = Timing_exports.Micro(event.ts - navigation2.ts);\n    const classification = scoreClassificationForFirstContentfulPaint(fcpTime);\n    const metricScore = { event, metricName: MetricName.FCP, classification, navigation: navigation2, timing: fcpTime };\n    storeMetricScore(frameId, navigationId, metricScore);\n    return;\n  }\n  if (TraceEvents_exports.isFirstPaint(event)) {\n    const paintTime = Timing_exports.Micro(event.ts - navigation2.ts);\n    const classification = ScoreClassification.UNCLASSIFIED;\n    const metricScore = { event, metricName: MetricName.FP, classification, navigation: navigation2, timing: paintTime };\n    storeMetricScore(frameId, navigationId, metricScore);\n    return;\n  }\n  if (TraceEvents_exports.isMarkDOMContent(event)) {\n    const dclTime = Timing_exports.Micro(event.ts - navigation2.ts);\n    const metricScore = {\n      event,\n      metricName: MetricName.DCL,\n      classification: scoreClassificationForDOMContentLoaded(dclTime),\n      navigation: navigation2,\n      timing: dclTime\n    };\n    storeMetricScore(frameId, navigationId, metricScore);\n    return;\n  }\n  if (TraceEvents_exports.isInteractiveTime(event)) {\n    const ttiValue = Timing_exports.Micro(event.ts - navigation2.ts);\n    const tti = {\n      event,\n      metricName: MetricName.TTI,\n      classification: scoreClassificationForTimeToInteractive(ttiValue),\n      navigation: navigation2,\n      timing: ttiValue\n    };\n    storeMetricScore(frameId, navigationId, tti);\n    const tbtValue = Timing_exports3.milliToMicro(Timing_exports.Milli(event.args.args.total_blocking_time_ms));\n    const tbt = {\n      event,\n      metricName: MetricName.TBT,\n      classification: scoreClassificationForTotalBlockingTime(tbtValue),\n      navigation: navigation2,\n      timing: tbtValue\n    };\n    storeMetricScore(frameId, navigationId, tbt);\n    return;\n  }\n  if (TraceEvents_exports.isMarkLoad(event)) {\n    const loadTime = Timing_exports.Micro(event.ts - navigation2.ts);\n    const metricScore = {\n      event,\n      metricName: MetricName.L,\n      classification: ScoreClassification.UNCLASSIFIED,\n      navigation: navigation2,\n      timing: loadTime\n    };\n    storeMetricScore(frameId, navigationId, metricScore);\n    return;\n  }\n  if (TraceEvents_exports.isLargestContentfulPaintCandidate(event)) {\n    const candidateIndex = event.args.data?.candidateIndex;\n    if (!candidateIndex) {\n      throw new Error(\"Largest Contentful Paint unexpectedly had no candidateIndex.\");\n    }\n    const lcpTime = Timing_exports.Micro(event.ts - navigation2.ts);\n    const lcp = {\n      event,\n      metricName: MetricName.LCP,\n      classification: scoreClassificationForLargestContentfulPaint(lcpTime),\n      navigation: navigation2,\n      timing: lcpTime\n    };\n    const metricsByNavigation = MapUtilities_exports.getWithDefault(metricScoresByFrameId, frameId, () => /* @__PURE__ */ new Map());\n    const metrics = MapUtilities_exports.getWithDefault(metricsByNavigation, navigationId, () => /* @__PURE__ */ new Map());\n    const lastLCPCandidate = metrics.get(MetricName.LCP);\n    if (lastLCPCandidate === void 0) {\n      selectedLCPCandidateEvents.add(lcp.event);\n      storeMetricScore(frameId, navigationId, lcp);\n      return;\n    }\n    const lastLCPCandidateEvent = lastLCPCandidate.event;\n    if (!TraceEvents_exports.isLargestContentfulPaintCandidate(lastLCPCandidateEvent)) {\n      return;\n    }\n    const lastCandidateIndex = lastLCPCandidateEvent.args.data?.candidateIndex;\n    if (!lastCandidateIndex) {\n      return;\n    }\n    if (lastCandidateIndex < candidateIndex) {\n      selectedLCPCandidateEvents.delete(lastLCPCandidateEvent);\n      selectedLCPCandidateEvents.add(lcp.event);\n      storeMetricScore(frameId, navigationId, lcp);\n    }\n    return;\n  }\n  if (TraceEvents_exports.isLayoutShift(event)) {\n    return;\n  }\n  return assertNever(event, `Unexpected event type: ${event}`);\n}\nfunction storeMetricScore(frameId, navigationId, metricScore) {\n  const metricsByNavigation = MapUtilities_exports.getWithDefault(metricScoresByFrameId, frameId, () => /* @__PURE__ */ new Map());\n  const metrics = MapUtilities_exports.getWithDefault(metricsByNavigation, navigationId, () => /* @__PURE__ */ new Map());\n  metrics.delete(metricScore.metricName);\n  metrics.set(metricScore.metricName, metricScore);\n}\nfunction getFrameIdForPageLoadEvent(event) {\n  if (TraceEvents_exports.isFirstContentfulPaint(event) || TraceEvents_exports.isInteractiveTime(event) || TraceEvents_exports.isLargestContentfulPaintCandidate(event) || TraceEvents_exports.isNavigationStart(event) || TraceEvents_exports.isLayoutShift(event) || TraceEvents_exports.isFirstPaint(event)) {\n    return event.args.frame;\n  }\n  if (TraceEvents_exports.isMarkDOMContent(event) || TraceEvents_exports.isMarkLoad(event)) {\n    const frameId = event.args.data?.frame;\n    if (!frameId) {\n      throw new Error(\"MarkDOMContent unexpectedly had no frame ID.\");\n    }\n    return frameId;\n  }\n  assertNever(event, `Unexpected event type: ${event}`);\n}\nfunction getNavigationForPageLoadEvent(event) {\n  if (TraceEvents_exports.isFirstContentfulPaint(event) || TraceEvents_exports.isLargestContentfulPaintCandidate(event) || TraceEvents_exports.isFirstPaint(event)) {\n    const navigationId = event.args.data?.navigationId;\n    if (!navigationId) {\n      throw new Error(\"Trace event unexpectedly had no navigation ID.\");\n    }\n    const { navigationsByNavigationId: navigationsByNavigationId2 } = data5();\n    const navigation2 = navigationsByNavigationId2.get(navigationId);\n    if (!navigation2) {\n      return null;\n    }\n    return navigation2;\n  }\n  if (TraceEvents_exports.isMarkDOMContent(event) || TraceEvents_exports.isInteractiveTime(event) || TraceEvents_exports.isLayoutShift(event) || TraceEvents_exports.isMarkLoad(event)) {\n    const frameId = getFrameIdForPageLoadEvent(event);\n    const { navigationsByFrameId: navigationsByFrameId2 } = data5();\n    return Trace_exports.getNavigationForTraceEvent(event, frameId, navigationsByFrameId2);\n  }\n  if (TraceEvents_exports.isNavigationStart(event)) {\n    return null;\n  }\n  return assertNever(event, `Unexpected event type: ${event}`);\n}\nfunction scoreClassificationForFirstContentfulPaint(fcpScoreInMicroseconds) {\n  const FCP_GOOD_TIMING = Timing_exports3.secondsToMicro(Timing_exports.Seconds(1.8));\n  const FCP_MEDIUM_TIMING = Timing_exports3.secondsToMicro(Timing_exports.Seconds(3));\n  let scoreClassification = ScoreClassification.BAD;\n  if (fcpScoreInMicroseconds <= FCP_MEDIUM_TIMING) {\n    scoreClassification = ScoreClassification.OK;\n  }\n  if (fcpScoreInMicroseconds <= FCP_GOOD_TIMING) {\n    scoreClassification = ScoreClassification.GOOD;\n  }\n  return scoreClassification;\n}\nfunction scoreClassificationForTimeToInteractive(ttiTimeInMicroseconds) {\n  const TTI_GOOD_TIMING = Timing_exports3.secondsToMicro(Timing_exports.Seconds(3.8));\n  const TTI_MEDIUM_TIMING = Timing_exports3.secondsToMicro(Timing_exports.Seconds(7.3));\n  let scoreClassification = ScoreClassification.BAD;\n  if (ttiTimeInMicroseconds <= TTI_MEDIUM_TIMING) {\n    scoreClassification = ScoreClassification.OK;\n  }\n  if (ttiTimeInMicroseconds <= TTI_GOOD_TIMING) {\n    scoreClassification = ScoreClassification.GOOD;\n  }\n  return scoreClassification;\n}\nfunction scoreClassificationForLargestContentfulPaint(lcpTimeInMicroseconds) {\n  const LCP_GOOD_TIMING = Timing_exports3.secondsToMicro(Timing_exports.Seconds(2.5));\n  const LCP_MEDIUM_TIMING = Timing_exports3.secondsToMicro(Timing_exports.Seconds(4));\n  let scoreClassification = ScoreClassification.BAD;\n  if (lcpTimeInMicroseconds <= LCP_MEDIUM_TIMING) {\n    scoreClassification = ScoreClassification.OK;\n  }\n  if (lcpTimeInMicroseconds <= LCP_GOOD_TIMING) {\n    scoreClassification = ScoreClassification.GOOD;\n  }\n  return scoreClassification;\n}\nfunction scoreClassificationForDOMContentLoaded(_dclTimeInMicroseconds) {\n  return ScoreClassification.UNCLASSIFIED;\n}\nfunction scoreClassificationForTotalBlockingTime(tbtTimeInMicroseconds) {\n  const TBT_GOOD_TIMING = Timing_exports3.milliToMicro(Timing_exports.Milli(200));\n  const TBT_MEDIUM_TIMING = Timing_exports3.milliToMicro(Timing_exports.Milli(600));\n  let scoreClassification = ScoreClassification.BAD;\n  if (tbtTimeInMicroseconds <= TBT_MEDIUM_TIMING) {\n    scoreClassification = ScoreClassification.OK;\n  }\n  if (tbtTimeInMicroseconds <= TBT_GOOD_TIMING) {\n    scoreClassification = ScoreClassification.GOOD;\n  }\n  return scoreClassification;\n}\nfunction gatherFinalLCPEvents() {\n  const allFinalLCPEvents = [];\n  const dataForAllFrames = [...metricScoresByFrameId.values()];\n  const dataForAllNavigations = dataForAllFrames.flatMap((frameData) => [...frameData.values()]);\n  for (let i = 0; i < dataForAllNavigations.length; i++) {\n    const navigationData = dataForAllNavigations[i];\n    const lcpInNavigation = navigationData.get(MetricName.LCP);\n    if (!lcpInNavigation?.event) {\n      continue;\n    }\n    allFinalLCPEvents.push(lcpInNavigation.event);\n  }\n  return allFinalLCPEvents;\n}\nasync function finalize19() {\n  pageLoadEventsArray.sort((a, b) => a.ts - b.ts);\n  for (const pageLoadEvent of pageLoadEventsArray) {\n    const navigation2 = getNavigationForPageLoadEvent(pageLoadEvent);\n    if (navigation2) {\n      storePageLoadMetricAgainstNavigationId(navigation2, pageLoadEvent);\n    }\n  }\n  const allFinalLCPEvents = gatherFinalLCPEvents();\n  const mainFrame = data5().mainFrameId;\n  const allEventsButLCP = pageLoadEventsArray.filter((event) => !TraceEvents_exports.isLargestContentfulPaintCandidate(event));\n  const markerEvents = [...allFinalLCPEvents, ...allEventsButLCP].filter(TraceEvents_exports.isMarkerEvent);\n  allMarkerEvents = markerEvents.filter((event) => getFrameIdForPageLoadEvent(event) === mainFrame).sort((a, b) => a.ts - b.ts);\n}\nfunction data19() {\n  return {\n    metricScoresByFrameId,\n    allMarkerEvents\n  };\n}\nfunction deps10() {\n  return [\"Meta\"];\n}\nfunction metricIsLCP(metric) {\n  return metric.metricName === MetricName.LCP;\n}\nvar metricScoresByFrameId, allMarkerEvents, pageLoadEventsArray, selectedLCPCandidateEvents, ScoreClassification, MetricName;\nvar init_PageLoadMetricsHandler = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/handlers/PageLoadMetricsHandler.js\"() {\n    init_process_global();\n    init_platform();\n    init_helpers2();\n    init_types2();\n    init_MetaHandler();\n    metricScoresByFrameId = /* @__PURE__ */ new Map();\n    allMarkerEvents = [];\n    __name(reset19, \"reset\");\n    pageLoadEventsArray = [];\n    selectedLCPCandidateEvents = /* @__PURE__ */ new Set();\n    __name(handleEvent19, \"handleEvent\");\n    __name(storePageLoadMetricAgainstNavigationId, \"storePageLoadMetricAgainstNavigationId\");\n    __name(storeMetricScore, \"storeMetricScore\");\n    __name(getFrameIdForPageLoadEvent, \"getFrameIdForPageLoadEvent\");\n    __name(getNavigationForPageLoadEvent, \"getNavigationForPageLoadEvent\");\n    __name(scoreClassificationForFirstContentfulPaint, \"scoreClassificationForFirstContentfulPaint\");\n    __name(scoreClassificationForTimeToInteractive, \"scoreClassificationForTimeToInteractive\");\n    __name(scoreClassificationForLargestContentfulPaint, \"scoreClassificationForLargestContentfulPaint\");\n    __name(scoreClassificationForDOMContentLoaded, \"scoreClassificationForDOMContentLoaded\");\n    __name(scoreClassificationForTotalBlockingTime, \"scoreClassificationForTotalBlockingTime\");\n    __name(gatherFinalLCPEvents, \"gatherFinalLCPEvents\");\n    __name(finalize19, \"finalize\");\n    __name(data19, \"data\");\n    __name(deps10, \"deps\");\n    (function(ScoreClassification2) {\n      ScoreClassification2[\"GOOD\"] = \"good\";\n      ScoreClassification2[\"OK\"] = \"ok\";\n      ScoreClassification2[\"BAD\"] = \"bad\";\n      ScoreClassification2[\"UNCLASSIFIED\"] = \"unclassified\";\n    })(ScoreClassification || (ScoreClassification = {}));\n    (function(MetricName2) {\n      MetricName2[\"FCP\"] = \"FCP\";\n      MetricName2[\"FP\"] = \"FP\";\n      MetricName2[\"L\"] = \"L\";\n      MetricName2[\"LCP\"] = \"LCP\";\n      MetricName2[\"DCL\"] = \"DCL\";\n      MetricName2[\"TTI\"] = \"TTI\";\n      MetricName2[\"TBT\"] = \"TBT\";\n      MetricName2[\"CLS\"] = \"CLS\";\n      MetricName2[\"NAV\"] = \"Nav\";\n    })(MetricName || (MetricName = {}));\n    __name(metricIsLCP, \"metricIsLCP\");\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/handlers/LargestImagePaintHandler.js\nvar LargestImagePaintHandler_exports = {};\n__export(LargestImagePaintHandler_exports, {\n  data: () => data20,\n  deps: () => deps11,\n  finalize: () => finalize20,\n  handleEvent: () => handleEvent20,\n  reset: () => reset20\n});\nfunction reset20() {\n  imagePaintsByNodeIdAndProcess = /* @__PURE__ */ new Map();\n  lcpRequestByNavigationId = /* @__PURE__ */ new Map();\n}\nfunction handleEvent20(event) {\n  if (!TraceEvents_exports.isLargestImagePaintCandidate(event) || !event.args.data) {\n    return;\n  }\n  const imagePaintsByNodeId = MapUtilities_exports.getWithDefault(imagePaintsByNodeIdAndProcess, event.pid, () => /* @__PURE__ */ new Map());\n  imagePaintsByNodeId.set(event.args.data.DOMNodeId, event);\n}\nasync function finalize20() {\n  const requests = data6().byTime;\n  const { traceBounds: traceBounds2, navigationsByNavigationId: navigationsByNavigationId2 } = data5();\n  const metricScoresByFrameId2 = data19().metricScoresByFrameId;\n  for (const [navigationId, navigation2] of navigationsByNavigationId2) {\n    const lcpMetric = metricScoresByFrameId2.get(navigation2.args.frame)?.get(navigationId)?.get(MetricName.LCP);\n    const lcpEvent = lcpMetric?.event;\n    if (!lcpEvent || !TraceEvents_exports.isLargestContentfulPaintCandidate(lcpEvent)) {\n      continue;\n    }\n    const nodeId = lcpEvent.args.data?.nodeId;\n    if (!nodeId) {\n      continue;\n    }\n    const lcpImagePaintEvent = imagePaintsByNodeIdAndProcess.get(lcpEvent.pid)?.get(nodeId);\n    const lcpUrl = lcpImagePaintEvent?.args.data?.imageUrl;\n    if (!lcpUrl) {\n      continue;\n    }\n    const startTime = navigation2?.ts ?? traceBounds2.min;\n    const endTime = lcpImagePaintEvent.ts;\n    let lcpRequest;\n    for (const request of requests) {\n      if (request.ts < startTime) {\n        continue;\n      }\n      if (request.ts >= endTime) {\n        break;\n      }\n      if (request.args.data.url === lcpUrl || request.args.data.redirects.some((r) => r.url === lcpUrl)) {\n        lcpRequest = request;\n        break;\n      }\n    }\n    if (lcpRequest) {\n      lcpRequestByNavigationId.set(navigationId, lcpRequest);\n    }\n  }\n}\nfunction data20() {\n  return { lcpRequestByNavigationId };\n}\nfunction deps11() {\n  return [\"Meta\", \"NetworkRequests\", \"PageLoadMetrics\"];\n}\nvar imagePaintsByNodeIdAndProcess, lcpRequestByNavigationId;\nvar init_LargestImagePaintHandler = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/handlers/LargestImagePaintHandler.js\"() {\n    init_process_global();\n    init_platform();\n    init_types2();\n    init_MetaHandler();\n    init_NetworkRequestsHandler();\n    init_PageLoadMetricsHandler();\n    imagePaintsByNodeIdAndProcess = /* @__PURE__ */ new Map();\n    lcpRequestByNavigationId = /* @__PURE__ */ new Map();\n    __name(reset20, \"reset\");\n    __name(handleEvent20, \"handleEvent\");\n    __name(finalize20, \"finalize\");\n    __name(data20, \"data\");\n    __name(deps11, \"deps\");\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/handlers/LargestTextPaintHandler.js\nvar LargestTextPaintHandler_exports = {};\n__export(LargestTextPaintHandler_exports, {\n  data: () => data21,\n  finalize: () => finalize21,\n  handleEvent: () => handleEvent21,\n  reset: () => reset21\n});\nfunction reset21() {\n  textPaintByDOMNodeId = /* @__PURE__ */ new Map();\n}\nfunction handleEvent21(event) {\n  if (!TraceEvents_exports.isLargestTextPaintCandidate(event)) {\n    return;\n  }\n  if (!event.args.data) {\n    return;\n  }\n  textPaintByDOMNodeId.set(event.args.data.DOMNodeId, event);\n}\nasync function finalize21() {\n}\nfunction data21() {\n  return textPaintByDOMNodeId;\n}\nvar textPaintByDOMNodeId;\nvar init_LargestTextPaintHandler = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/handlers/LargestTextPaintHandler.js\"() {\n    init_process_global();\n    init_types2();\n    textPaintByDOMNodeId = /* @__PURE__ */ new Map();\n    __name(reset21, \"reset\");\n    __name(handleEvent21, \"handleEvent\");\n    __name(finalize21, \"finalize\");\n    __name(data21, \"data\");\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/handlers/ScreenshotsHandler.js\nvar ScreenshotsHandler_exports = {};\n__export(ScreenshotsHandler_exports, {\n  data: () => data22,\n  deps: () => deps12,\n  finalize: () => finalize22,\n  handleEvent: () => handleEvent22,\n  reset: () => reset22,\n  screenshotImageDataUri: () => screenshotImageDataUri\n});\nfunction reset22() {\n  unpairedAsyncEvents = [];\n  legacyScreenshotEvents = [];\n  syntheticScreenshots = [];\n  modernScreenshotEvents = [];\n  frameSequenceToTs = {};\n}\nfunction handleEvent22(event) {\n  if (TraceEvents_exports.isLegacyScreenshot(event)) {\n    legacyScreenshotEvents.push(event);\n  } else if (TraceEvents_exports.isScreenshot(event)) {\n    modernScreenshotEvents.push(event);\n  } else if (TraceEvents_exports.isPipelineReporter(event)) {\n    unpairedAsyncEvents.push(event);\n  }\n}\nasync function finalize22() {\n  const pipelineReporterEvents = Trace_exports.createMatchedSortedSyntheticEvents(unpairedAsyncEvents);\n  frameSequenceToTs = Object.fromEntries(pipelineReporterEvents.map((evt) => {\n    const args = evt.args.data.beginEvent.args;\n    const frameReporter = \"frame_reporter\" in args ? args.frame_reporter : args.chrome_frame_reporter;\n    const frameSequenceId = frameReporter.frame_sequence;\n    const presentationTs = Timing_exports.Micro(evt.ts + evt.dur);\n    return [frameSequenceId, presentationTs];\n  }));\n  for (const snapshotEvent of legacyScreenshotEvents) {\n    const { cat, name, ph, pid, tid } = snapshotEvent;\n    const syntheticEvent = SyntheticEvents_exports.SyntheticEventsManager.registerSyntheticEvent({\n      rawSourceEvent: snapshotEvent,\n      cat,\n      name,\n      ph,\n      pid,\n      tid,\n      // TODO(paulirish, crbug.com/41363012): investigate why getPresentationTimestamp(snapshotEvent) seems less accurate. Resolve screenshot timing inaccuracy.\n      // `getPresentationTimestamp(snapshotEvent) - snapshotEvent.ts` is how many microsec the screenshot should be adjusted to the right/later\n      ts: snapshotEvent.ts,\n      args: {\n        dataUri: `data:image/jpg;base64,${snapshotEvent.args.snapshot}`\n      }\n    });\n    syntheticScreenshots.push(syntheticEvent);\n  }\n}\nfunction screenshotImageDataUri(event) {\n  if (TraceEvents_exports.isLegacySyntheticScreenshot(event)) {\n    return event.args.dataUri;\n  }\n  return `data:image/jpg;base64,${event.args.snapshot}`;\n}\nfunction data22() {\n  return {\n    legacySyntheticScreenshots: syntheticScreenshots.length ? syntheticScreenshots : null,\n    screenshots: modernScreenshotEvents.length ? modernScreenshotEvents : null\n  };\n}\nfunction deps12() {\n  return [\"Meta\"];\n}\nvar unpairedAsyncEvents, legacyScreenshotEvents, modernScreenshotEvents, syntheticScreenshots, frameSequenceToTs;\nvar init_ScreenshotsHandler = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/handlers/ScreenshotsHandler.js\"() {\n    init_process_global();\n    init_helpers2();\n    init_types2();\n    unpairedAsyncEvents = [];\n    legacyScreenshotEvents = [];\n    modernScreenshotEvents = [];\n    syntheticScreenshots = [];\n    frameSequenceToTs = {};\n    __name(reset22, \"reset\");\n    __name(handleEvent22, \"handleEvent\");\n    __name(finalize22, \"finalize\");\n    __name(screenshotImageDataUri, \"screenshotImageDataUri\");\n    __name(data22, \"data\");\n    __name(deps12, \"deps\");\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/handlers/LayoutShiftsHandler.js\nvar LayoutShiftsHandler_exports = {};\n__export(LayoutShiftsHandler_exports, {\n  LayoutShiftsThreshold: () => LayoutShiftsThreshold,\n  MAX_CLUSTER_DURATION: () => MAX_CLUSTER_DURATION,\n  MAX_SHIFT_TIME_DELTA: () => MAX_SHIFT_TIME_DELTA,\n  data: () => data23,\n  deps: () => deps13,\n  finalize: () => finalize23,\n  handleEvent: () => handleEvent23,\n  reset: () => reset23,\n  scoreClassificationForLayoutShift: () => scoreClassificationForLayoutShift\n});\nfunction reset23() {\n  layoutShiftEvents = [];\n  layoutInvalidationEvents = [];\n  scheduleStyleInvalidationEvents = [];\n  styleRecalcInvalidationEvents = [];\n  prePaintEvents = [];\n  paintImageEvents2 = [];\n  renderFrameImplCreateChildFrameEvents = [];\n  layoutImageUnsizedEvents = [];\n  domLoadingEvents = [];\n  remoteFonts = [];\n  backendNodeIds = /* @__PURE__ */ new Set();\n  clusters = [];\n  sessionMaxScore = 0;\n  scoreRecords = [];\n  clsWindowID = -1;\n  clustersByNavigationId = /* @__PURE__ */ new Map();\n}\nfunction handleEvent23(event) {\n  if (TraceEvents_exports.isLayoutShift(event) && !event.args.data?.had_recent_input) {\n    layoutShiftEvents.push(event);\n    return;\n  }\n  if (TraceEvents_exports.isLayoutInvalidationTracking(event)) {\n    layoutInvalidationEvents.push(event);\n    return;\n  }\n  if (TraceEvents_exports.isScheduleStyleInvalidationTracking(event)) {\n    scheduleStyleInvalidationEvents.push(event);\n  }\n  if (TraceEvents_exports.isStyleRecalcInvalidationTracking(event)) {\n    styleRecalcInvalidationEvents.push(event);\n  }\n  if (TraceEvents_exports.isPrePaint(event)) {\n    prePaintEvents.push(event);\n    return;\n  }\n  if (TraceEvents_exports.isRenderFrameImplCreateChildFrame(event)) {\n    renderFrameImplCreateChildFrameEvents.push(event);\n  }\n  if (TraceEvents_exports.isDomLoading(event)) {\n    domLoadingEvents.push(event);\n  }\n  if (TraceEvents_exports.isLayoutImageUnsized(event)) {\n    layoutImageUnsizedEvents.push(event);\n  }\n  if (TraceEvents_exports.isBeginRemoteFontLoad(event)) {\n    remoteFonts.push({\n      display: event.args.display,\n      url: event.args.url,\n      beginRemoteFontLoadEvent: event\n    });\n  }\n  if (TraceEvents_exports.isRemoteFontLoaded(event)) {\n    for (const remoteFont of remoteFonts) {\n      if (remoteFont.url === event.args.url) {\n        remoteFont.name = event.args.name;\n      }\n    }\n  }\n  if (TraceEvents_exports.isPaintImage(event)) {\n    paintImageEvents2.push(event);\n  }\n}\nfunction traceWindowFromTime(time) {\n  return {\n    min: time,\n    max: time,\n    range: Timing_exports.Micro(0)\n  };\n}\nfunction updateTraceWindowMax(traceWindow, newMax) {\n  traceWindow.max = newMax;\n  traceWindow.range = Timing_exports.Micro(traceWindow.max - traceWindow.min);\n}\nfunction findScreenshots(timestamp) {\n  const data31 = data22();\n  if (data31.screenshots) {\n    const before = Trace_exports.findPreviousEventBeforeTimestamp(data31.screenshots, timestamp);\n    const after = before ? data31.screenshots[data31.screenshots.indexOf(before) + 1] : null;\n    return { before, after };\n  }\n  if (data31.legacySyntheticScreenshots) {\n    const before = Trace_exports.findPreviousEventBeforeTimestamp(data31.legacySyntheticScreenshots, timestamp);\n    const after = before ? data31.legacySyntheticScreenshots[data31.legacySyntheticScreenshots.indexOf(before) + 1] : null;\n    return { before, after };\n  }\n  return { before: null, after: null };\n}\nfunction buildScoreRecords() {\n  const { traceBounds: traceBounds2 } = data5();\n  scoreRecords.push({ ts: traceBounds2.min, score: 0 });\n  for (const cluster of clusters) {\n    let clusterScore = 0;\n    if (cluster.events[0].args.data) {\n      scoreRecords.push({ ts: cluster.clusterWindow.min, score: cluster.events[0].args.data.weighted_score_delta });\n    }\n    for (let i = 0; i < cluster.events.length; i++) {\n      const event = cluster.events[i];\n      if (!event.args.data) {\n        continue;\n      }\n      clusterScore += event.args.data.weighted_score_delta;\n      scoreRecords.push({ ts: event.ts, score: clusterScore });\n    }\n    scoreRecords.push({ ts: cluster.clusterWindow.max, score: 0 });\n  }\n}\nfunction collectNodes() {\n  backendNodeIds.clear();\n  for (const layoutShift of layoutShiftEvents) {\n    if (!layoutShift.args.data?.impacted_nodes) {\n      continue;\n    }\n    for (const node of layoutShift.args.data.impacted_nodes) {\n      backendNodeIds.add(node.node_id);\n    }\n  }\n  for (const layoutInvalidation of layoutInvalidationEvents) {\n    if (!layoutInvalidation.args.data?.nodeId) {\n      continue;\n    }\n    backendNodeIds.add(layoutInvalidation.args.data.nodeId);\n  }\n  for (const scheduleStyleInvalidation of scheduleStyleInvalidationEvents) {\n    if (!scheduleStyleInvalidation.args.data?.nodeId) {\n      continue;\n    }\n    backendNodeIds.add(scheduleStyleInvalidation.args.data.nodeId);\n  }\n}\nasync function finalize23() {\n  layoutShiftEvents.sort((a, b) => a.ts - b.ts);\n  prePaintEvents.sort((a, b) => a.ts - b.ts);\n  layoutInvalidationEvents.sort((a, b) => a.ts - b.ts);\n  renderFrameImplCreateChildFrameEvents.sort((a, b) => a.ts - b.ts);\n  domLoadingEvents.sort((a, b) => a.ts - b.ts);\n  layoutImageUnsizedEvents.sort((a, b) => a.ts - b.ts);\n  remoteFonts.sort((a, b) => a.beginRemoteFontLoadEvent.ts - b.beginRemoteFontLoadEvent.ts);\n  paintImageEvents2.sort((a, b) => a.ts - b.ts);\n  await buildLayoutShiftsClusters();\n  buildScoreRecords();\n  collectNodes();\n}\nasync function buildLayoutShiftsClusters() {\n  const { navigationsByFrameId: navigationsByFrameId2, mainFrameId: mainFrameId2, traceBounds: traceBounds2 } = data5();\n  const navigations = navigationsByFrameId2.get(mainFrameId2) || [];\n  if (layoutShiftEvents.length === 0) {\n    return;\n  }\n  let firstShiftTime = layoutShiftEvents[0].ts;\n  let lastShiftTime = layoutShiftEvents[0].ts;\n  let lastShiftNavigation = null;\n  for (const event of layoutShiftEvents) {\n    const clusterDurationExceeded = event.ts - firstShiftTime > MAX_CLUSTER_DURATION;\n    const maxTimeDeltaSinceLastShiftExceeded = event.ts - lastShiftTime > MAX_SHIFT_TIME_DELTA;\n    const currentShiftNavigation = ArrayUtilities_exports.nearestIndexFromEnd(navigations, (nav) => nav.ts < event.ts);\n    const hasNavigated = lastShiftNavigation !== currentShiftNavigation && currentShiftNavigation !== null;\n    if (clusterDurationExceeded || maxTimeDeltaSinceLastShiftExceeded || hasNavigated || !clusters.length) {\n      const clusterStartTime = event.ts;\n      const endTimeByMaxSessionDuration = clusterDurationExceeded ? firstShiftTime + MAX_CLUSTER_DURATION : Infinity;\n      const endTimeByMaxShiftGap = maxTimeDeltaSinceLastShiftExceeded ? lastShiftTime + MAX_SHIFT_TIME_DELTA : Infinity;\n      const endTimeByNavigation = hasNavigated ? navigations[currentShiftNavigation].ts : Infinity;\n      const previousClusterEndTime = Math.min(endTimeByMaxSessionDuration, endTimeByMaxShiftGap, endTimeByNavigation);\n      if (clusters.length > 0) {\n        const currentCluster2 = clusters[clusters.length - 1];\n        updateTraceWindowMax(currentCluster2.clusterWindow, Timing_exports.Micro(previousClusterEndTime));\n      }\n      const navigationId = currentShiftNavigation === null ? TraceEvents_exports.NO_NAVIGATION : navigations[currentShiftNavigation].args.data?.navigationId;\n      clusters.push(SyntheticEvents_exports.SyntheticEventsManager.registerSyntheticEvent({\n        name: \"SyntheticLayoutShiftCluster\",\n        // Will be replaced by the worst layout shift in the next for loop.\n        rawSourceEvent: event,\n        events: [],\n        clusterWindow: traceWindowFromTime(clusterStartTime),\n        clusterCumulativeScore: 0,\n        scoreWindows: {\n          good: traceWindowFromTime(clusterStartTime)\n        },\n        navigationId,\n        // Set default Event so that this event is treated accordingly for the track appender.\n        ts: event.ts,\n        pid: event.pid,\n        tid: event.tid,\n        ph: TraceEvents_exports.Phase.COMPLETE,\n        cat: \"\",\n        dur: Timing_exports.Micro(-1)\n        // This `cluster.dur` is updated below.\n      }));\n      firstShiftTime = clusterStartTime;\n    }\n    const currentCluster = clusters[clusters.length - 1];\n    const timeFromNavigation = currentShiftNavigation !== null ? Timing_exports.Micro(event.ts - navigations[currentShiftNavigation].ts) : void 0;\n    currentCluster.clusterCumulativeScore += event.args.data ? event.args.data.weighted_score_delta : 0;\n    if (!event.args.data) {\n      continue;\n    }\n    const shift = SyntheticEvents_exports.SyntheticEventsManager.registerSyntheticEvent({\n      rawSourceEvent: event,\n      ...event,\n      name: TraceEvents_exports.Name.SYNTHETIC_LAYOUT_SHIFT,\n      args: {\n        frame: event.args.frame,\n        data: {\n          ...event.args.data,\n          rawEvent: event,\n          navigationId: currentCluster.navigationId ?? void 0\n        }\n      },\n      parsedData: {\n        timeFromNavigation,\n        screenshots: findScreenshots(event.ts),\n        cumulativeWeightedScoreInWindow: currentCluster.clusterCumulativeScore,\n        // The score of the session window is temporarily set to 0 just\n        // to initialize it. Since we need to get the score of all shifts\n        // in the session window to determine its value, its definite\n        // value is set when stepping through the built clusters.\n        sessionWindowData: { cumulativeWindowScore: 0, id: clusters.length }\n      }\n    });\n    currentCluster.events.push(shift);\n    updateTraceWindowMax(currentCluster.clusterWindow, event.ts);\n    lastShiftTime = event.ts;\n    lastShiftNavigation = currentShiftNavigation;\n  }\n  for (const cluster of clusters) {\n    let weightedScore = 0;\n    let windowID = -1;\n    if (cluster === clusters[clusters.length - 1]) {\n      const clusterEndByMaxDuration = MAX_CLUSTER_DURATION + cluster.clusterWindow.min;\n      const clusterEndByMaxGap = cluster.clusterWindow.max + MAX_SHIFT_TIME_DELTA;\n      const nextNavigationIndex = ArrayUtilities_exports.nearestIndexFromBeginning(navigations, (nav) => nav.ts > cluster.clusterWindow.max);\n      const nextNavigationTime = nextNavigationIndex ? navigations[nextNavigationIndex].ts : Infinity;\n      const clusterEnd = Math.min(clusterEndByMaxDuration, clusterEndByMaxGap, traceBounds2.max, nextNavigationTime);\n      updateTraceWindowMax(cluster.clusterWindow, Timing_exports.Micro(clusterEnd));\n    }\n    let largestScore = 0;\n    let worstShiftEvent = null;\n    for (const shift of cluster.events) {\n      weightedScore += shift.args.data ? shift.args.data.weighted_score_delta : 0;\n      windowID = shift.parsedData.sessionWindowData.id;\n      const ts = shift.ts;\n      shift.parsedData.sessionWindowData.cumulativeWindowScore = cluster.clusterCumulativeScore;\n      if (weightedScore < LayoutShiftsThreshold.NEEDS_IMPROVEMENT) {\n        updateTraceWindowMax(cluster.scoreWindows.good, ts);\n      } else if (weightedScore >= LayoutShiftsThreshold.NEEDS_IMPROVEMENT && weightedScore < LayoutShiftsThreshold.BAD) {\n        if (!cluster.scoreWindows.needsImprovement) {\n          updateTraceWindowMax(cluster.scoreWindows.good, Timing_exports.Micro(ts - 1));\n          cluster.scoreWindows.needsImprovement = traceWindowFromTime(ts);\n        }\n        updateTraceWindowMax(cluster.scoreWindows.needsImprovement, ts);\n      } else if (weightedScore >= LayoutShiftsThreshold.BAD) {\n        if (!cluster.scoreWindows.bad) {\n          if (cluster.scoreWindows.needsImprovement) {\n            updateTraceWindowMax(cluster.scoreWindows.needsImprovement, Timing_exports.Micro(ts - 1));\n          } else {\n            updateTraceWindowMax(cluster.scoreWindows.good, Timing_exports.Micro(ts - 1));\n          }\n          cluster.scoreWindows.bad = traceWindowFromTime(shift.ts);\n        }\n        updateTraceWindowMax(cluster.scoreWindows.bad, ts);\n      }\n      if (cluster.scoreWindows.bad) {\n        updateTraceWindowMax(cluster.scoreWindows.bad, cluster.clusterWindow.max);\n      } else if (cluster.scoreWindows.needsImprovement) {\n        updateTraceWindowMax(cluster.scoreWindows.needsImprovement, cluster.clusterWindow.max);\n      } else {\n        updateTraceWindowMax(cluster.scoreWindows.good, cluster.clusterWindow.max);\n      }\n      const score = shift.args.data?.weighted_score_delta;\n      if (score !== void 0 && score > largestScore) {\n        largestScore = score;\n        worstShiftEvent = shift;\n      }\n    }\n    if (worstShiftEvent) {\n      cluster.worstShiftEvent = worstShiftEvent;\n      cluster.rawSourceEvent = worstShiftEvent;\n    }\n    cluster.ts = cluster.events[0].ts;\n    const lastShiftTimings = Timing_exports3.eventTimingsMicroSeconds(cluster.events[cluster.events.length - 1]);\n    cluster.dur = Timing_exports.Micro(lastShiftTimings.endTime - cluster.events[0].ts + MAX_SHIFT_TIME_DELTA);\n    if (weightedScore > sessionMaxScore) {\n      clsWindowID = windowID;\n      sessionMaxScore = weightedScore;\n    }\n    if (cluster.navigationId) {\n      const clustersForId = MapUtilities_exports.getWithDefault(clustersByNavigationId, cluster.navigationId, () => {\n        return [];\n      });\n      clustersForId.push(cluster);\n    }\n  }\n}\nfunction data23() {\n  return {\n    clusters,\n    sessionMaxScore,\n    clsWindowID,\n    prePaintEvents,\n    layoutInvalidationEvents,\n    scheduleStyleInvalidationEvents,\n    styleRecalcInvalidationEvents,\n    renderFrameImplCreateChildFrameEvents,\n    domLoadingEvents,\n    layoutImageUnsizedEvents,\n    remoteFonts,\n    scoreRecords,\n    backendNodeIds,\n    clustersByNavigationId,\n    paintImageEvents: paintImageEvents2\n  };\n}\nfunction deps13() {\n  return [\"Screenshots\", \"Meta\"];\n}\nfunction scoreClassificationForLayoutShift(score) {\n  let state = ScoreClassification.GOOD;\n  if (score >= LayoutShiftsThreshold.NEEDS_IMPROVEMENT) {\n    state = ScoreClassification.OK;\n  }\n  if (score >= LayoutShiftsThreshold.BAD) {\n    state = ScoreClassification.BAD;\n  }\n  return state;\n}\nvar MAX_CLUSTER_DURATION, MAX_SHIFT_TIME_DELTA, layoutShiftEvents, layoutInvalidationEvents, scheduleStyleInvalidationEvents, styleRecalcInvalidationEvents, renderFrameImplCreateChildFrameEvents, domLoadingEvents, layoutImageUnsizedEvents, remoteFonts, backendNodeIds, prePaintEvents, paintImageEvents2, sessionMaxScore, clsWindowID, clusters, clustersByNavigationId, scoreRecords, LayoutShiftsThreshold;\nvar init_LayoutShiftsHandler = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/handlers/LayoutShiftsHandler.js\"() {\n    init_process_global();\n    init_platform();\n    init_helpers2();\n    init_types2();\n    init_MetaHandler();\n    init_PageLoadMetricsHandler();\n    init_ScreenshotsHandler();\n    MAX_CLUSTER_DURATION = Timing_exports3.milliToMicro(Timing_exports.Milli(5e3));\n    MAX_SHIFT_TIME_DELTA = Timing_exports3.milliToMicro(Timing_exports.Milli(1e3));\n    layoutShiftEvents = [];\n    layoutInvalidationEvents = [];\n    scheduleStyleInvalidationEvents = [];\n    styleRecalcInvalidationEvents = [];\n    renderFrameImplCreateChildFrameEvents = [];\n    domLoadingEvents = [];\n    layoutImageUnsizedEvents = [];\n    remoteFonts = [];\n    backendNodeIds = /* @__PURE__ */ new Set();\n    prePaintEvents = [];\n    paintImageEvents2 = [];\n    sessionMaxScore = 0;\n    clsWindowID = -1;\n    clusters = [];\n    clustersByNavigationId = /* @__PURE__ */ new Map();\n    scoreRecords = [];\n    __name(reset23, \"reset\");\n    __name(handleEvent23, \"handleEvent\");\n    __name(traceWindowFromTime, \"traceWindowFromTime\");\n    __name(updateTraceWindowMax, \"updateTraceWindowMax\");\n    __name(findScreenshots, \"findScreenshots\");\n    __name(buildScoreRecords, \"buildScoreRecords\");\n    __name(collectNodes, \"collectNodes\");\n    __name(finalize23, \"finalize\");\n    __name(buildLayoutShiftsClusters, \"buildLayoutShiftsClusters\");\n    __name(data23, \"data\");\n    __name(deps13, \"deps\");\n    __name(scoreClassificationForLayoutShift, \"scoreClassificationForLayoutShift\");\n    (function(LayoutShiftsThreshold2) {\n      LayoutShiftsThreshold2[LayoutShiftsThreshold2[\"GOOD\"] = 0] = \"GOOD\";\n      LayoutShiftsThreshold2[LayoutShiftsThreshold2[\"NEEDS_IMPROVEMENT\"] = 0.1] = \"NEEDS_IMPROVEMENT\";\n      LayoutShiftsThreshold2[LayoutShiftsThreshold2[\"BAD\"] = 0.25] = \"BAD\";\n    })(LayoutShiftsThreshold || (LayoutShiftsThreshold = {}));\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/handlers/MemoryHandler.js\nvar MemoryHandler_exports = {};\n__export(MemoryHandler_exports, {\n  data: () => data24,\n  finalize: () => finalize24,\n  handleEvent: () => handleEvent24,\n  reset: () => reset24\n});\nfunction reset24() {\n  updateCountersByProcess = /* @__PURE__ */ new Map();\n}\nfunction handleEvent24(event) {\n  if (TraceEvents_exports.isUpdateCounters(event)) {\n    const countersForProcess = MapUtilities_exports.getWithDefault(updateCountersByProcess, event.pid, () => []);\n    countersForProcess.push(event);\n    updateCountersByProcess.set(event.pid, countersForProcess);\n  }\n}\nasync function finalize24() {\n}\nfunction data24() {\n  return { updateCountersByProcess };\n}\nvar updateCountersByProcess;\nvar init_MemoryHandler = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/handlers/MemoryHandler.js\"() {\n    init_process_global();\n    init_platform();\n    init_types2();\n    updateCountersByProcess = /* @__PURE__ */ new Map();\n    __name(reset24, \"reset\");\n    __name(handleEvent24, \"handleEvent\");\n    __name(finalize24, \"finalize\");\n    __name(data24, \"data\");\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/handlers/PageFramesHandler.js\nvar PageFramesHandler_exports = {};\n__export(PageFramesHandler_exports, {\n  data: () => data25,\n  finalize: () => finalize25,\n  handleEvent: () => handleEvent25,\n  reset: () => reset25\n});\nfunction reset25() {\n  frames = /* @__PURE__ */ new Map();\n}\nfunction handleEvent25(event) {\n  if (TraceEvents_exports.isTracingStartedInBrowser(event)) {\n    for (const frame of event.args.data?.frames ?? []) {\n      frames.set(frame.frame, frame);\n    }\n    return;\n  }\n  if (TraceEvents_exports.isCommitLoad(event)) {\n    const frameData = event.args.data;\n    if (!frameData) {\n      return;\n    }\n    const frame = frames.get(frameData.frame);\n    if (!frame) {\n      return;\n    }\n    frames.set(frameData.frame, {\n      ...frame,\n      url: frameData.url || frame.url,\n      name: frameData.name || frameData.name\n    });\n  }\n}\nasync function finalize25() {\n}\nfunction data25() {\n  return {\n    frames\n  };\n}\nvar frames;\nvar init_PageFramesHandler = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/handlers/PageFramesHandler.js\"() {\n    init_process_global();\n    init_types2();\n    frames = /* @__PURE__ */ new Map();\n    __name(reset25, \"reset\");\n    __name(handleEvent25, \"handleEvent\");\n    __name(finalize25, \"finalize\");\n    __name(data25, \"data\");\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/handlers/ScriptsHandler.js\nvar ScriptsHandler_exports = {};\n__export(ScriptsHandler_exports, {\n  data: () => data26,\n  deps: () => deps14,\n  finalize: () => finalize26,\n  getScriptGeneratedSizes: () => getScriptGeneratedSizes,\n  handleEvent: () => handleEvent26,\n  reset: () => reset26\n});\nfunction completeURL(base, url) {\n  if (url.startsWith(\"data:\") || url.startsWith(\"blob:\") || url.startsWith(\"javascript:\") || url.startsWith(\"mailto:\")) {\n    return url;\n  }\n  try {\n    return new URL(url, base).href;\n  } catch {\n  }\n  return null;\n}\nfunction deps14() {\n  return [\"Meta\", \"NetworkRequests\"];\n}\nfunction reset26() {\n  scriptById = /* @__PURE__ */ new Map();\n}\nfunction handleEvent26(event) {\n  const getOrMakeScript = /* @__PURE__ */ __name((isolate, scriptIdAsNumber) => {\n    const scriptId = String(scriptIdAsNumber);\n    const key = `${isolate}.${scriptId}`;\n    return MapUtilities_exports.getWithDefault(scriptById, key, () => ({ isolate, scriptId, frame: \"\", ts: event.ts }));\n  }, \"getOrMakeScript\");\n  if (TraceEvents_exports.isRundownScriptCompiled(event) && event.args.data) {\n    const { isolate, scriptId, frame } = event.args.data;\n    const script = getOrMakeScript(isolate, scriptId);\n    script.frame = frame;\n    script.ts = event.ts;\n    return;\n  }\n  if (TraceEvents_exports.isRundownScript(event)) {\n    const { isolate, scriptId, url, sourceUrl, sourceMapUrl, sourceMapUrlElided } = event.args.data;\n    const script = getOrMakeScript(isolate, scriptId);\n    script.url = url;\n    script.ts = event.ts;\n    if (sourceUrl) {\n      script.sourceUrl = sourceUrl;\n    }\n    if (sourceMapUrlElided) {\n      script.sourceMapUrlElided = true;\n    } else if (sourceMapUrl) {\n      script.sourceMapUrl = sourceMapUrl;\n    }\n    return;\n  }\n  if (TraceEvents_exports.isRundownScriptSource(event)) {\n    const { isolate, scriptId, sourceText } = event.args.data;\n    const script = getOrMakeScript(isolate, scriptId);\n    script.content = sourceText;\n    return;\n  }\n  if (TraceEvents_exports.isRundownScriptSourceLarge(event)) {\n    const { isolate, scriptId, sourceText } = event.args.data;\n    const script = getOrMakeScript(isolate, scriptId);\n    script.content = (script.content ?? \"\") + sourceText;\n    return;\n  }\n}\nfunction findFrame(meta, frameId) {\n  for (const frames2 of meta.frameByProcessId?.values()) {\n    const frame = frames2.get(frameId);\n    if (frame) {\n      return frame;\n    }\n  }\n  return null;\n}\nfunction findNetworkRequest(networkRequests, script) {\n  if (!script.url) {\n    return null;\n  }\n  return networkRequests.find((request) => request.args.data.url === script.url) ?? null;\n}\nfunction computeMappingEndColumns(map) {\n  const result = /* @__PURE__ */ new Map();\n  const mappings = map.mappings();\n  for (let i = 0; i < mappings.length - 1; i++) {\n    const mapping = mappings[i];\n    const nextMapping = mappings[i + 1];\n    if (mapping.lineNumber === nextMapping.lineNumber) {\n      result.set(mapping, nextMapping.columnNumber);\n    }\n  }\n  return result;\n}\nfunction computeGeneratedFileSizes(script) {\n  if (!script.sourceMap) {\n    throw new Error(\"expected source map\");\n  }\n  const map = script.sourceMap;\n  const content = script.content ?? \"\";\n  const contentLength = content.length;\n  const lines = content.split(\"\\n\");\n  const files = {};\n  const totalBytes = contentLength;\n  let unmappedBytes = totalBytes;\n  const mappingEndCols = computeMappingEndColumns(script.sourceMap);\n  for (const mapping of map.mappings()) {\n    const source = mapping.sourceURL;\n    const lineNum = mapping.lineNumber;\n    const colNum = mapping.columnNumber;\n    const lastColNum = mappingEndCols.get(mapping);\n    if (!source) {\n      continue;\n    }\n    const line = lines[lineNum];\n    if (line === null || line === void 0) {\n      const errorMessage = `${map.url()} mapping for line out of bounds: ${lineNum + 1}`;\n      return { errorMessage };\n    }\n    if (colNum > line.length) {\n      const errorMessage = `${map.url()} mapping for column out of bounds: ${lineNum + 1}:${colNum}`;\n      return { errorMessage };\n    }\n    let mappingLength = 0;\n    if (lastColNum !== void 0) {\n      if (lastColNum > line.length) {\n        const errorMessage = `${map.url()} mapping for last column out of bounds: ${lineNum + 1}:${lastColNum}`;\n        return { errorMessage };\n      }\n      mappingLength = lastColNum - colNum;\n    } else {\n      mappingLength = line.length - colNum + 1;\n    }\n    files[source] = (files[source] || 0) + mappingLength;\n    unmappedBytes -= mappingLength;\n  }\n  return {\n    files,\n    unmappedBytes,\n    totalBytes\n  };\n}\nfunction getScriptGeneratedSizes(script) {\n  if (script.sourceMap && !script.sizes) {\n    script.sizes = computeGeneratedFileSizes(script);\n  }\n  return script.sizes ?? null;\n}\nfunction findCachedRawSourceMap(script, options) {\n  if (options.isFreshRecording || !options.metadata?.sourceMaps) {\n    return;\n  }\n  if (script.sourceMapUrlElided) {\n    if (!script.url) {\n      return;\n    }\n    const cachedSourceMap = options.metadata.sourceMaps.find((m) => m.url === script.url);\n    if (cachedSourceMap) {\n      return cachedSourceMap.sourceMap;\n    }\n    return;\n  }\n  if (!script.sourceMapUrl) {\n    return;\n  }\n  const isDataUrl = script.sourceMapUrl.startsWith(\"data:\");\n  if (!isDataUrl) {\n    const cachedSourceMap = options.metadata.sourceMaps.find((m) => m.sourceMapUrl === script.sourceMapUrl);\n    if (cachedSourceMap) {\n      return cachedSourceMap.sourceMap;\n    }\n  }\n  return;\n}\nasync function finalize26(options) {\n  const meta = data5();\n  const networkRequests = [...data6().byId.values()];\n  const documentUrls = /* @__PURE__ */ new Set();\n  for (const frames2 of meta.frameByProcessId.values()) {\n    for (const frame of frames2.values()) {\n      documentUrls.add(frame.url);\n    }\n  }\n  for (const script of scriptById.values()) {\n    script.request = findNetworkRequest(networkRequests, script) ?? void 0;\n    script.inline = !!script.url && documentUrls.has(script.url);\n  }\n  if (!options.resolveSourceMap) {\n    return;\n  }\n  const promises = [];\n  for (const script of scriptById.values()) {\n    if (!script.frame || !script.url || !script.sourceMapUrl && !script.sourceMapUrlElided) {\n      continue;\n    }\n    const frameUrl = findFrame(meta, script.frame)?.url;\n    if (!frameUrl) {\n      continue;\n    }\n    let sourceUrl = script.url;\n    if (script.sourceUrl) {\n      sourceUrl = completeURL(frameUrl, script.sourceUrl) ?? script.sourceUrl;\n    }\n    let sourceMapUrl;\n    if (script.sourceMapUrl) {\n      sourceMapUrl = completeURL(sourceUrl, script.sourceMapUrl);\n      if (!sourceMapUrl) {\n        continue;\n      }\n      script.sourceMapUrl = sourceMapUrl;\n    }\n    const params = {\n      scriptId: script.scriptId,\n      scriptUrl: script.url,\n      sourceUrl,\n      sourceMapUrl: sourceMapUrl ?? \"\",\n      frame: script.frame,\n      cachedRawSourceMap: findCachedRawSourceMap(script, options)\n    };\n    const promise = options.resolveSourceMap(params).then((sourceMap) => {\n      if (sourceMap) {\n        script.sourceMap = sourceMap;\n      }\n    });\n    promises.push(promise.catch((e) => {\n      console.error(\"Uncaught error when resolving source map\", params, e);\n    }));\n  }\n  await Promise.all(promises);\n}\nfunction data26() {\n  return {\n    scripts: [...scriptById.values()]\n  };\n}\nvar scriptById;\nvar init_ScriptsHandler = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/handlers/ScriptsHandler.js\"() {\n    init_process_global();\n    init_platform();\n    init_types2();\n    init_MetaHandler();\n    init_NetworkRequestsHandler();\n    __name(completeURL, \"completeURL\");\n    scriptById = /* @__PURE__ */ new Map();\n    __name(deps14, \"deps\");\n    __name(reset26, \"reset\");\n    __name(handleEvent26, \"handleEvent\");\n    __name(findFrame, \"findFrame\");\n    __name(findNetworkRequest, \"findNetworkRequest\");\n    __name(computeMappingEndColumns, \"computeMappingEndColumns\");\n    __name(computeGeneratedFileSizes, \"computeGeneratedFileSizes\");\n    __name(getScriptGeneratedSizes, \"getScriptGeneratedSizes\");\n    __name(findCachedRawSourceMap, \"findCachedRawSourceMap\");\n    __name(finalize26, \"finalize\");\n    __name(data26, \"data\");\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/handlers/SelectorStatsHandler.js\nvar SelectorStatsHandler_exports = {};\n__export(SelectorStatsHandler_exports, {\n  data: () => data27,\n  finalize: () => finalize27,\n  handleEvent: () => handleEvent27,\n  reset: () => reset27\n});\nfunction reset27() {\n  lastRecalcStyleEvent = null;\n  lastInvalidatedNode = null;\n  selectorDataForRecalcStyle = /* @__PURE__ */ new Map();\n  invalidatedNodeList = [];\n}\nfunction handleEvent27(event) {\n  if (TraceEvents_exports.isStyleRecalcInvalidationTracking(event)) {\n    if (event.args.data.subtree && event.args.data.reason === TraceEvents_exports.StyleRecalcInvalidationReason.RELATED_STYLE_RULE && lastInvalidatedNode && event.args.data.nodeId === lastInvalidatedNode.backendNodeId) {\n      lastInvalidatedNode.subtree = true;\n      return;\n    }\n  }\n  if (TraceEvents_exports.isSelectorStats(event) && lastRecalcStyleEvent && event.args.selector_stats) {\n    selectorDataForRecalcStyle.set(lastRecalcStyleEvent, {\n      timings: event.args.selector_stats.selector_timings\n    });\n    return;\n  }\n  if (TraceEvents_exports.isStyleInvalidatorInvalidationTracking(event)) {\n    const selectorList = new Array();\n    event.args.data.selectors?.forEach((selector) => {\n      selectorList.push({\n        selector: selector.selector,\n        styleSheetId: selector.style_sheet_id\n      });\n    });\n    if (selectorList.length > 0) {\n      lastInvalidatedNode = {\n        frame: event.args.data.frame,\n        backendNodeId: event.args.data.nodeId,\n        type: TraceEvents_exports.InvalidationEventType.StyleInvalidatorInvalidationTracking,\n        selectorList,\n        ts: event.ts,\n        tts: event.tts,\n        subtree: false,\n        lastRecalcStyleEventTs: lastRecalcStyleEvent ? lastRecalcStyleEvent.ts : Timing_exports.Micro(0)\n      };\n      invalidatedNodeList.push(lastInvalidatedNode);\n    }\n  }\n  if (TraceEvents_exports.isRecalcStyle(event)) {\n    lastRecalcStyleEvent = event;\n    return;\n  }\n}\nasync function finalize27() {\n}\nfunction data27() {\n  return {\n    dataForRecalcStyleEvent: selectorDataForRecalcStyle,\n    invalidatedNodeList\n  };\n}\nvar lastRecalcStyleEvent, lastInvalidatedNode, selectorDataForRecalcStyle, invalidatedNodeList;\nvar init_SelectorStatsHandler = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/handlers/SelectorStatsHandler.js\"() {\n    init_process_global();\n    init_types2();\n    lastRecalcStyleEvent = null;\n    lastInvalidatedNode = null;\n    selectorDataForRecalcStyle = /* @__PURE__ */ new Map();\n    invalidatedNodeList = new Array();\n    __name(reset27, \"reset\");\n    __name(handleEvent27, \"handleEvent\");\n    __name(finalize27, \"finalize\");\n    __name(data27, \"data\");\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/handlers/UserInteractionsHandler.js\nvar UserInteractionsHandler_exports = {};\n__export(UserInteractionsHandler_exports, {\n  LONG_INTERACTION_THRESHOLD: () => LONG_INTERACTION_THRESHOLD,\n  categoryOfInteraction: () => categoryOfInteraction,\n  data: () => data28,\n  deps: () => deps15,\n  finalize: () => finalize28,\n  handleEvent: () => handleEvent28,\n  removeNestedInteractionsAndSetProcessingTime: () => removeNestedInteractionsAndSetProcessingTime,\n  reset: () => reset28,\n  scoreClassificationForInteractionToNextPaint: () => scoreClassificationForInteractionToNextPaint\n});\nfunction reset28() {\n  beginCommitCompositorFrameEvents = [];\n  parseMetaViewportEvents = [];\n  interactionEvents = [];\n  eventTimingStartEventsForInteractions = [];\n  eventTimingEndEventsForInteractions = [];\n  interactionEventsWithNoNesting = [];\n  longestInteractionEvent = null;\n}\nfunction handleEvent28(event) {\n  if (TraceEvents_exports.isBeginCommitCompositorFrame(event)) {\n    beginCommitCompositorFrameEvents.push(event);\n    return;\n  }\n  if (TraceEvents_exports.isParseMetaViewport(event)) {\n    parseMetaViewportEvents.push(event);\n    return;\n  }\n  if (!TraceEvents_exports.isEventTiming(event)) {\n    return;\n  }\n  if (TraceEvents_exports.isEventTimingEnd(event)) {\n    eventTimingEndEventsForInteractions.push(event);\n  }\n  if (!event.args.data || !TraceEvents_exports.isEventTimingStart(event)) {\n    return;\n  }\n  const { duration, interactionId } = event.args.data;\n  if (duration < 1 || interactionId === void 0 || interactionId === 0) {\n    return;\n  }\n  eventTimingStartEventsForInteractions.push(event);\n}\nfunction categoryOfInteraction(interaction) {\n  if (pointerEventTypes.has(interaction.type)) {\n    return \"POINTER\";\n  }\n  if (keyboardEventTypes.has(interaction.type)) {\n    return \"KEYBOARD\";\n  }\n  return \"OTHER\";\n}\nfunction removeNestedInteractionsAndSetProcessingTime(interactions) {\n  const earliestEventForEndTimePerCategory = {\n    POINTER: /* @__PURE__ */ new Map(),\n    KEYBOARD: /* @__PURE__ */ new Map(),\n    OTHER: /* @__PURE__ */ new Map()\n  };\n  function storeEventIfEarliestForCategoryAndEndTime(interaction) {\n    const category = categoryOfInteraction(interaction);\n    const earliestEventForEndTime = earliestEventForEndTimePerCategory[category];\n    const endTime = Timing_exports.Micro(interaction.ts + interaction.dur);\n    const earliestCurrentEvent = earliestEventForEndTime.get(endTime);\n    if (!earliestCurrentEvent) {\n      earliestEventForEndTime.set(endTime, interaction);\n      return;\n    }\n    if (interaction.ts < earliestCurrentEvent.ts) {\n      earliestEventForEndTime.set(endTime, interaction);\n    } else if (interaction.ts === earliestCurrentEvent.ts && interaction.interactionId === earliestCurrentEvent.interactionId) {\n      const currentProcessingDuration = earliestCurrentEvent.processingEnd - earliestCurrentEvent.processingStart;\n      const newProcessingDuration = interaction.processingEnd - interaction.processingStart;\n      if (newProcessingDuration > currentProcessingDuration) {\n        earliestEventForEndTime.set(endTime, interaction);\n      }\n    }\n    if (interaction.processingStart < earliestCurrentEvent.processingStart) {\n      earliestCurrentEvent.processingStart = interaction.processingStart;\n      writeSyntheticTimespans(earliestCurrentEvent);\n    }\n    if (interaction.processingEnd > earliestCurrentEvent.processingEnd) {\n      earliestCurrentEvent.processingEnd = interaction.processingEnd;\n      writeSyntheticTimespans(earliestCurrentEvent);\n    }\n  }\n  __name(storeEventIfEarliestForCategoryAndEndTime, \"storeEventIfEarliestForCategoryAndEndTime\");\n  for (const interaction of interactions) {\n    storeEventIfEarliestForCategoryAndEndTime(interaction);\n  }\n  const keptEvents = Object.values(earliestEventForEndTimePerCategory).flatMap((eventsByEndTime) => Array.from(eventsByEndTime.values()));\n  keptEvents.sort((eventA, eventB) => {\n    return eventA.ts - eventB.ts;\n  });\n  return keptEvents;\n}\nfunction writeSyntheticTimespans(event) {\n  const startEvent = event.args.data.beginEvent;\n  const endEvent = event.args.data.endEvent;\n  event.inputDelay = Timing_exports.Micro(event.processingStart - startEvent.ts);\n  event.mainThreadHandling = Timing_exports.Micro(event.processingEnd - event.processingStart);\n  event.presentationDelay = Timing_exports.Micro(endEvent.ts - event.processingEnd);\n}\nasync function finalize28() {\n  const { navigationsByFrameId: navigationsByFrameId2 } = data5();\n  const beginAndEndEvents = ArrayUtilities_exports.mergeOrdered(eventTimingStartEventsForInteractions, eventTimingEndEventsForInteractions, Trace_exports.eventTimeComparator);\n  const beginEventById = /* @__PURE__ */ new Map();\n  for (const event of beginAndEndEvents) {\n    if (TraceEvents_exports.isEventTimingStart(event)) {\n      const forId = beginEventById.get(event.id) ?? [];\n      forId.push(event);\n      beginEventById.set(event.id, forId);\n    } else if (TraceEvents_exports.isEventTimingEnd(event)) {\n      const beginEvents = beginEventById.get(event.id) ?? [];\n      const beginEvent = beginEvents.pop();\n      if (!beginEvent) {\n        continue;\n      }\n      const { type, interactionId, timeStamp, processingStart, processingEnd } = beginEvent.args.data;\n      if (!type || !interactionId || !timeStamp || !processingStart || !processingEnd) {\n        continue;\n      }\n      const processingStartRelativeToTraceTime = Timing_exports.Micro(Timing_exports3.milliToMicro(processingStart) - Timing_exports3.milliToMicro(timeStamp) + beginEvent.ts);\n      const processingEndRelativeToTraceTime = Timing_exports.Micro(Timing_exports3.milliToMicro(processingEnd) - Timing_exports3.milliToMicro(timeStamp) + beginEvent.ts);\n      const frameId = beginEvent.args.frame ?? beginEvent.args.data.frame ?? \"\";\n      const navigation2 = Trace_exports.getNavigationForTraceEvent(beginEvent, frameId, navigationsByFrameId2);\n      const navigationId = navigation2?.args.data?.navigationId;\n      const interactionEvent = SyntheticEvents_exports.SyntheticEventsManager.registerSyntheticEvent({\n        // Use the start event to define the common fields.\n        rawSourceEvent: beginEvent,\n        cat: beginEvent.cat,\n        name: beginEvent.name,\n        pid: beginEvent.pid,\n        tid: beginEvent.tid,\n        ph: beginEvent.ph,\n        processingStart: processingStartRelativeToTraceTime,\n        processingEnd: processingEndRelativeToTraceTime,\n        // These will be set in writeSyntheticTimespans()\n        inputDelay: Timing_exports.Micro(-1),\n        mainThreadHandling: Timing_exports.Micro(-1),\n        presentationDelay: Timing_exports.Micro(-1),\n        args: {\n          data: {\n            beginEvent,\n            endEvent: event,\n            frame: frameId,\n            navigationId\n          }\n        },\n        ts: beginEvent.ts,\n        dur: Timing_exports.Micro(event.ts - beginEvent.ts),\n        type: beginEvent.args.data.type,\n        interactionId: beginEvent.args.data.interactionId\n      });\n      writeSyntheticTimespans(interactionEvent);\n      interactionEvents.push(interactionEvent);\n    }\n  }\n  Trace_exports.sortTraceEventsInPlace(interactionEvents);\n  interactionEventsWithNoNesting.push(...removeNestedInteractionsAndSetProcessingTime(interactionEvents));\n  for (const interactionEvent of interactionEventsWithNoNesting) {\n    if (!longestInteractionEvent || longestInteractionEvent.dur < interactionEvent.dur) {\n      longestInteractionEvent = interactionEvent;\n    }\n  }\n}\nfunction data28() {\n  return {\n    beginCommitCompositorFrameEvents,\n    parseMetaViewportEvents,\n    interactionEvents,\n    interactionEventsWithNoNesting,\n    longestInteractionEvent,\n    interactionsOverThreshold: new Set(interactionEvents.filter((event) => {\n      return event.dur > LONG_INTERACTION_THRESHOLD;\n    }))\n  };\n}\nfunction deps15() {\n  return [\"Meta\"];\n}\nfunction scoreClassificationForInteractionToNextPaint(timing) {\n  if (timing <= INP_GOOD_TIMING) {\n    return ScoreClassification.GOOD;\n  }\n  if (timing <= INP_MEDIUM_TIMING) {\n    return ScoreClassification.OK;\n  }\n  return ScoreClassification.BAD;\n}\nvar beginCommitCompositorFrameEvents, parseMetaViewportEvents, LONG_INTERACTION_THRESHOLD, INP_GOOD_TIMING, INP_MEDIUM_TIMING, longestInteractionEvent, interactionEvents, interactionEventsWithNoNesting, eventTimingStartEventsForInteractions, eventTimingEndEventsForInteractions, pointerEventTypes, keyboardEventTypes;\nvar init_UserInteractionsHandler = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/handlers/UserInteractionsHandler.js\"() {\n    init_process_global();\n    init_platform();\n    init_helpers2();\n    init_types2();\n    init_MetaHandler();\n    init_PageLoadMetricsHandler();\n    beginCommitCompositorFrameEvents = [];\n    parseMetaViewportEvents = [];\n    LONG_INTERACTION_THRESHOLD = Timing_exports3.milliToMicro(Timing_exports.Milli(200));\n    INP_GOOD_TIMING = LONG_INTERACTION_THRESHOLD;\n    INP_MEDIUM_TIMING = Timing_exports3.milliToMicro(Timing_exports.Milli(500));\n    longestInteractionEvent = null;\n    interactionEvents = [];\n    interactionEventsWithNoNesting = [];\n    eventTimingStartEventsForInteractions = [];\n    eventTimingEndEventsForInteractions = [];\n    __name(reset28, \"reset\");\n    __name(handleEvent28, \"handleEvent\");\n    pointerEventTypes = /* @__PURE__ */ new Set([\n      \"pointerdown\",\n      \"touchstart\",\n      \"pointerup\",\n      \"touchend\",\n      \"mousedown\",\n      \"mouseup\",\n      \"click\"\n    ]);\n    keyboardEventTypes = /* @__PURE__ */ new Set([\n      \"keydown\",\n      \"keypress\",\n      \"keyup\"\n    ]);\n    __name(categoryOfInteraction, \"categoryOfInteraction\");\n    __name(removeNestedInteractionsAndSetProcessingTime, \"removeNestedInteractionsAndSetProcessingTime\");\n    __name(writeSyntheticTimespans, \"writeSyntheticTimespans\");\n    __name(finalize28, \"finalize\");\n    __name(data28, \"data\");\n    __name(deps15, \"deps\");\n    __name(scoreClassificationForInteractionToNextPaint, \"scoreClassificationForInteractionToNextPaint\");\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/handlers/WorkersHandler.js\nvar WorkersHandler_exports = {};\n__export(WorkersHandler_exports, {\n  data: () => data29,\n  finalize: () => finalize29,\n  handleEvent: () => handleEvent29,\n  reset: () => reset29\n});\nfunction reset29() {\n  sessionIdEvents = [];\n  workerIdByThread = /* @__PURE__ */ new Map();\n  workerURLById = /* @__PURE__ */ new Map();\n}\nfunction handleEvent29(event) {\n  if (TraceEvents_exports.isTracingSessionIdForWorker(event)) {\n    sessionIdEvents.push(event);\n  }\n}\nasync function finalize29() {\n  for (const sessionIdEvent of sessionIdEvents) {\n    if (!sessionIdEvent.args.data) {\n      continue;\n    }\n    workerIdByThread.set(sessionIdEvent.args.data.workerThreadId, sessionIdEvent.args.data.workerId);\n    workerURLById.set(sessionIdEvent.args.data.workerId, sessionIdEvent.args.data.url);\n  }\n}\nfunction data29() {\n  return {\n    workerSessionIdEvents: sessionIdEvents,\n    workerIdByThread,\n    workerURLById\n  };\n}\nvar sessionIdEvents, workerIdByThread, workerURLById;\nvar init_WorkersHandler = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/handlers/WorkersHandler.js\"() {\n    init_process_global();\n    init_types2();\n    sessionIdEvents = [];\n    workerIdByThread = /* @__PURE__ */ new Map();\n    workerURLById = /* @__PURE__ */ new Map();\n    __name(reset29, \"reset\");\n    __name(handleEvent29, \"handleEvent\");\n    __name(finalize29, \"finalize\");\n    __name(data29, \"data\");\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/handlers/WarningsHandler.js\nvar WarningsHandler_exports = {};\n__export(WarningsHandler_exports, {\n  FORCED_REFLOW_THRESHOLD: () => FORCED_REFLOW_THRESHOLD,\n  LONG_MAIN_THREAD_TASK_THRESHOLD: () => LONG_MAIN_THREAD_TASK_THRESHOLD,\n  data: () => data30,\n  deps: () => deps16,\n  finalize: () => finalize30,\n  handleEvent: () => handleEvent30,\n  reset: () => reset30\n});\nfunction reset30() {\n  warningsPerEvent = /* @__PURE__ */ new Map();\n  eventsPerWarning = /* @__PURE__ */ new Map();\n  allEventsStack = [];\n  jsInvokeStack = [];\n  taskReflowEvents = [];\n  longTaskEvents = [];\n}\nfunction storeWarning(event, warning) {\n  const existingWarnings = MapUtilities_exports.getWithDefault(warningsPerEvent, event, () => []);\n  existingWarnings.push(warning);\n  warningsPerEvent.set(event, existingWarnings);\n  const existingEvents = MapUtilities_exports.getWithDefault(eventsPerWarning, warning, () => []);\n  existingEvents.push(event);\n  eventsPerWarning.set(warning, existingEvents);\n}\nfunction handleEvent30(event) {\n  processForcedReflowWarning(event);\n  if (event.name === TraceEvents_exports.Name.RUN_TASK) {\n    const { duration } = Timing_exports3.eventTimingsMicroSeconds(event);\n    if (duration > LONG_MAIN_THREAD_TASK_THRESHOLD) {\n      longTaskEvents.push(event);\n    }\n    return;\n  }\n  if (TraceEvents_exports.isFireIdleCallback(event)) {\n    const { duration } = Timing_exports3.eventTimingsMilliSeconds(event);\n    if (duration > event.args.data.allottedMilliseconds) {\n      storeWarning(event, \"IDLE_CALLBACK_OVER_TIME\");\n    }\n    return;\n  }\n}\nfunction processForcedReflowWarning(event) {\n  accomodateEventInStack(event, allEventsStack);\n  accomodateEventInStack(\n    event,\n    jsInvokeStack,\n    /* pushEventToStack */\n    TraceEvents_exports.isJSInvocationEvent(event)\n  );\n  if (jsInvokeStack.length) {\n    if (event.name === TraceEvents_exports.Name.LAYOUT || event.name === TraceEvents_exports.Name.RECALC_STYLE) {\n      taskReflowEvents.push(event);\n      return;\n    }\n  }\n  if (allEventsStack.length === 1) {\n    const totalTime = taskReflowEvents.reduce((time, event2) => time + (event2.dur || 0), 0);\n    if (totalTime >= FORCED_REFLOW_THRESHOLD) {\n      taskReflowEvents.forEach((reflowEvent) => storeWarning(reflowEvent, \"FORCED_REFLOW\"));\n    }\n    taskReflowEvents.length = 0;\n  }\n}\nfunction accomodateEventInStack(event, stack, pushEventToStack = true) {\n  let nextItem = stack.at(-1);\n  while (nextItem && event.ts > nextItem.ts + (nextItem.dur || 0)) {\n    stack.pop();\n    nextItem = stack.at(-1);\n  }\n  if (!pushEventToStack) {\n    return;\n  }\n  stack.push(event);\n}\nfunction deps16() {\n  return [\"UserInteractions\", \"Workers\"];\n}\nasync function finalize30() {\n  const longInteractions = data28().interactionsOverThreshold;\n  for (const interaction of longInteractions) {\n    storeWarning(interaction, \"LONG_INTERACTION\");\n  }\n  for (const event of longTaskEvents) {\n    if (!(event.tid, data29().workerIdByThread.has(event.tid))) {\n      storeWarning(event, \"LONG_TASK\");\n    }\n  }\n  longTaskEvents.length = 0;\n}\nfunction data30() {\n  return {\n    perEvent: warningsPerEvent,\n    perWarning: eventsPerWarning\n  };\n}\nvar warningsPerEvent, eventsPerWarning, allEventsStack, jsInvokeStack, taskReflowEvents, longTaskEvents, FORCED_REFLOW_THRESHOLD, LONG_MAIN_THREAD_TASK_THRESHOLD;\nvar init_WarningsHandler = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/handlers/WarningsHandler.js\"() {\n    init_process_global();\n    init_platform();\n    init_helpers2();\n    init_types2();\n    init_UserInteractionsHandler();\n    init_WorkersHandler();\n    warningsPerEvent = /* @__PURE__ */ new Map();\n    eventsPerWarning = /* @__PURE__ */ new Map();\n    allEventsStack = [];\n    jsInvokeStack = [];\n    taskReflowEvents = [];\n    longTaskEvents = [];\n    FORCED_REFLOW_THRESHOLD = Timing_exports3.milliToMicro(Timing_exports.Milli(30));\n    LONG_MAIN_THREAD_TASK_THRESHOLD = Timing_exports3.milliToMicro(Timing_exports.Milli(50));\n    __name(reset30, \"reset\");\n    __name(storeWarning, \"storeWarning\");\n    __name(handleEvent30, \"handleEvent\");\n    __name(processForcedReflowWarning, \"processForcedReflowWarning\");\n    __name(accomodateEventInStack, \"accomodateEventInStack\");\n    __name(deps16, \"deps\");\n    __name(finalize30, \"finalize\");\n    __name(data30, \"data\");\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/handlers/ModelHandlers.js\nvar ModelHandlers_exports = {};\n__export(ModelHandlers_exports, {\n  AnimationFrames: () => AnimationFramesHandler_exports,\n  Animations: () => AnimationHandler_exports,\n  AsyncJSCalls: () => AsyncJSCallsHandler_exports,\n  AuctionWorklets: () => AuctionWorkletsHandler_exports,\n  DOMStats: () => DOMStatsHandler_exports,\n  ExtensionTraceData: () => ExtensionTraceDataHandler_exports,\n  Flows: () => FlowsHandler_exports,\n  Frames: () => FramesHandler_exports,\n  GPU: () => GPUHandler_exports,\n  ImagePainting: () => ImagePaintingHandler_exports,\n  Initiators: () => InitiatorsHandler_exports,\n  Invalidations: () => InvalidationsHandler_exports,\n  LargestImagePaint: () => LargestImagePaintHandler_exports,\n  LargestTextPaint: () => LargestTextPaintHandler_exports,\n  LayerTree: () => LayerTreeHandler_exports,\n  LayoutShifts: () => LayoutShiftsHandler_exports,\n  Memory: () => MemoryHandler_exports,\n  Meta: () => MetaHandler_exports,\n  NetworkRequests: () => NetworkRequestsHandler_exports,\n  PageFrames: () => PageFramesHandler_exports,\n  PageLoadMetrics: () => PageLoadMetricsHandler_exports,\n  Renderer: () => RendererHandler_exports,\n  Samples: () => SamplesHandler_exports,\n  Screenshots: () => ScreenshotsHandler_exports,\n  Scripts: () => ScriptsHandler_exports,\n  SelectorStats: () => SelectorStatsHandler_exports,\n  UserInteractions: () => UserInteractionsHandler_exports,\n  UserTimings: () => UserTimingsHandler_exports,\n  Warnings: () => WarningsHandler_exports,\n  Workers: () => WorkersHandler_exports\n});\nvar init_ModelHandlers = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/handlers/ModelHandlers.js\"() {\n    init_process_global();\n    init_AnimationFramesHandler();\n    init_AnimationHandler();\n    init_AsyncJSCallsHandler();\n    init_AuctionWorkletsHandler();\n    init_DOMStatsHandler();\n    init_ExtensionTraceDataHandler();\n    init_FlowsHandler();\n    init_FramesHandler();\n    init_GPUHandler();\n    init_ImagePaintingHandler();\n    init_InitiatorsHandler();\n    init_InvalidationsHandler();\n    init_LargestImagePaintHandler();\n    init_LargestTextPaintHandler();\n    init_LayerTreeHandler();\n    init_LayoutShiftsHandler();\n    init_MemoryHandler();\n    init_MetaHandler();\n    init_NetworkRequestsHandler();\n    init_PageFramesHandler();\n    init_PageLoadMetricsHandler();\n    init_RendererHandler();\n    init_SamplesHandler();\n    init_ScreenshotsHandler();\n    init_ScriptsHandler();\n    init_SelectorStatsHandler();\n    init_UserInteractionsHandler();\n    init_UserTimingsHandler();\n    init_WarningsHandler();\n    init_WorkersHandler();\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/handlers/types.js\nvar init_types3 = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/handlers/types.js\"() {\n    init_process_global();\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/handlers/handlers.js\nvar init_handlers = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/handlers/handlers.js\"() {\n    init_process_global();\n    init_helpers();\n    init_ModelHandlers();\n    init_Threads();\n    init_types3();\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/EntityMapper.js\nvar init_EntityMapper = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/EntityMapper.js\"() {\n    init_process_global();\n    init_handlers();\n    init_helpers2();\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/EventsSerializer.js\nvar init_EventsSerializer = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/EventsSerializer.js\"() {\n    init_process_global();\n    init_helpers2();\n    init_types2();\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/extras/ScriptDuplication.js\nvar ScriptDuplication_exports = {};\n__export(ScriptDuplication_exports, {\n  computeScriptDuplication: () => computeScriptDuplication,\n  getNodeModuleName: () => getNodeModuleName,\n  normalizeDuplication: () => normalizeDuplication,\n  normalizeSource: () => normalizeSource\n});\nfunction normalizeSource(source) {\n  source = source.replace(/\\?$/, \"\");\n  const lastNodeModulesIndex = source.lastIndexOf(\"node_modules\");\n  if (lastNodeModulesIndex !== -1) {\n    source = source.substring(lastNodeModulesIndex);\n  }\n  return source;\n}\nfunction shouldIgnoreSource(source) {\n  if (source.includes(\"webpack/bootstrap\")) {\n    return true;\n  }\n  if (source.includes(\"(webpack)/buildin\")) {\n    return true;\n  }\n  if (source.includes(\"external \")) {\n    return true;\n  }\n  return false;\n}\nfunction normalizeDuplication(duplication) {\n  for (const [key, data31] of duplication) {\n    data31.duplicates.sort((a, b) => b.attributedSize - a.attributedSize);\n    if (data31.duplicates.length > 1) {\n      const largestResourceSize = data31.duplicates[0].attributedSize;\n      data31.duplicates = data31.duplicates.filter((duplicate) => {\n        const percentSize = duplicate.attributedSize / largestResourceSize;\n        return percentSize >= RELATIVE_SIZE_THRESHOLD;\n      });\n    }\n    data31.duplicates = data31.duplicates.filter((duplicate) => duplicate.attributedSize >= ABSOLUTE_SIZE_THRESHOLD_BYTES);\n    if (data31.duplicates.length <= 1) {\n      duplication.delete(key);\n      continue;\n    }\n    data31.estimatedDuplicateBytes = data31.duplicates.slice(1).reduce((acc, cur) => acc + cur.attributedSize, 0);\n  }\n}\nfunction indexOfOrLength(haystack, needle, startPosition = 0) {\n  const index = haystack.indexOf(needle, startPosition);\n  return index === -1 ? haystack.length : index;\n}\nfunction getNodeModuleName(source) {\n  const sourceSplit = source.split(\"node_modules/\");\n  source = sourceSplit[sourceSplit.length - 1];\n  const indexFirstSlash = indexOfOrLength(source, \"/\");\n  if (source[0] === \"@\") {\n    return source.slice(0, indexOfOrLength(source, \"/\", indexFirstSlash + 1));\n  }\n  return source.slice(0, indexFirstSlash);\n}\nfunction groupByNodeModules(duplication) {\n  const groupedDuplication = /* @__PURE__ */ new Map();\n  for (const [source, data31] of duplication) {\n    if (!source.includes(\"node_modules\")) {\n      groupedDuplication.set(source, data31);\n      continue;\n    }\n    const nodeModuleKey = \"node_modules/\" + getNodeModuleName(source);\n    const aggregatedData = groupedDuplication.get(nodeModuleKey) ?? {\n      duplicates: [],\n      // This is calculated in normalizeDuplication.\n      estimatedDuplicateBytes: 0\n    };\n    groupedDuplication.set(nodeModuleKey, aggregatedData);\n    for (const { script, attributedSize } of data31.duplicates) {\n      let duplicate = aggregatedData.duplicates.find((d) => d.script === script);\n      if (!duplicate) {\n        duplicate = { script, attributedSize: 0 };\n        aggregatedData.duplicates.push(duplicate);\n      }\n      duplicate.attributedSize += attributedSize;\n    }\n  }\n  return groupedDuplication;\n}\nfunction sorted(duplication) {\n  return new Map([...duplication].sort((a, b) => b[1].estimatedDuplicateBytes - a[1].estimatedDuplicateBytes));\n}\nfunction computeScriptDuplication(scriptsData, compressionRatios) {\n  const sourceDatasMap = /* @__PURE__ */ new Map();\n  for (const script of scriptsData.scripts) {\n    if (!script.content || !script.sourceMap) {\n      continue;\n    }\n    const sizes = ModelHandlers_exports.Scripts.getScriptGeneratedSizes(script);\n    if (!sizes) {\n      continue;\n    }\n    if (\"errorMessage\" in sizes) {\n      console.error(sizes.errorMessage);\n      continue;\n    }\n    const sourceDataArray = [];\n    sourceDatasMap.set(script, sourceDataArray);\n    const sources = script.sourceMap.sourceURLs();\n    for (let i = 0; i < sources.length; i++) {\n      if (shouldIgnoreSource(sources[i])) {\n        continue;\n      }\n      const sourceSize = sizes.files[sources[i]];\n      sourceDataArray.push({\n        source: normalizeSource(sources[i]),\n        resourceSize: sourceSize\n      });\n    }\n  }\n  const duplication = /* @__PURE__ */ new Map();\n  for (const [script, sourceDataArray] of sourceDatasMap) {\n    for (const sourceData of sourceDataArray) {\n      let data31 = duplication.get(sourceData.source);\n      if (!data31) {\n        data31 = { estimatedDuplicateBytes: 0, duplicates: [] };\n        duplication.set(sourceData.source, data31);\n      }\n      const compressionRatio = script.request ? compressionRatios.get(script.request?.args.data.requestId) ?? 1 : 1;\n      const transferSize = Math.round(sourceData.resourceSize * compressionRatio);\n      data31.duplicates.push({\n        script,\n        attributedSize: transferSize\n      });\n    }\n  }\n  const duplicationGroupedByNodeModules = groupByNodeModules(duplication);\n  normalizeDuplication(duplication);\n  normalizeDuplication(duplicationGroupedByNodeModules);\n  return {\n    duplication: sorted(duplication),\n    duplicationGroupedByNodeModules: sorted(duplicationGroupedByNodeModules)\n  };\n}\nvar ABSOLUTE_SIZE_THRESHOLD_BYTES, RELATIVE_SIZE_THRESHOLD;\nvar init_ScriptDuplication = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/extras/ScriptDuplication.js\"() {\n    init_process_global();\n    init_handlers();\n    ABSOLUTE_SIZE_THRESHOLD_BYTES = 1024 * 0.5;\n    RELATIVE_SIZE_THRESHOLD = 0.1;\n    __name(normalizeSource, \"normalizeSource\");\n    __name(shouldIgnoreSource, \"shouldIgnoreSource\");\n    __name(normalizeDuplication, \"normalizeDuplication\");\n    __name(indexOfOrLength, \"indexOfOrLength\");\n    __name(getNodeModuleName, \"getNodeModuleName\");\n    __name(groupByNodeModules, \"groupByNodeModules\");\n    __name(sorted, \"sorted\");\n    __name(computeScriptDuplication, \"computeScriptDuplication\");\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/extras/StackTraceForEvent.js\nvar StackTraceForEvent_exports = {};\n__export(StackTraceForEvent_exports, {\n  clearCacheForTrace: () => clearCacheForTrace,\n  get: () => get,\n  stackTraceForEventInTrace: () => stackTraceForEventInTrace\n});\nfunction clearCacheForTrace(data31) {\n  stackTraceForEventInTrace.delete(data31);\n}\nfunction get(event, data31) {\n  let cacheForTrace = stackTraceForEventInTrace.get(data31);\n  if (!cacheForTrace) {\n    cacheForTrace = /* @__PURE__ */ new Map();\n    stackTraceForEventInTrace.set(data31, cacheForTrace);\n  }\n  const resultFromCache = cacheForTrace.get(event);\n  if (resultFromCache) {\n    return resultFromCache;\n  }\n  let result = null;\n  if (Extensions_exports.isSyntheticExtensionEntry(event)) {\n    result = getForExtensionEntry(event, data31);\n  } else if (TraceEvents_exports.isPerformanceMeasureBegin(event)) {\n    result = getForPerformanceMeasure(event, data31);\n  } else {\n    result = getForEvent(event, data31);\n    const payloadCallFrames = getTraceEventPayloadStackAsProtocolCallFrame(event).filter((callFrame) => !isNativeJSFunction(callFrame));\n    if (!result.callFrames.length) {\n      result.callFrames = payloadCallFrames;\n    } else {\n      for (let i = 0; i < payloadCallFrames.length && i < result.callFrames.length; i++) {\n        result.callFrames[i] = payloadCallFrames[i];\n      }\n    }\n  }\n  if (result) {\n    cacheForTrace.set(event, result);\n  }\n  return result;\n}\nfunction getForEvent(event, data31) {\n  const entryToNode4 = data31.Renderer.entryToNode.size > 0 ? data31.Renderer.entryToNode : data31.Samples.entryToNode;\n  const topStackTrace = { callFrames: [] };\n  let stackTrace = topStackTrace;\n  let currentEntry;\n  let node = entryToNode4.get(event);\n  const traceCache = stackTraceForEventInTrace.get(data31) || /* @__PURE__ */ new Map();\n  stackTraceForEventInTrace.set(data31, traceCache);\n  while (node) {\n    if (!TraceEvents_exports.isProfileCall(node.entry)) {\n      const maybeAsyncParent = data31.AsyncJSCalls.runEntryPointToScheduler.get(node.entry);\n      if (!maybeAsyncParent) {\n        node = node.parent;\n        continue;\n      }\n      const maybeAsyncParentNode2 = maybeAsyncParent && entryToNode4.get(maybeAsyncParent.scheduler);\n      if (maybeAsyncParentNode2) {\n        stackTrace = addAsyncParentToStack(stackTrace, maybeAsyncParent.taskName);\n        node = maybeAsyncParentNode2;\n      }\n      continue;\n    }\n    currentEntry = node.entry;\n    const stackTraceFromCache = traceCache.get(node.entry);\n    if (stackTraceFromCache) {\n      stackTrace.callFrames.push(...stackTraceFromCache.callFrames.filter((callFrame) => !isNativeJSFunction(callFrame)));\n      stackTrace.parent = stackTraceFromCache.parent;\n      stackTrace.description = stackTrace.description || stackTraceFromCache.description;\n      break;\n    }\n    if (!isNativeJSFunction(currentEntry.callFrame)) {\n      stackTrace.callFrames.push(currentEntry.callFrame);\n    }\n    const maybeAsyncParentEvent = data31.AsyncJSCalls.asyncCallToScheduler.get(currentEntry);\n    const maybeAsyncParentNode = maybeAsyncParentEvent && entryToNode4.get(maybeAsyncParentEvent.scheduler);\n    if (maybeAsyncParentNode) {\n      stackTrace = addAsyncParentToStack(stackTrace, maybeAsyncParentEvent.taskName);\n      node = maybeAsyncParentNode;\n      continue;\n    }\n    node = node.parent;\n  }\n  return topStackTrace;\n}\nfunction addAsyncParentToStack(stackTrace, taskName) {\n  const parent = { callFrames: [] };\n  stackTrace.parent = parent;\n  parent.description = taskName;\n  return parent;\n}\nfunction getForExtensionEntry(event, data31) {\n  const rawEvent = event.rawSourceEvent;\n  if (TraceEvents_exports.isPerformanceMeasureBegin(rawEvent)) {\n    return getForPerformanceMeasure(rawEvent, data31);\n  }\n  if (!rawEvent) {\n    return null;\n  }\n  return get(rawEvent, data31);\n}\nfunction getForPerformanceMeasure(event, data31) {\n  let rawEvent = event;\n  if (event.args.traceId === void 0) {\n    return null;\n  }\n  rawEvent = data31.UserTimings.measureTraceByTraceId.get(event.args.traceId);\n  if (!rawEvent) {\n    return null;\n  }\n  return get(rawEvent, data31);\n}\nfunction isNativeJSFunction({ columnNumber, lineNumber, url, scriptId }) {\n  return lineNumber === -1 && columnNumber === -1 && url === \"\" && scriptId === \"0\";\n}\nfunction getTraceEventPayloadStackAsProtocolCallFrame(event) {\n  const payloadCallStack = Trace_exports.getZeroIndexedStackTraceInEventPayload(event) || [];\n  const callFrames = [];\n  for (const frame of payloadCallStack) {\n    callFrames.push({ ...frame, scriptId: String(frame.scriptId) });\n  }\n  return callFrames;\n}\nvar stackTraceForEventInTrace;\nvar init_StackTraceForEvent = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/extras/StackTraceForEvent.js\"() {\n    init_process_global();\n    init_helpers2();\n    init_types2();\n    stackTraceForEventInTrace = /* @__PURE__ */ new Map();\n    __name(clearCacheForTrace, \"clearCacheForTrace\");\n    __name(get, \"get\");\n    __name(getForEvent, \"getForEvent\");\n    __name(addAsyncParentToStack, \"addAsyncParentToStack\");\n    __name(getForExtensionEntry, \"getForExtensionEntry\");\n    __name(getForPerformanceMeasure, \"getForPerformanceMeasure\");\n    __name(isNativeJSFunction, \"isNativeJSFunction\");\n    __name(getTraceEventPayloadStackAsProtocolCallFrame, \"getTraceEventPayloadStackAsProtocolCallFrame\");\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/extras/TraceFilter.js\nvar TraceFilter, VisibleEventsFilter, ExclusiveNameFilter;\nvar init_TraceFilter = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/extras/TraceFilter.js\"() {\n    init_process_global();\n    init_types2();\n    TraceFilter = class {\n      static {\n        __name(this, \"TraceFilter\");\n      }\n    };\n    VisibleEventsFilter = class _VisibleEventsFilter extends TraceFilter {\n      static {\n        __name(this, \"VisibleEventsFilter\");\n      }\n      visibleTypes;\n      constructor(visibleTypes) {\n        super();\n        this.visibleTypes = new Set(visibleTypes);\n      }\n      accept(event) {\n        if (Extensions_exports.isSyntheticExtensionEntry(event)) {\n          return true;\n        }\n        return this.visibleTypes.has(_VisibleEventsFilter.eventType(event));\n      }\n      static eventType(event) {\n        if (event.cat.includes(\"blink.console\")) {\n          return TraceEvents_exports.Name.CONSOLE_TIME;\n        }\n        if (event.cat.includes(\"blink.user_timing\")) {\n          return TraceEvents_exports.Name.USER_TIMING;\n        }\n        return event.name;\n      }\n    };\n    ExclusiveNameFilter = class extends TraceFilter {\n      static {\n        __name(this, \"ExclusiveNameFilter\");\n      }\n      #excludeNames;\n      constructor(excludeNames) {\n        super();\n        this.#excludeNames = new Set(excludeNames);\n      }\n      accept(event) {\n        return !this.#excludeNames.has(event.name);\n      }\n    };\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/extras/TraceTree.js\nfunction generateEventID(event) {\n  if (TraceEvents_exports.isProfileCall(event)) {\n    const name = SamplesIntegrator.isNativeRuntimeFrame(event.callFrame) ? SamplesIntegrator.nativeGroup(event.callFrame.functionName) : event.callFrame.functionName;\n    const location = event.callFrame.scriptId || event.callFrame.url || \"\";\n    return `f:${name}@${location}`;\n  }\n  if (TraceEvents_exports.isConsoleTimeStamp(event) && event.args.data) {\n    return `${event.name}:${event.args.data.name}`;\n  }\n  if (TraceEvents_exports.isSyntheticNetworkRequest(event) || TraceEvents_exports.isReceivedDataEvent(event)) {\n    return `req:${event.args.data.requestId}`;\n  }\n  return event.name;\n}\nvar Node2, BottomUpRootNode, GroupNode, BottomUpNode;\nvar init_TraceTree = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/extras/TraceTree.js\"() {\n    init_process_global();\n    init_helpers2();\n    init_SamplesIntegrator();\n    init_types2();\n    Node2 = class {\n      static {\n        __name(this, \"Node\");\n      }\n      /** ms */\n      totalTime;\n      /** ms */\n      selfTime;\n      transferSize;\n      id;\n      /** The first trace event encountered that necessitated the creation of this tree node. */\n      event;\n      /**\n       * All of the trace events associated with this aggregate node.\n       * Minor: In the case of Event Log (EventsTimelineTreeView), the node is not aggregate and this will only hold 1 event, the same that's in this.event\n       */\n      events;\n      parent;\n      groupId;\n      isGroupNodeInternal;\n      depth;\n      constructor(id, event) {\n        this.totalTime = 0;\n        this.selfTime = 0;\n        this.transferSize = 0;\n        this.id = id;\n        this.event = event;\n        this.events = [event];\n        this.groupId = \"\";\n        this.isGroupNodeInternal = false;\n        this.depth = 0;\n      }\n      isGroupNode() {\n        return this.isGroupNodeInternal;\n      }\n      hasChildren() {\n        throw new Error(\"Not implemented\");\n      }\n      setHasChildren(_value) {\n        throw new Error(\"Not implemented\");\n      }\n      /**\n       * Returns the direct descendants of this node.\n       * @returns a map with ordered <nodeId, Node> tuples.\n       */\n      children() {\n        throw new Error(\"Not implemented\");\n      }\n      searchTree(matchFunction, results) {\n        results = results || [];\n        if (this.event && matchFunction(this.event)) {\n          results.push(this);\n        }\n        for (const child of this.children().values()) {\n          child.searchTree(matchFunction, results);\n        }\n        return results;\n      }\n    };\n    BottomUpRootNode = class extends Node2 {\n      static {\n        __name(this, \"BottomUpRootNode\");\n      }\n      childrenInternal;\n      textFilter;\n      filter;\n      startTime;\n      endTime;\n      totalTime;\n      eventGroupIdCallback;\n      calculateTransferSize;\n      forceGroupIdCallback;\n      constructor(events, { textFilter, filters, startTime, endTime, eventGroupIdCallback, calculateTransferSize, forceGroupIdCallback }) {\n        super(\"\", events[0]);\n        this.childrenInternal = null;\n        this.events = events;\n        this.textFilter = textFilter;\n        this.filter = (e) => filters.every((f) => f.accept(e));\n        this.startTime = startTime;\n        this.endTime = endTime;\n        this.eventGroupIdCallback = eventGroupIdCallback;\n        this.totalTime = endTime - startTime;\n        this.calculateTransferSize = calculateTransferSize;\n        this.forceGroupIdCallback = forceGroupIdCallback;\n      }\n      hasChildren() {\n        return true;\n      }\n      filterChildren(children) {\n        for (const [id, child] of children) {\n          if (child.event && child.depth <= 1 && !this.textFilter.accept(child.event)) {\n            children.delete(id);\n          }\n        }\n        return children;\n      }\n      children() {\n        if (!this.childrenInternal) {\n          this.childrenInternal = this.filterChildren(this.grouppedTopNodes());\n        }\n        return this.childrenInternal;\n      }\n      // If no grouping is applied, the nodes returned here are what's initially shown in the bottom-up view.\n      // \"No grouping\" == no grouping in UI dropdown == no groupingFunction…\n      // … HOWEVER, nodes are still aggregated via `generateEventID`, which is ~= the event name.\n      ungroupedTopNodes() {\n        const root2 = this;\n        const startTime = this.startTime;\n        const endTime = this.endTime;\n        const nodeById = /* @__PURE__ */ new Map();\n        const selfTimeStack = [endTime - startTime];\n        const firstNodeStack = [];\n        const totalTimeById = /* @__PURE__ */ new Map();\n        const eventGroupIdCallback = this.eventGroupIdCallback;\n        const forceGroupIdCallback = this.forceGroupIdCallback;\n        const sumTransferSizeOfInstantEvent = /* @__PURE__ */ __name((e) => {\n          if (TraceEvents_exports.isReceivedDataEvent(e)) {\n            let id = generateEventID(e);\n            if (this.forceGroupIdCallback && this.eventGroupIdCallback) {\n              id = `${id}-${this.eventGroupIdCallback(e)}`;\n            }\n            let node = nodeById.get(id);\n            if (!node) {\n              node = new BottomUpNode(root2, id, e, false, root2);\n              nodeById.set(id, node);\n            } else {\n              node.events.push(e);\n            }\n            if (e.name === \"ResourceReceivedData\") {\n              node.transferSize += e.args.data.encodedDataLength;\n            } else if (e.args.data.encodedDataLength > 0) {\n              node.transferSize = e.args.data.encodedDataLength;\n            }\n          }\n        }, \"sumTransferSizeOfInstantEvent\");\n        Trace_exports.forEachEvent(this.events, {\n          onStartEvent,\n          onEndEvent,\n          onInstantEvent: this.calculateTransferSize ? sumTransferSizeOfInstantEvent : void 0,\n          startTime: Timing_exports3.milliToMicro(this.startTime),\n          endTime: Timing_exports3.milliToMicro(this.endTime),\n          eventFilter: this.filter,\n          ignoreAsyncEvents: false\n        });\n        function onStartEvent(e) {\n          const { startTime: currentStartTime, endTime: currentEndTime } = Timing_exports3.eventTimingsMilliSeconds(e);\n          const actualEndTime = currentEndTime !== void 0 ? Math.min(currentEndTime, endTime) : endTime;\n          const duration = actualEndTime - Math.max(currentStartTime, startTime);\n          selfTimeStack[selfTimeStack.length - 1] -= duration;\n          selfTimeStack.push(duration);\n          let id = generateEventID(e);\n          if (forceGroupIdCallback && eventGroupIdCallback) {\n            id = `${id}-${eventGroupIdCallback(e)}`;\n          }\n          const noNodeOnStack = !totalTimeById.has(id);\n          if (noNodeOnStack) {\n            totalTimeById.set(id, duration);\n          }\n          firstNodeStack.push(noNodeOnStack);\n        }\n        __name(onStartEvent, \"onStartEvent\");\n        function onEndEvent(event) {\n          let id = generateEventID(event);\n          if (forceGroupIdCallback && eventGroupIdCallback) {\n            id = `${id}-${eventGroupIdCallback(event)}`;\n          }\n          let node = nodeById.get(id);\n          if (!node) {\n            node = new BottomUpNode(root2, id, event, false, root2);\n            nodeById.set(id, node);\n          } else {\n            node.events.push(event);\n          }\n          node.selfTime += selfTimeStack.pop() || 0;\n          if (firstNodeStack.pop()) {\n            node.totalTime += totalTimeById.get(id) || 0;\n            totalTimeById.delete(id);\n          }\n          if (firstNodeStack.length) {\n            node.setHasChildren(true);\n          }\n        }\n        __name(onEndEvent, \"onEndEvent\");\n        this.selfTime = selfTimeStack.pop() || 0;\n        for (const pair of nodeById) {\n          if (pair[1].selfTime <= 0 && (!this.calculateTransferSize || pair[1].transferSize <= 0)) {\n            nodeById.delete(pair[0]);\n          }\n        }\n        return nodeById;\n      }\n      grouppedTopNodes() {\n        const flatNodes = this.ungroupedTopNodes();\n        if (!this.eventGroupIdCallback) {\n          return flatNodes;\n        }\n        const groupNodes = /* @__PURE__ */ new Map();\n        for (const node of flatNodes.values()) {\n          const groupId = this.eventGroupIdCallback(node.event);\n          let groupNode = groupNodes.get(groupId);\n          if (!groupNode) {\n            groupNode = new GroupNode(groupId, this, node.events);\n            groupNodes.set(groupId, groupNode);\n          } else {\n            for (const e of node.events) {\n              groupNode.events.push(e);\n            }\n          }\n          groupNode.addChild(node, node.selfTime, node.selfTime, node.transferSize);\n        }\n        return groupNodes;\n      }\n    };\n    GroupNode = class extends Node2 {\n      static {\n        __name(this, \"GroupNode\");\n      }\n      childrenInternal;\n      isGroupNodeInternal;\n      events;\n      constructor(id, parent, events) {\n        super(id, events[0]);\n        this.events = events;\n        this.childrenInternal = /* @__PURE__ */ new Map();\n        this.parent = parent;\n        this.isGroupNodeInternal = true;\n      }\n      addChild(child, selfTime, totalTime, transferSize) {\n        this.childrenInternal.set(child.id, child);\n        this.selfTime += selfTime;\n        this.totalTime += totalTime;\n        this.transferSize += transferSize;\n        child.parent = this;\n      }\n      hasChildren() {\n        return true;\n      }\n      children() {\n        return this.childrenInternal;\n      }\n    };\n    BottomUpNode = class _BottomUpNode extends Node2 {\n      static {\n        __name(this, \"BottomUpNode\");\n      }\n      parent;\n      root;\n      depth;\n      cachedChildren;\n      hasChildrenInternal;\n      constructor(root2, id, event, hasChildren, parent) {\n        super(id, event);\n        this.parent = parent;\n        this.root = root2;\n        this.depth = (parent.depth || 0) + 1;\n        this.cachedChildren = null;\n        this.hasChildrenInternal = hasChildren;\n      }\n      hasChildren() {\n        return this.hasChildrenInternal;\n      }\n      setHasChildren(value) {\n        this.hasChildrenInternal = value;\n      }\n      children() {\n        if (this.cachedChildren) {\n          return this.cachedChildren;\n        }\n        const selfTimeStack = [0];\n        const eventIdStack = [];\n        const eventStack = [];\n        const nodeById = /* @__PURE__ */ new Map();\n        const startTime = this.root.startTime;\n        const endTime = this.root.endTime;\n        let lastTimeMarker = startTime;\n        const self2 = this;\n        Trace_exports.forEachEvent(this.root.events, {\n          onStartEvent,\n          onEndEvent,\n          startTime: Timing_exports3.milliToMicro(startTime),\n          endTime: Timing_exports3.milliToMicro(endTime),\n          eventFilter: this.root.filter,\n          ignoreAsyncEvents: false\n        });\n        function onStartEvent(e) {\n          const { startTime: currentStartTime, endTime: currentEndTime } = Timing_exports3.eventTimingsMilliSeconds(e);\n          const actualEndTime = currentEndTime !== void 0 ? Math.min(currentEndTime, endTime) : endTime;\n          const duration = actualEndTime - Math.max(currentStartTime, startTime);\n          if (duration < 0) {\n            console.assert(false, \"Negative duration of an event\");\n          }\n          selfTimeStack[selfTimeStack.length - 1] -= duration;\n          selfTimeStack.push(duration);\n          const id = generateEventID(e);\n          eventIdStack.push(id);\n          eventStack.push(e);\n        }\n        __name(onStartEvent, \"onStartEvent\");\n        function onEndEvent(e) {\n          const { startTime: currentStartTime, endTime: currentEndTime } = Timing_exports3.eventTimingsMilliSeconds(e);\n          const selfTime = selfTimeStack.pop();\n          const id = eventIdStack.pop();\n          eventStack.pop();\n          let node;\n          for (node = self2; node.depth > 1; node = node.parent) {\n            if (node.id !== eventIdStack[eventIdStack.length + 1 - node.depth]) {\n              return;\n            }\n          }\n          if (node.id !== id || eventIdStack.length < self2.depth) {\n            return;\n          }\n          const childId = eventIdStack[eventIdStack.length - self2.depth];\n          node = nodeById.get(childId);\n          if (!node) {\n            const event = eventStack[eventStack.length - self2.depth];\n            const hasChildren = eventStack.length > self2.depth;\n            node = new _BottomUpNode(self2.root, childId, event, hasChildren, self2);\n            nodeById.set(childId, node);\n          } else {\n            node.events.push(e);\n          }\n          const actualEndTime = currentEndTime !== void 0 ? Math.min(currentEndTime, endTime) : endTime;\n          const totalTime = actualEndTime - Math.max(currentStartTime, lastTimeMarker);\n          node.selfTime += selfTime || 0;\n          node.totalTime += totalTime;\n          lastTimeMarker = actualEndTime;\n        }\n        __name(onEndEvent, \"onEndEvent\");\n        this.cachedChildren = this.root.filterChildren(nodeById);\n        return this.cachedChildren;\n      }\n      searchTree(matchFunction, results) {\n        results = results || [];\n        if (this.event && matchFunction(this.event)) {\n          results.push(this);\n        }\n        return results;\n      }\n    };\n    __name(generateEventID, \"generateEventID\");\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/extras/ThirdParties.js\nvar ThirdParties_exports = {};\n__export(ThirdParties_exports, {\n  summarizeByThirdParty: () => summarizeByThirdParty,\n  summarizeByURL: () => summarizeByURL\n});\nfunction collectMainThreadActivity(data31) {\n  const mainFrameMainThread = data31.Renderer.processes.values().find((p) => {\n    const url = p.url ?? \"\";\n    return p.isOnMainFrame && !url.startsWith(\"about:\") && !url.startsWith(\"chrome:\");\n  })?.threads.values().find((t) => t.name === \"CrRendererMain\");\n  if (!mainFrameMainThread) {\n    return [];\n  }\n  return mainFrameMainThread.entries;\n}\nfunction summarizeByThirdParty(data31, traceBounds2) {\n  const mainThreadEvents = collectMainThreadActivity(data31).sort(Trace_exports.eventTimeComparator);\n  const groupingFunction = /* @__PURE__ */ __name((event) => {\n    const entity = data31.Renderer.entityMappings.entityByEvent.get(event);\n    return entity?.name ?? \"\";\n  }, \"groupingFunction\");\n  const node = getBottomUpTree(mainThreadEvents, traceBounds2, groupingFunction);\n  const summaries = summarizeBottomUpByEntity(node, data31);\n  return summaries;\n}\nfunction summarizeByURL(data31, traceBounds2) {\n  const mainThreadEvents = collectMainThreadActivity(data31).sort(Trace_exports.eventTimeComparator);\n  const groupingFunction = /* @__PURE__ */ __name((event) => {\n    return helpers_exports.getNonResolvedURL(event, data31) ?? \"\";\n  }, \"groupingFunction\");\n  const node = getBottomUpTree(mainThreadEvents, traceBounds2, groupingFunction);\n  const summaries = summarizeBottomUpByURL(node, data31);\n  return summaries;\n}\nfunction summarizeBottomUpByEntity(root2, data31) {\n  const summaries = [];\n  const topNodes = [...root2.children().values()].flat();\n  for (const node of topNodes) {\n    if (node.id === \"\") {\n      continue;\n    }\n    const entity = data31.Renderer.entityMappings.entityByEvent.get(node.event);\n    if (!entity) {\n      continue;\n    }\n    const summary = {\n      transferSize: node.transferSize,\n      mainThreadTime: Timing_exports.Milli(node.selfTime),\n      entity,\n      relatedEvents: data31.Renderer.entityMappings.eventsByEntity.get(entity) ?? []\n    };\n    summaries.push(summary);\n  }\n  return summaries;\n}\nfunction summarizeBottomUpByURL(root2, data31) {\n  const summaries = [];\n  const allRequests = data31.NetworkRequests.byTime;\n  const topNodes = [...root2.children().values()].flat();\n  for (const node of topNodes) {\n    if (node.id === \"\" || typeof node.id !== \"string\") {\n      continue;\n    }\n    const entity = data31.Renderer.entityMappings.entityByEvent.get(node.event);\n    if (!entity) {\n      continue;\n    }\n    const url = node.id;\n    const request = allRequests.find((r) => r.args.data.url === url);\n    const summary = {\n      request,\n      url,\n      entity,\n      transferSize: node.transferSize,\n      mainThreadTime: Timing_exports.Milli(node.selfTime)\n    };\n    summaries.push(summary);\n  }\n  return summaries;\n}\nfunction getBottomUpTree(mainThreadEvents, tracebounds, groupingFunction) {\n  const visibleEvents = Trace_exports.VISIBLE_TRACE_EVENT_TYPES.values().toArray();\n  const filter = new VisibleEventsFilter(visibleEvents.concat([TraceEvents_exports.Name.SYNTHETIC_NETWORK_REQUEST]));\n  const startTime = Timing_exports3.microToMilli(tracebounds.min);\n  const endTime = Timing_exports3.microToMilli(tracebounds.max);\n  return new BottomUpRootNode(mainThreadEvents, {\n    textFilter: new ExclusiveNameFilter([]),\n    filters: [filter],\n    startTime,\n    endTime,\n    eventGroupIdCallback: groupingFunction,\n    calculateTransferSize: true,\n    // Ensure we group by 3P alongside eventID for correct 3P grouping.\n    forceGroupIdCallback: true\n  });\n}\nvar init_ThirdParties = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/extras/ThirdParties.js\"() {\n    init_process_global();\n    init_handlers();\n    init_helpers2();\n    init_types2();\n    init_TraceFilter();\n    init_TraceTree();\n    __name(collectMainThreadActivity, \"collectMainThreadActivity\");\n    __name(summarizeByThirdParty, \"summarizeByThirdParty\");\n    __name(summarizeByURL, \"summarizeByURL\");\n    __name(summarizeBottomUpByEntity, \"summarizeBottomUpByEntity\");\n    __name(summarizeBottomUpByURL, \"summarizeBottomUpByURL\");\n    __name(getBottomUpTree, \"getBottomUpTree\");\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/extras/extras.js\nvar init_extras = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/extras/extras.js\"() {\n    init_process_global();\n    init_ScriptDuplication();\n    init_StackTraceForEvent();\n    init_ThirdParties();\n    init_TraceFilter();\n    init_TraceTree();\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/insights/Statistics.js\nfunction erf2(x) {\n  const sign = Math.sign(x);\n  x = Math.abs(x);\n  const a1 = 0.254829592;\n  const a2 = -0.284496736;\n  const a3 = 1.421413741;\n  const a4 = -1.453152027;\n  const a5 = 1.061405429;\n  const p = 0.3275911;\n  const t = 1 / (1 + p * x);\n  const y = t * (a1 + t * (a2 + t * (a3 + t * (a4 + t * a5))));\n  return sign * (1 - y * Math.exp(-x * x));\n}\nfunction getLogNormalScore2({ median, p10 }, value) {\n  if (median <= 0) {\n    throw new Error(\"median must be greater than zero\");\n  }\n  if (p10 <= 0) {\n    throw new Error(\"p10 must be greater than zero\");\n  }\n  if (p10 >= median) {\n    throw new Error(\"p10 must be less than the median\");\n  }\n  if (value <= 0) {\n    return 1;\n  }\n  const INVERSE_ERFC_ONE_FIFTH = 0.9061938024368232;\n  const xRatio = Math.max(Number.MIN_VALUE, value / median);\n  const xLogRatio = Math.log(xRatio);\n  const p10Ratio = Math.max(Number.MIN_VALUE, p10 / median);\n  const p10LogRatio = -Math.log(p10Ratio);\n  const standardizedX = xLogRatio * INVERSE_ERFC_ONE_FIFTH / p10LogRatio;\n  const complementaryPercentile = (1 - erf2(standardizedX)) / 2;\n  let score;\n  if (value <= p10) {\n    score = Math.max(MIN_PASSING_SCORE2, Math.min(1, complementaryPercentile));\n  } else if (value <= median) {\n    score = Math.max(MIN_AVERAGE_SCORE2, Math.min(MAX_AVERAGE_SCORE2, complementaryPercentile));\n  } else {\n    score = Math.max(0, Math.min(MAX_FAILING_SCORE2, complementaryPercentile));\n  }\n  return score;\n}\nfunction linearInterpolation(x0, y0, x1, y1, x) {\n  const slope = (y1 - y0) / (x1 - x0);\n  return y0 + (x - x0) * slope;\n}\nvar MIN_PASSING_SCORE2, MAX_AVERAGE_SCORE2, MIN_AVERAGE_SCORE2, MAX_FAILING_SCORE2;\nvar init_Statistics = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/insights/Statistics.js\"() {\n    init_process_global();\n    /**\n     * @license\n     * Copyright 2017 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    MIN_PASSING_SCORE2 = 0.9;\n    MAX_AVERAGE_SCORE2 = 0.8999999999999999;\n    MIN_AVERAGE_SCORE2 = 0.5;\n    MAX_FAILING_SCORE2 = 0.49999999999999994;\n    __name(erf2, \"erf\");\n    __name(getLogNormalScore2, \"getLogNormalScore\");\n    __name(linearInterpolation, \"linearInterpolation\");\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/insights/types.js\nvar InsightWarning, InsightCategory, InsightKeys;\nvar init_types4 = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/insights/types.js\"() {\n    init_process_global();\n    (function(InsightWarning2) {\n      InsightWarning2[\"NO_FP\"] = \"NO_FP\";\n      InsightWarning2[\"NO_LCP\"] = \"NO_LCP\";\n      InsightWarning2[\"NO_DOCUMENT_REQUEST\"] = \"NO_DOCUMENT_REQUEST\";\n      InsightWarning2[\"NO_LAYOUT\"] = \"NO_LAYOUT\";\n    })(InsightWarning || (InsightWarning = {}));\n    (function(InsightCategory2) {\n      InsightCategory2[\"ALL\"] = \"All\";\n      InsightCategory2[\"INP\"] = \"INP\";\n      InsightCategory2[\"LCP\"] = \"LCP\";\n      InsightCategory2[\"CLS\"] = \"CLS\";\n    })(InsightCategory || (InsightCategory = {}));\n    (function(InsightKeys2) {\n      InsightKeys2[\"LCP_BREAKDOWN\"] = \"LCPBreakdown\";\n      InsightKeys2[\"INP_BREAKDOWN\"] = \"INPBreakdown\";\n      InsightKeys2[\"CLS_CULPRITS\"] = \"CLSCulprits\";\n      InsightKeys2[\"THIRD_PARTIES\"] = \"ThirdParties\";\n      InsightKeys2[\"DOCUMENT_LATENCY\"] = \"DocumentLatency\";\n      InsightKeys2[\"DOM_SIZE\"] = \"DOMSize\";\n      InsightKeys2[\"DUPLICATE_JAVASCRIPT\"] = \"DuplicatedJavaScript\";\n      InsightKeys2[\"FONT_DISPLAY\"] = \"FontDisplay\";\n      InsightKeys2[\"FORCED_REFLOW\"] = \"ForcedReflow\";\n      InsightKeys2[\"IMAGE_DELIVERY\"] = \"ImageDelivery\";\n      InsightKeys2[\"LCP_DISCOVERY\"] = \"LCPDiscovery\";\n      InsightKeys2[\"LEGACY_JAVASCRIPT\"] = \"LegacyJavaScript\";\n      InsightKeys2[\"NETWORK_DEPENDENCY_TREE\"] = \"NetworkDependencyTree\";\n      InsightKeys2[\"RENDER_BLOCKING\"] = \"RenderBlocking\";\n      InsightKeys2[\"SLOW_CSS_SELECTOR\"] = \"SlowCSSSelector\";\n      InsightKeys2[\"VIEWPORT\"] = \"Viewport\";\n      InsightKeys2[\"MODERN_HTTP\"] = \"ModernHTTP\";\n      InsightKeys2[\"CACHE\"] = \"Cache\";\n    })(InsightKeys || (InsightKeys = {}));\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/insights/Common.js\nvar Common_exports = {};\n__export(Common_exports, {\n  calculateDocFirstByteTs: () => calculateDocFirstByteTs,\n  calculateMetricWeightsForSorting: () => calculateMetricWeightsForSorting,\n  estimateCompressedContentSize: () => estimateCompressedContentSize,\n  estimateCompressionRatioForScript: () => estimateCompressionRatioForScript,\n  evaluateCLSMetricScore: () => evaluateCLSMetricScore,\n  evaluateINPMetricScore: () => evaluateINPMetricScore,\n  evaluateLCPMetricScore: () => evaluateLCPMetricScore,\n  getCLS: () => getCLS,\n  getFieldMetricsForInsightSet: () => getFieldMetricsForInsightSet,\n  getINP: () => getINP,\n  getInsight: () => getInsight,\n  getLCP: () => getLCP,\n  insightBounds: () => insightBounds,\n  isRequestCompressed: () => isRequestCompressed,\n  isRequestServedFromBrowserCache: () => isRequestServedFromBrowserCache,\n  metricSavingsForWastedBytes: () => metricSavingsForWastedBytes\n});\nfunction getInsight(insightName, insightSet) {\n  const insight = insightSet.model[insightName];\n  if (insight instanceof Error) {\n    return null;\n  }\n  return insight;\n}\nfunction getLCP(insightSet) {\n  const insight = getInsight(InsightKeys.LCP_BREAKDOWN, insightSet);\n  if (!insight || !insight.lcpMs || !insight.lcpEvent) {\n    return null;\n  }\n  const value = Timing_exports3.milliToMicro(insight.lcpMs);\n  return { value, event: insight.lcpEvent };\n}\nfunction getINP(insightSet) {\n  const insight = getInsight(InsightKeys.INP_BREAKDOWN, insightSet);\n  if (!insight?.longestInteractionEvent?.dur) {\n    return null;\n  }\n  const value = insight.longestInteractionEvent.dur;\n  return { value, event: insight.longestInteractionEvent };\n}\nfunction getCLS(insightSet) {\n  const insight = getInsight(InsightKeys.CLS_CULPRITS, insightSet);\n  if (!insight) {\n    return { value: 0, worstClusterEvent: null };\n  }\n  let maxScore = 0;\n  let worstCluster;\n  for (const cluster of insight.clusters) {\n    if (cluster.clusterCumulativeScore > maxScore) {\n      maxScore = cluster.clusterCumulativeScore;\n      worstCluster = cluster;\n    }\n  }\n  return { value: maxScore, worstClusterEvent: worstCluster ?? null };\n}\nfunction evaluateLCPMetricScore(value) {\n  return getLogNormalScore2({ p10: 2500, median: 4e3 }, value);\n}\nfunction evaluateINPMetricScore(value) {\n  return getLogNormalScore2({ p10: 200, median: 500 }, value);\n}\nfunction evaluateCLSMetricScore(value) {\n  return getLogNormalScore2({ p10: 0.1, median: 0.25 }, value);\n}\nfunction getPageResult(cruxFieldData, url, origin, scope = null) {\n  return cruxFieldData.find((result) => {\n    const key = scope ? result[`${scope.pageScope}-${scope.deviceScope}`]?.record.key : (result[\"url-ALL\"] || result[\"origin-ALL\"])?.record.key;\n    return key?.url && key.url === url || key?.origin && key.origin === origin;\n  });\n}\nfunction getMetricResult(pageResult, name, scope = null) {\n  const scopes = [];\n  if (scope) {\n    scopes.push(scope);\n  } else {\n    scopes.push({ pageScope: \"url\", deviceScope: \"ALL\" });\n    scopes.push({ pageScope: \"origin\", deviceScope: \"ALL\" });\n  }\n  for (const scope2 of scopes) {\n    const key = `${scope2.pageScope}-${scope2.deviceScope}`;\n    let value = pageResult[key]?.record.metrics[name]?.percentiles?.p75;\n    if (typeof value === \"string\") {\n      value = Number(value);\n    }\n    if (typeof value === \"number\" && Number.isFinite(value)) {\n      return { value, pageScope: scope2.pageScope };\n    }\n  }\n  return null;\n}\nfunction getMetricTimingResult(pageResult, name, scope = null) {\n  const result = getMetricResult(pageResult, name, scope);\n  if (result) {\n    const valueMs = result.value;\n    return { value: Timing_exports3.milliToMicro(valueMs), pageScope: result.pageScope };\n  }\n  return null;\n}\nfunction getFieldMetricsForInsightSet(insightSet, metadata, scope = null) {\n  const cruxFieldData = metadata?.cruxFieldData;\n  if (!cruxFieldData) {\n    return null;\n  }\n  const pageResult = getPageResult(cruxFieldData, insightSet.url.href, insightSet.url.origin, scope);\n  if (!pageResult) {\n    return null;\n  }\n  return {\n    fcp: getMetricTimingResult(pageResult, \"first_contentful_paint\", scope),\n    lcp: getMetricTimingResult(pageResult, \"largest_contentful_paint\", scope),\n    inp: getMetricTimingResult(pageResult, \"interaction_to_next_paint\", scope),\n    cls: getMetricResult(pageResult, \"cumulative_layout_shift\", scope),\n    lcpBreakdown: {\n      ttfb: getMetricTimingResult(pageResult, \"largest_contentful_paint_image_time_to_first_byte\", scope),\n      loadDelay: getMetricTimingResult(pageResult, \"largest_contentful_paint_image_resource_load_delay\", scope),\n      loadDuration: getMetricTimingResult(pageResult, \"largest_contentful_paint_image_resource_load_duration\", scope),\n      renderDelay: getMetricTimingResult(pageResult, \"largest_contentful_paint_image_element_render_delay\", scope)\n    }\n  };\n}\nfunction calculateMetricWeightsForSorting(insightSet, metadata) {\n  const weights = {\n    lcp: 1 / 3,\n    inp: 1 / 3,\n    cls: 1 / 3\n  };\n  const cruxFieldData = metadata?.cruxFieldData;\n  if (!cruxFieldData) {\n    return weights;\n  }\n  const fieldMetrics = getFieldMetricsForInsightSet(insightSet, metadata);\n  if (!fieldMetrics) {\n    return weights;\n  }\n  const fieldLcp = fieldMetrics.lcp?.value ?? null;\n  const fieldInp = fieldMetrics.inp?.value ?? null;\n  const fieldCls = fieldMetrics.cls?.value ?? null;\n  const fieldLcpScore = fieldLcp !== null ? evaluateLCPMetricScore(Timing_exports3.microToMilli(fieldLcp)) : 0;\n  const fieldInpScore = fieldInp !== null ? evaluateINPMetricScore(Timing_exports3.microToMilli(fieldInp)) : 0;\n  const fieldClsScore = fieldCls !== null ? evaluateCLSMetricScore(fieldCls) : 0;\n  const fieldLcpScoreInverted = 1 - fieldLcpScore;\n  const fieldInpScoreInverted = 1 - fieldInpScore;\n  const fieldClsScoreInverted = 1 - fieldClsScore;\n  const invertedSum = fieldLcpScoreInverted + fieldInpScoreInverted + fieldClsScoreInverted;\n  if (!invertedSum) {\n    return weights;\n  }\n  weights.lcp = fieldLcpScoreInverted / invertedSum;\n  weights.inp = fieldInpScoreInverted / invertedSum;\n  weights.cls = fieldClsScoreInverted / invertedSum;\n  return weights;\n}\nfunction estimateSavingsWithGraphs(wastedBytesByRequestId, simulator, graph2) {\n  const simulationBeforeChanges = simulator.simulate(graph2);\n  const originalTransferSizes = /* @__PURE__ */ new Map();\n  graph2.traverse((node) => {\n    if (node.type !== \"network\") {\n      return;\n    }\n    const wastedBytes = wastedBytesByRequestId.get(node.request.requestId);\n    if (!wastedBytes) {\n      return;\n    }\n    const original = node.request.transferSize;\n    originalTransferSizes.set(node.request.requestId, original);\n    node.request.transferSize = Math.max(original - wastedBytes, 0);\n  });\n  const simulationAfterChanges = simulator.simulate(graph2);\n  graph2.traverse((node) => {\n    if (node.type !== \"network\") {\n      return;\n    }\n    const originalTransferSize = originalTransferSizes.get(node.request.requestId);\n    if (originalTransferSize === void 0) {\n      return;\n    }\n    node.request.transferSize = originalTransferSize;\n  });\n  let savings = simulationBeforeChanges.timeInMs - simulationAfterChanges.timeInMs;\n  savings = Math.round(savings / GRAPH_SAVINGS_PRECISION) * GRAPH_SAVINGS_PRECISION;\n  return Timing_exports.Milli(savings);\n}\nfunction metricSavingsForWastedBytes(wastedBytesByRequestId, context) {\n  if (!context.navigation || !context.lantern) {\n    return;\n  }\n  if (!wastedBytesByRequestId.size) {\n    return { FCP: Timing_exports.Milli(0), LCP: Timing_exports.Milli(0) };\n  }\n  const simulator = context.lantern.simulator;\n  const fcpGraph = context.lantern.metrics.firstContentfulPaint.optimisticGraph;\n  const lcpGraph = context.lantern.metrics.largestContentfulPaint.optimisticGraph;\n  return {\n    FCP: estimateSavingsWithGraphs(wastedBytesByRequestId, simulator, fcpGraph),\n    LCP: estimateSavingsWithGraphs(wastedBytesByRequestId, simulator, lcpGraph)\n  };\n}\nfunction isRequestCompressed(request) {\n  if (!request.args.data.responseHeaders) {\n    return false;\n  }\n  const patterns = [\n    /^content-encoding$/i,\n    /^x-content-encoding-over-network$/i,\n    /^x-original-content-encoding$/i\n    // Lightrider.\n  ];\n  const compressionTypes = [\"gzip\", \"br\", \"deflate\", \"zstd\"];\n  return request.args.data.responseHeaders.some((header) => patterns.some((p) => header.name.match(p)) && compressionTypes.includes(header.value));\n}\nfunction isRequestServedFromBrowserCache(request) {\n  if (!request.args.data.responseHeaders || request.args.data.failed) {\n    return false;\n  }\n  if (request.args.data.statusCode === 304) {\n    return true;\n  }\n  const { transferSize, resourceSize } = getRequestSizes(request);\n  const ratio = resourceSize ? transferSize / resourceSize : 0;\n  if (ratio < 0.01) {\n    return true;\n  }\n  return false;\n}\nfunction getRequestSizes(request) {\n  const resourceSize = request.args.data.decodedBodyLength;\n  const transferSize = request.args.data.encodedDataLength;\n  return { resourceSize, transferSize };\n}\nfunction estimateCompressedContentSize(request, totalBytes, resourceType) {\n  if (!request || isRequestServedFromBrowserCache(request)) {\n    switch (resourceType) {\n      case \"Stylesheet\":\n        return Math.round(totalBytes * 0.2);\n      case \"Script\":\n      case \"Document\":\n        return Math.round(totalBytes * 0.33);\n      default:\n        return Math.round(totalBytes * 0.5);\n    }\n  }\n  const { transferSize, resourceSize } = getRequestSizes(request);\n  let contentTransferSize = transferSize;\n  if (!isRequestCompressed(request)) {\n    contentTransferSize = resourceSize;\n  }\n  if (request.args.data.resourceType === resourceType) {\n    return contentTransferSize;\n  }\n  const compressionRatio = Number.isFinite(resourceSize) && resourceSize > 0 ? contentTransferSize / resourceSize : 1;\n  return Math.round(totalBytes * compressionRatio);\n}\nfunction estimateCompressionRatioForScript(script) {\n  if (!script.request) {\n    return 1;\n  }\n  const request = script.request;\n  const contentLength = request.args.data.decodedBodyLength ?? script.content?.length ?? 0;\n  const compressedSize = estimateCompressedContentSize(\n    request,\n    contentLength,\n    \"Script\"\n    /* Protocol.Network.ResourceType.Script */\n  );\n  if (contentLength === 0 || compressedSize === 0) {\n    return 1;\n  }\n  const compressionRatio = compressedSize / contentLength;\n  return compressionRatio;\n}\nfunction calculateDocFirstByteTs(docRequest) {\n  if (docRequest.args.data.protocol === \"file\") {\n    return docRequest.ts;\n  }\n  const timing = docRequest.args.data.timing;\n  if (!timing) {\n    return null;\n  }\n  return Timing_exports.Micro(Timing_exports3.secondsToMicro(timing.requestTime) + Timing_exports3.milliToMicro(timing.receiveHeadersStart ?? timing.receiveHeadersEnd));\n}\nfunction insightBounds(insight, insightSetBounds) {\n  const overlays = insight.createOverlays?.() ?? [];\n  const windows = overlays.map(Timing_exports3.traceWindowFromOverlay).filter((bounds) => !!bounds);\n  const overlaysBounds = Timing_exports3.combineTraceWindowsMicro(windows);\n  if (overlaysBounds) {\n    return overlaysBounds;\n  }\n  return insightSetBounds;\n}\nvar GRAPH_SAVINGS_PRECISION;\nvar init_Common = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/insights/Common.js\"() {\n    init_process_global();\n    init_helpers2();\n    init_types2();\n    init_Statistics();\n    init_types4();\n    GRAPH_SAVINGS_PRECISION = 50;\n    __name(getInsight, \"getInsight\");\n    __name(getLCP, \"getLCP\");\n    __name(getINP, \"getINP\");\n    __name(getCLS, \"getCLS\");\n    __name(evaluateLCPMetricScore, \"evaluateLCPMetricScore\");\n    __name(evaluateINPMetricScore, \"evaluateINPMetricScore\");\n    __name(evaluateCLSMetricScore, \"evaluateCLSMetricScore\");\n    __name(getPageResult, \"getPageResult\");\n    __name(getMetricResult, \"getMetricResult\");\n    __name(getMetricTimingResult, \"getMetricTimingResult\");\n    __name(getFieldMetricsForInsightSet, \"getFieldMetricsForInsightSet\");\n    __name(calculateMetricWeightsForSorting, \"calculateMetricWeightsForSorting\");\n    __name(estimateSavingsWithGraphs, \"estimateSavingsWithGraphs\");\n    __name(metricSavingsForWastedBytes, \"metricSavingsForWastedBytes\");\n    __name(isRequestCompressed, \"isRequestCompressed\");\n    __name(isRequestServedFromBrowserCache, \"isRequestServedFromBrowserCache\");\n    __name(getRequestSizes, \"getRequestSizes\");\n    __name(estimateCompressedContentSize, \"estimateCompressedContentSize\");\n    __name(estimateCompressionRatioForScript, \"estimateCompressionRatioForScript\");\n    __name(calculateDocFirstByteTs, \"calculateDocFirstByteTs\");\n    __name(insightBounds, \"insightBounds\");\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/insights/Cache.js\nvar Cache_exports = {};\n__export(Cache_exports, {\n  UIStrings: () => UIStrings2,\n  cachingDisabled: () => cachingDisabled,\n  computeCacheLifetimeInSeconds: () => computeCacheLifetimeInSeconds,\n  createOverlayForRequest: () => createOverlayForRequest,\n  createOverlays: () => createOverlays,\n  generateInsight: () => generateInsight,\n  getCombinedHeaders: () => getCombinedHeaders,\n  i18nString: () => i18nString,\n  isCacheInsight: () => isCacheInsight,\n  isCacheable: () => isCacheable\n});\nfunction finalize31(partialModel) {\n  return {\n    insightKey: InsightKeys.CACHE,\n    strings: UIStrings2,\n    title: i18nString(UIStrings2.title),\n    description: i18nString(UIStrings2.description),\n    docs: \"https://developer.chrome.com/docs/performance/insights/cache\",\n    category: InsightCategory.ALL,\n    state: partialModel.requests.length > 0 ? \"fail\" : \"pass\",\n    ...partialModel\n  };\n}\nfunction isCacheable(request) {\n  if (Network_exports.NON_NETWORK_SCHEMES.includes(request.args.data.protocol)) {\n    return false;\n  }\n  return Boolean(Network_exports.CACHEABLE_STATUS_CODES.has(request.args.data.statusCode) && Network_exports.STATIC_RESOURCE_TYPES.has(\n    request.args.data.resourceType || \"Other\"\n    /* Protocol.Network.ResourceType.Other */\n  ));\n}\nfunction computeCacheLifetimeInSeconds(headers, cacheControl) {\n  if (cacheControl?.[\"max-age\"] !== void 0) {\n    return cacheControl[\"max-age\"];\n  }\n  const expiresHeaders = headers.find((h) => h.name === \"expires\")?.value ?? null;\n  if (expiresHeaders) {\n    const expires = new Date(expiresHeaders).getTime();\n    if (!expires) {\n      return 0;\n    }\n    return Math.ceil((expires - Date.now()) / 1e3);\n  }\n  return null;\n}\nfunction getCacheHitProbability(maxAgeInSeconds) {\n  const RESOURCE_AGE_IN_HOURS_DECILES = [0, 0.2, 1, 3, 8, 12, 24, 48, 72, 168, 8760, Infinity];\n  const maxAgeInHours = maxAgeInSeconds / 3600;\n  const upperDecileIndex = RESOURCE_AGE_IN_HOURS_DECILES.findIndex((decile) => decile >= maxAgeInHours);\n  if (upperDecileIndex === RESOURCE_AGE_IN_HOURS_DECILES.length - 1) {\n    return 1;\n  }\n  if (upperDecileIndex === 0) {\n    return 0;\n  }\n  const upperDecileValue = RESOURCE_AGE_IN_HOURS_DECILES[upperDecileIndex];\n  const lowerDecileValue = RESOURCE_AGE_IN_HOURS_DECILES[upperDecileIndex - 1];\n  const upperDecile = upperDecileIndex / 10;\n  const lowerDecile = (upperDecileIndex - 1) / 10;\n  return linearInterpolation(lowerDecileValue, lowerDecile, upperDecileValue, upperDecile, maxAgeInHours);\n}\nfunction getCombinedHeaders(responseHeaders) {\n  const headers = /* @__PURE__ */ new Map();\n  for (const header of responseHeaders) {\n    const name = header.name.toLowerCase();\n    if (headers.get(name)) {\n      headers.set(name, `${headers.get(name)}, ${header.value}`);\n    } else {\n      headers.set(name, header.value);\n    }\n  }\n  return headers;\n}\nfunction cachingDisabled(headers, parsedCacheControl) {\n  const cacheControl = headers?.get(\"cache-control\") ?? null;\n  const pragma = headers?.get(\"pragma\") ?? null;\n  if (!cacheControl && pragma?.includes(\"no-cache\")) {\n    return true;\n  }\n  if (parsedCacheControl && (parsedCacheControl[\"must-revalidate\"] || parsedCacheControl[\"no-cache\"] || parsedCacheControl[\"no-store\"] || parsedCacheControl[\"private\"])) {\n    return true;\n  }\n  return false;\n}\nfunction isCacheInsight(model2) {\n  return model2.insightKey === InsightKeys.CACHE;\n}\nfunction generateInsight(data31, context) {\n  const isWithinContext = /* @__PURE__ */ __name((event) => Timing_exports3.eventIsInBounds(event, context.bounds), \"isWithinContext\");\n  const contextRequests = data31.NetworkRequests.byTime.filter(isWithinContext);\n  const results = [];\n  let totalWastedBytes = 0;\n  const wastedBytesByRequestId = /* @__PURE__ */ new Map();\n  for (const req of contextRequests) {\n    if (!req.args.data.responseHeaders || !isCacheable(req)) {\n      continue;\n    }\n    const headers = getCombinedHeaders(req.args.data.responseHeaders);\n    const cacheControl = headers.get(\"cache-control\") ?? null;\n    const parsedDirectives = Network_exports.parseCacheControl(cacheControl);\n    if (cachingDisabled(headers, parsedDirectives)) {\n      continue;\n    }\n    let ttl = computeCacheLifetimeInSeconds(req.args.data.responseHeaders, parsedDirectives);\n    if (ttl !== null && (!Number.isFinite(ttl) || ttl <= 0)) {\n      continue;\n    }\n    ttl = ttl || 0;\n    const ttlDays = ttl / 86400;\n    if (ttlDays >= 30) {\n      continue;\n    }\n    const cacheHitProbability = getCacheHitProbability(ttl);\n    if (cacheHitProbability > IGNORE_THRESHOLD_IN_PERCENT) {\n      continue;\n    }\n    const transferSize = req.args.data.encodedDataLength || 0;\n    const wastedBytes = (1 - cacheHitProbability) * transferSize;\n    wastedBytesByRequestId.set(req.args.data.requestId, wastedBytes);\n    totalWastedBytes += wastedBytes;\n    results.push({ request: req, ttl, wastedBytes });\n  }\n  results.sort((a, b) => {\n    return b.request.args.data.decodedBodyLength - a.request.args.data.decodedBodyLength || a.ttl - b.ttl;\n  });\n  return finalize31({\n    relatedEvents: results.map((r) => r.request),\n    requests: results,\n    metricSavings: metricSavingsForWastedBytes(wastedBytesByRequestId, context),\n    wastedBytes: totalWastedBytes\n  });\n}\nfunction createOverlayForRequest(request) {\n  return {\n    type: \"ENTRY_OUTLINE\",\n    entry: request,\n    outlineReason: \"ERROR\"\n  };\n}\nfunction createOverlays(model2) {\n  return model2.requests.map((req) => createOverlayForRequest(req.request));\n}\nvar UIStrings2, i18nString, IGNORE_THRESHOLD_IN_PERCENT;\nvar init_Cache = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/insights/Cache.js\"() {\n    init_process_global();\n    init_helpers2();\n    init_Common();\n    init_Statistics();\n    init_types4();\n    UIStrings2 = {\n      /**\n       * @description Title of an insight that provides information and suggestions of resources that could improve their caching.\n       */\n      title: \"Use efficient cache lifetimes\",\n      /**\n       * @description Text to tell the user about how caching can help improve performance.\n       */\n      description: \"A long cache lifetime can speed up repeat visits to your page. [Learn more about caching](https://developer.chrome.com/docs/performance/insights/cache).\",\n      /**\n       * @description Column for a font loaded by the page to render text.\n       */\n      requestColumn: \"Request\",\n      /**\n       * @description Column for a resource cache's Time To Live.\n       */\n      cacheTTL: \"Cache TTL\",\n      /**\n       * @description Text describing that there were no requests found that need caching.\n       */\n      noRequestsToCache: \"No requests with inefficient cache policies\",\n      /**\n       * @description Table row value representing the remaining items not shown in the table due to size constraints. This row will always represent at least 2 items.\n       * @example {5} PH1\n       */\n      others: \"{PH1} others\"\n    };\n    i18nString = /* @__PURE__ */ __name((i18nId, values) => ({ i18nId, values }), \"i18nString\");\n    IGNORE_THRESHOLD_IN_PERCENT = 0.925;\n    __name(finalize31, \"finalize\");\n    __name(isCacheable, \"isCacheable\");\n    __name(computeCacheLifetimeInSeconds, \"computeCacheLifetimeInSeconds\");\n    __name(getCacheHitProbability, \"getCacheHitProbability\");\n    __name(getCombinedHeaders, \"getCombinedHeaders\");\n    __name(cachingDisabled, \"cachingDisabled\");\n    __name(isCacheInsight, \"isCacheInsight\");\n    __name(generateInsight, \"generateInsight\");\n    __name(createOverlayForRequest, \"createOverlayForRequest\");\n    __name(createOverlays, \"createOverlays\");\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/insights/CLSCulprits.js\nvar CLSCulprits_exports = {};\n__export(CLSCulprits_exports, {\n  AnimationFailureReasons: () => AnimationFailureReasons,\n  LayoutShiftType: () => LayoutShiftType,\n  UIStrings: () => UIStrings3,\n  createOverlays: () => createOverlays2,\n  generateInsight: () => generateInsight2,\n  getNonCompositedFailure: () => getNonCompositedFailure,\n  i18nString: () => i18nString2,\n  isCLSCulpritsInsight: () => isCLSCulpritsInsight\n});\nfunction isInRootCauseWindow(event, targetEvent) {\n  const eventEnd = event.dur ? event.ts + event.dur : event.ts;\n  return eventEnd < targetEvent.ts && eventEnd >= targetEvent.ts - ROOT_CAUSE_WINDOW;\n}\nfunction getNonCompositedFailure(animationEvent) {\n  const failures = [];\n  const beginEvent = animationEvent.args.data.beginEvent;\n  const instantEvents = animationEvent.args.data.instantEvents || [];\n  for (const event of instantEvents) {\n    const failureMask = event.args.data.compositeFailed;\n    const unsupportedProperties = event.args.data.unsupportedProperties;\n    if (!failureMask) {\n      continue;\n    }\n    const failureReasons = ACTIONABLE_FAILURE_REASONS.filter((reason) => failureMask & reason.flag).map((reason) => reason.failure);\n    const failure = {\n      name: beginEvent.args.data.displayName,\n      failureReasons,\n      unsupportedProperties,\n      animation: animationEvent\n    };\n    failures.push(failure);\n  }\n  return failures;\n}\nfunction getNonCompositedFailureRootCauses(animationEvents, prePaintEvents2, shiftsByPrePaint, rootCausesByShift) {\n  const allAnimationFailures = [];\n  for (const animation of animationEvents) {\n    const failures = getNonCompositedFailure(animation);\n    if (!failures) {\n      continue;\n    }\n    allAnimationFailures.push(...failures);\n    const nextPrePaint = getNextEvent(prePaintEvents2, animation);\n    if (!nextPrePaint) {\n      continue;\n    }\n    if (!isInRootCauseWindow(animation, nextPrePaint)) {\n      continue;\n    }\n    const shifts = shiftsByPrePaint.get(nextPrePaint);\n    if (!shifts) {\n      continue;\n    }\n    for (const shift of shifts) {\n      const rootCausesForShift = rootCausesByShift.get(shift);\n      if (!rootCausesForShift) {\n        throw new Error(\"Unaccounted shift\");\n      }\n      rootCausesForShift.nonCompositedAnimations.push(...failures);\n    }\n  }\n  return allAnimationFailures;\n}\nfunction getShiftsByPrePaintEvents(layoutShifts, prePaintEvents2) {\n  const shiftsByPrePaint = /* @__PURE__ */ new Map();\n  for (const prePaintEvent of prePaintEvents2) {\n    const firstShiftIndex = ArrayUtilities_exports.nearestIndexFromBeginning(layoutShifts, (shift) => shift.ts >= prePaintEvent.ts);\n    if (firstShiftIndex === null) {\n      continue;\n    }\n    for (let i = firstShiftIndex; i < layoutShifts.length; i++) {\n      const shift = layoutShifts[i];\n      if (shift.ts >= prePaintEvent.ts && shift.ts <= prePaintEvent.ts + prePaintEvent.dur) {\n        const shiftsInPrePaint = MapUtilities_exports.getWithDefault(shiftsByPrePaint, prePaintEvent, () => []);\n        shiftsInPrePaint.push(shift);\n      }\n      if (shift.ts > prePaintEvent.ts + prePaintEvent.dur) {\n        break;\n      }\n    }\n  }\n  return shiftsByPrePaint;\n}\nfunction getNextEvent(sourceEvents, targetEvent) {\n  const index = ArrayUtilities_exports.nearestIndexFromBeginning(sourceEvents, (source) => source.ts > targetEvent.ts + (targetEvent.dur || 0));\n  if (index === null) {\n    return void 0;\n  }\n  return sourceEvents[index];\n}\nfunction getIframeRootCauses(data31, iframeCreatedEvents, prePaintEvents2, shiftsByPrePaint, rootCausesByShift, domLoadingEvents2) {\n  for (const iframeEvent of iframeCreatedEvents) {\n    const nextPrePaint = getNextEvent(prePaintEvents2, iframeEvent);\n    if (!nextPrePaint) {\n      continue;\n    }\n    const shifts = shiftsByPrePaint.get(nextPrePaint);\n    if (!shifts) {\n      continue;\n    }\n    for (const shift of shifts) {\n      const rootCausesForShift = rootCausesByShift.get(shift);\n      if (!rootCausesForShift) {\n        throw new Error(\"Unaccounted shift\");\n      }\n      const domEvent = domLoadingEvents2.find((e) => {\n        const maxIframe = Timing_exports.Micro(iframeEvent.ts + (iframeEvent.dur ?? 0));\n        return e.ts >= iframeEvent.ts && e.ts <= maxIframe;\n      });\n      if (domEvent?.args.frame) {\n        const frame = domEvent.args.frame;\n        let url;\n        const processes2 = data31.Meta.rendererProcessesByFrame.get(frame);\n        if (processes2 && processes2.size > 0) {\n          url = [...processes2.values()][0]?.[0].frame.url;\n        }\n        rootCausesForShift.iframes.push({ frame, url });\n      }\n    }\n  }\n  return rootCausesByShift;\n}\nfunction getUnsizedImageRootCauses(unsizedImageEvents, paintImageEvents3, shiftsByPrePaint, rootCausesByShift) {\n  shiftsByPrePaint.forEach((shifts, prePaint) => {\n    const paintImage = getNextEvent(paintImageEvents3, prePaint);\n    if (!paintImage) {\n      return;\n    }\n    const matchingNode = unsizedImageEvents.find((unsizedImage) => unsizedImage.args.data.nodeId === paintImage.args.data.nodeId);\n    if (!matchingNode) {\n      return;\n    }\n    for (const shift of shifts) {\n      const rootCausesForShift = rootCausesByShift.get(shift);\n      if (!rootCausesForShift) {\n        throw new Error(\"Unaccounted shift\");\n      }\n      rootCausesForShift.unsizedImages.push({\n        backendNodeId: matchingNode.args.data.nodeId,\n        paintImageEvent: paintImage\n      });\n    }\n  });\n  return rootCausesByShift;\n}\nfunction isCLSCulpritsInsight(insight) {\n  return insight.insightKey === InsightKeys.CLS_CULPRITS;\n}\nfunction getFontRootCauses(networkRequests, prePaintEvents2, shiftsByPrePaint, rootCausesByShift) {\n  const fontRequests = networkRequests.filter((req) => req.args.data.resourceType === \"Font\" && req.args.data.mimeType.startsWith(\"font\"));\n  for (const req of fontRequests) {\n    const nextPrePaint = getNextEvent(prePaintEvents2, req);\n    if (!nextPrePaint) {\n      continue;\n    }\n    if (!isInRootCauseWindow(req, nextPrePaint)) {\n      continue;\n    }\n    const shifts = shiftsByPrePaint.get(nextPrePaint);\n    if (!shifts) {\n      continue;\n    }\n    for (const shift of shifts) {\n      const rootCausesForShift = rootCausesByShift.get(shift);\n      if (!rootCausesForShift) {\n        throw new Error(\"Unaccounted shift\");\n      }\n      rootCausesForShift.webFonts.push(req);\n    }\n  }\n  return rootCausesByShift;\n}\nfunction getTopCulprits(cluster, culpritsByShift) {\n  const MAX_TOP_CULPRITS = 3;\n  const causes = [];\n  const shifts = cluster.events;\n  for (const shift of shifts) {\n    const culprits = culpritsByShift.get(shift);\n    if (!culprits) {\n      continue;\n    }\n    const fontReq = culprits.webFonts;\n    const iframes = culprits.iframes;\n    const animations2 = culprits.nonCompositedAnimations;\n    const unsizedImages = culprits.unsizedImages;\n    for (let i = 0; i < fontReq.length && causes.length < MAX_TOP_CULPRITS; i++) {\n      causes.push({ type: LayoutShiftType.WEB_FONT, description: i18nString2(UIStrings3.webFont) });\n    }\n    for (let i = 0; i < iframes.length && causes.length < MAX_TOP_CULPRITS; i++) {\n      causes.push({ type: LayoutShiftType.IFRAMES, description: i18nString2(UIStrings3.injectedIframe) });\n    }\n    for (let i = 0; i < animations2.length && causes.length < MAX_TOP_CULPRITS; i++) {\n      causes.push({ type: LayoutShiftType.ANIMATIONS, description: i18nString2(UIStrings3.animation) });\n    }\n    for (let i = 0; i < unsizedImages.length && causes.length < MAX_TOP_CULPRITS; i++) {\n      causes.push({\n        type: LayoutShiftType.UNSIZED_IMAGE,\n        description: i18nString2(UIStrings3.unsizedImage),\n        url: unsizedImages[i].paintImageEvent.args.data.url || \"\",\n        backendNodeId: unsizedImages[i].backendNodeId,\n        frame: unsizedImages[i].paintImageEvent.args.data.frame || \"\"\n      });\n    }\n    if (causes.length >= MAX_TOP_CULPRITS) {\n      break;\n    }\n  }\n  return causes.slice(0, MAX_TOP_CULPRITS);\n}\nfunction finalize32(partialModel) {\n  let state = \"pass\";\n  if (partialModel.worstCluster) {\n    const classification = ModelHandlers_exports.LayoutShifts.scoreClassificationForLayoutShift(partialModel.worstCluster.clusterCumulativeScore);\n    if (classification === ModelHandlers_exports.PageLoadMetrics.ScoreClassification.GOOD) {\n      state = \"informative\";\n    } else {\n      state = \"fail\";\n    }\n  }\n  return {\n    insightKey: InsightKeys.CLS_CULPRITS,\n    strings: UIStrings3,\n    title: i18nString2(UIStrings3.title),\n    description: i18nString2(UIStrings3.description),\n    docs: \"https://developer.chrome.com/docs/performance/insights/cls-culprit\",\n    category: InsightCategory.CLS,\n    state,\n    ...partialModel\n  };\n}\nfunction generateInsight2(data31, context) {\n  const isWithinContext = /* @__PURE__ */ __name((event) => Timing_exports3.eventIsInBounds(event, context.bounds), \"isWithinContext\");\n  const compositeAnimationEvents = data31.Animations.animations.filter(isWithinContext);\n  const iframeEvents = data31.LayoutShifts.renderFrameImplCreateChildFrameEvents.filter(isWithinContext);\n  const networkRequests = data31.NetworkRequests.byTime.filter(isWithinContext);\n  const domLoadingEvents2 = data31.LayoutShifts.domLoadingEvents.filter(isWithinContext);\n  const unsizedImageEvents = data31.LayoutShifts.layoutImageUnsizedEvents.filter(isWithinContext);\n  const clusterKey = context.navigation ? context.navigationId : TraceEvents_exports.NO_NAVIGATION;\n  const clusters2 = data31.LayoutShifts.clustersByNavigationId.get(clusterKey) ?? [];\n  const clustersByScore = [...clusters2].sort((a, b) => b.clusterCumulativeScore - a.clusterCumulativeScore);\n  const worstCluster = clustersByScore.at(0);\n  const layoutShifts = clusters2.flatMap((cluster) => cluster.events);\n  const prePaintEvents2 = data31.LayoutShifts.prePaintEvents.filter(isWithinContext);\n  const paintImageEvents3 = data31.LayoutShifts.paintImageEvents.filter(isWithinContext);\n  const rootCausesByShift = /* @__PURE__ */ new Map();\n  const shiftsByPrePaint = getShiftsByPrePaintEvents(layoutShifts, prePaintEvents2);\n  for (const shift of layoutShifts) {\n    rootCausesByShift.set(shift, { iframes: [], webFonts: [], nonCompositedAnimations: [], unsizedImages: [] });\n  }\n  getIframeRootCauses(data31, iframeEvents, prePaintEvents2, shiftsByPrePaint, rootCausesByShift, domLoadingEvents2);\n  getFontRootCauses(networkRequests, prePaintEvents2, shiftsByPrePaint, rootCausesByShift);\n  getUnsizedImageRootCauses(unsizedImageEvents, paintImageEvents3, shiftsByPrePaint, rootCausesByShift);\n  const animationFailures = getNonCompositedFailureRootCauses(compositeAnimationEvents, prePaintEvents2, shiftsByPrePaint, rootCausesByShift);\n  const relatedEvents = [...layoutShifts];\n  if (worstCluster) {\n    relatedEvents.push(worstCluster);\n  }\n  const topCulpritsByCluster = /* @__PURE__ */ new Map();\n  for (const cluster of clusters2) {\n    topCulpritsByCluster.set(cluster, getTopCulprits(cluster, rootCausesByShift));\n  }\n  return finalize32({\n    relatedEvents,\n    animationFailures,\n    shifts: rootCausesByShift,\n    clusters: clusters2,\n    worstCluster,\n    topCulpritsByCluster\n  });\n}\nfunction createOverlays2(model2) {\n  const clustersByScore = model2.clusters.toSorted((a, b) => b.clusterCumulativeScore - a.clusterCumulativeScore) ?? [];\n  const worstCluster = clustersByScore[0];\n  if (!worstCluster) {\n    return [];\n  }\n  const range = Timing_exports.Micro(worstCluster.dur ?? 0);\n  const max = Timing_exports.Micro(worstCluster.ts + range);\n  return [{\n    type: \"TIMESPAN_BREAKDOWN\",\n    sections: [\n      {\n        bounds: { min: worstCluster.ts, range, max },\n        label: i18nString2(UIStrings3.worstLayoutShiftCluster),\n        showDuration: false\n      }\n    ],\n    // This allows for the overlay to sit over the layout shift.\n    entry: worstCluster.events[0],\n    renderLocation: \"ABOVE_EVENT\"\n  }];\n}\nvar UIStrings3, i18nString2, AnimationFailureReasons, LayoutShiftType, ACTIONABLE_FAILURE_REASONS, ROOT_CAUSE_WINDOW;\nvar init_CLSCulprits = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/insights/CLSCulprits.js\"() {\n    init_process_global();\n    init_platform();\n    init_handlers();\n    init_helpers2();\n    init_types2();\n    init_types4();\n    UIStrings3 = {\n      /** Title of an insight that provides details about why elements shift/move on the page. The causes for these shifts are referred to as culprits (\"reasons\"). */\n      title: \"Layout shift culprits\",\n      /**\n       * @description Description of a DevTools insight that identifies the reasons that elements shift on the page.\n       * This is displayed after a user expands the section to see more. No character length limits.\n       */\n      description: \"Layout shifts occur when elements move absent any user interaction. [Investigate the causes of layout shifts](https://developer.chrome.com/docs/performance/insights/cls-culprit), such as elements being added, removed, or their fonts changing as the page loads.\",\n      /**\n       * @description Text indicating the worst layout shift cluster.\n       */\n      worstLayoutShiftCluster: \"Worst layout shift cluster\",\n      /**\n       * @description Text indicating the worst layout shift cluster.\n       */\n      worstCluster: \"Worst cluster\",\n      /**\n       * @description Text indicating a layout shift cluster and its start time.\n       * @example {32 ms} PH1\n       */\n      layoutShiftCluster: \"Layout shift cluster @ {PH1}\",\n      /**\n       * @description Text indicating the biggest reasons for the layout shifts.\n       */\n      topCulprits: \"Top layout shift culprits\",\n      /**\n       * @description Text for a culprit type of Injected iframe.\n       */\n      injectedIframe: \"Injected iframe\",\n      /**\n       * @description Text for a culprit type of web font request.\n       */\n      webFont: \"Web font\",\n      /**\n       * @description Text for a culprit type of Animation.\n       */\n      animation: \"Animation\",\n      /**\n       * @description Text for a culprit type of Unsized image.\n       */\n      unsizedImage: \"Unsized image element\",\n      /**\n       * @description Text status when there were no layout shifts detected.\n       */\n      noLayoutShifts: \"No layout shifts\",\n      /**\n       * @description Text status when there no layout shifts culprits/root causes were found.\n       */\n      noCulprits: \"Could not detect any layout shift culprits\"\n    };\n    i18nString2 = /* @__PURE__ */ __name((i18nId, values) => ({ i18nId, values }), \"i18nString\");\n    (function(AnimationFailureReasons2) {\n      AnimationFailureReasons2[\"ACCELERATED_ANIMATIONS_DISABLED\"] = \"ACCELERATED_ANIMATIONS_DISABLED\";\n      AnimationFailureReasons2[\"EFFECT_SUPPRESSED_BY_DEVTOOLS\"] = \"EFFECT_SUPPRESSED_BY_DEVTOOLS\";\n      AnimationFailureReasons2[\"INVALID_ANIMATION_OR_EFFECT\"] = \"INVALID_ANIMATION_OR_EFFECT\";\n      AnimationFailureReasons2[\"EFFECT_HAS_UNSUPPORTED_TIMING_PARAMS\"] = \"EFFECT_HAS_UNSUPPORTED_TIMING_PARAMS\";\n      AnimationFailureReasons2[\"EFFECT_HAS_NON_REPLACE_COMPOSITE_MODE\"] = \"EFFECT_HAS_NON_REPLACE_COMPOSITE_MODE\";\n      AnimationFailureReasons2[\"TARGET_HAS_INVALID_COMPOSITING_STATE\"] = \"TARGET_HAS_INVALID_COMPOSITING_STATE\";\n      AnimationFailureReasons2[\"TARGET_HAS_INCOMPATIBLE_ANIMATIONS\"] = \"TARGET_HAS_INCOMPATIBLE_ANIMATIONS\";\n      AnimationFailureReasons2[\"TARGET_HAS_CSS_OFFSET\"] = \"TARGET_HAS_CSS_OFFSET\";\n      AnimationFailureReasons2[\"ANIMATION_AFFECTS_NON_CSS_PROPERTIES\"] = \"ANIMATION_AFFECTS_NON_CSS_PROPERTIES\";\n      AnimationFailureReasons2[\"TRANSFORM_RELATED_PROPERTY_CANNOT_BE_ACCELERATED_ON_TARGET\"] = \"TRANSFORM_RELATED_PROPERTY_CANNOT_BE_ACCELERATED_ON_TARGET\";\n      AnimationFailureReasons2[\"TRANSFROM_BOX_SIZE_DEPENDENT\"] = \"TRANSFROM_BOX_SIZE_DEPENDENT\";\n      AnimationFailureReasons2[\"FILTER_RELATED_PROPERTY_MAY_MOVE_PIXELS\"] = \"FILTER_RELATED_PROPERTY_MAY_MOVE_PIXELS\";\n      AnimationFailureReasons2[\"UNSUPPORTED_CSS_PROPERTY\"] = \"UNSUPPORTED_CSS_PROPERTY\";\n      AnimationFailureReasons2[\"MIXED_KEYFRAME_VALUE_TYPES\"] = \"MIXED_KEYFRAME_VALUE_TYPES\";\n      AnimationFailureReasons2[\"TIMELINE_SOURCE_HAS_INVALID_COMPOSITING_STATE\"] = \"TIMELINE_SOURCE_HAS_INVALID_COMPOSITING_STATE\";\n      AnimationFailureReasons2[\"ANIMATION_HAS_NO_VISIBLE_CHANGE\"] = \"ANIMATION_HAS_NO_VISIBLE_CHANGE\";\n      AnimationFailureReasons2[\"AFFECTS_IMPORTANT_PROPERTY\"] = \"AFFECTS_IMPORTANT_PROPERTY\";\n      AnimationFailureReasons2[\"SVG_TARGET_HAS_INDEPENDENT_TRANSFORM_PROPERTY\"] = \"SVG_TARGET_HAS_INDEPENDENT_TRANSFORM_PROPERTY\";\n    })(AnimationFailureReasons || (AnimationFailureReasons = {}));\n    (function(LayoutShiftType2) {\n      LayoutShiftType2[LayoutShiftType2[\"WEB_FONT\"] = 0] = \"WEB_FONT\";\n      LayoutShiftType2[LayoutShiftType2[\"IFRAMES\"] = 1] = \"IFRAMES\";\n      LayoutShiftType2[LayoutShiftType2[\"ANIMATIONS\"] = 2] = \"ANIMATIONS\";\n      LayoutShiftType2[LayoutShiftType2[\"UNSIZED_IMAGE\"] = 3] = \"UNSIZED_IMAGE\";\n    })(LayoutShiftType || (LayoutShiftType = {}));\n    ACTIONABLE_FAILURE_REASONS = [\n      {\n        flag: 1 << 0,\n        failure: AnimationFailureReasons.ACCELERATED_ANIMATIONS_DISABLED\n      },\n      {\n        flag: 1 << 1,\n        failure: AnimationFailureReasons.EFFECT_SUPPRESSED_BY_DEVTOOLS\n      },\n      {\n        flag: 1 << 2,\n        failure: AnimationFailureReasons.INVALID_ANIMATION_OR_EFFECT\n      },\n      {\n        flag: 1 << 3,\n        failure: AnimationFailureReasons.EFFECT_HAS_UNSUPPORTED_TIMING_PARAMS\n      },\n      {\n        flag: 1 << 4,\n        failure: AnimationFailureReasons.EFFECT_HAS_NON_REPLACE_COMPOSITE_MODE\n      },\n      {\n        flag: 1 << 5,\n        failure: AnimationFailureReasons.TARGET_HAS_INVALID_COMPOSITING_STATE\n      },\n      {\n        flag: 1 << 6,\n        failure: AnimationFailureReasons.TARGET_HAS_INCOMPATIBLE_ANIMATIONS\n      },\n      {\n        flag: 1 << 7,\n        failure: AnimationFailureReasons.TARGET_HAS_CSS_OFFSET\n      },\n      // The failure 1 << 8 is marked as obsolete in Blink\n      {\n        flag: 1 << 9,\n        failure: AnimationFailureReasons.ANIMATION_AFFECTS_NON_CSS_PROPERTIES\n      },\n      {\n        flag: 1 << 10,\n        failure: AnimationFailureReasons.TRANSFORM_RELATED_PROPERTY_CANNOT_BE_ACCELERATED_ON_TARGET\n      },\n      {\n        flag: 1 << 11,\n        failure: AnimationFailureReasons.TRANSFROM_BOX_SIZE_DEPENDENT\n      },\n      {\n        flag: 1 << 12,\n        failure: AnimationFailureReasons.FILTER_RELATED_PROPERTY_MAY_MOVE_PIXELS\n      },\n      {\n        flag: 1 << 13,\n        failure: AnimationFailureReasons.UNSUPPORTED_CSS_PROPERTY\n      },\n      // The failure 1 << 14 is marked as obsolete in Blink\n      {\n        flag: 1 << 15,\n        failure: AnimationFailureReasons.MIXED_KEYFRAME_VALUE_TYPES\n      },\n      {\n        flag: 1 << 16,\n        failure: AnimationFailureReasons.TIMELINE_SOURCE_HAS_INVALID_COMPOSITING_STATE\n      },\n      {\n        flag: 1 << 17,\n        failure: AnimationFailureReasons.ANIMATION_HAS_NO_VISIBLE_CHANGE\n      },\n      {\n        flag: 1 << 18,\n        failure: AnimationFailureReasons.AFFECTS_IMPORTANT_PROPERTY\n      },\n      {\n        flag: 1 << 19,\n        failure: AnimationFailureReasons.SVG_TARGET_HAS_INDEPENDENT_TRANSFORM_PROPERTY\n      }\n    ];\n    ROOT_CAUSE_WINDOW = Timing_exports3.secondsToMicro(Timing_exports.Seconds(0.5));\n    __name(isInRootCauseWindow, \"isInRootCauseWindow\");\n    __name(getNonCompositedFailure, \"getNonCompositedFailure\");\n    __name(getNonCompositedFailureRootCauses, \"getNonCompositedFailureRootCauses\");\n    __name(getShiftsByPrePaintEvents, \"getShiftsByPrePaintEvents\");\n    __name(getNextEvent, \"getNextEvent\");\n    __name(getIframeRootCauses, \"getIframeRootCauses\");\n    __name(getUnsizedImageRootCauses, \"getUnsizedImageRootCauses\");\n    __name(isCLSCulpritsInsight, \"isCLSCulpritsInsight\");\n    __name(getFontRootCauses, \"getFontRootCauses\");\n    __name(getTopCulprits, \"getTopCulprits\");\n    __name(finalize32, \"finalize\");\n    __name(generateInsight2, \"generateInsight\");\n    __name(createOverlays2, \"createOverlays\");\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/insights/DocumentLatency.js\nvar DocumentLatency_exports = {};\n__export(DocumentLatency_exports, {\n  UIStrings: () => UIStrings4,\n  createOverlays: () => createOverlays3,\n  generateInsight: () => generateInsight3,\n  i18nString: () => i18nString3,\n  isDocumentLatencyInsight: () => isDocumentLatencyInsight\n});\nfunction isDocumentLatencyInsight(x) {\n  return x.insightKey === \"DocumentLatency\";\n}\nfunction getServerResponseTime(request) {\n  const isLightrider = globalThis.isLightrider;\n  if (isLightrider) {\n    return request.args.data.lrServerResponseTime ?? null;\n  }\n  const timing = request.args.data.timing;\n  if (!timing) {\n    return null;\n  }\n  const ms = Timing_exports3.microToMilli(request.args.data.syntheticData.serverResponseTime);\n  return Math.round(ms);\n}\nfunction getCompressionSavings(request) {\n  const isCompressed = isRequestCompressed(request);\n  if (isCompressed) {\n    return 0;\n  }\n  const originalSize = request.args.data.decodedBodyLength;\n  let estimatedSavings = 0;\n  switch (request.args.data.mimeType) {\n    case \"text/css\":\n      estimatedSavings = Math.round(originalSize * 0.8);\n      break;\n    case \"text/html\":\n    case \"text/javascript\":\n      estimatedSavings = Math.round(originalSize * 0.67);\n      break;\n    case \"text/plain\":\n    case \"text/xml\":\n    case \"text/x-component\":\n    case \"application/javascript\":\n    case \"application/json\":\n    case \"application/manifest+json\":\n    case \"application/vnd.api+json\":\n    case \"application/xml\":\n    case \"application/xhtml+xml\":\n    case \"application/rss+xml\":\n    case \"application/atom+xml\":\n    case \"application/vnd.ms-fontobject\":\n    case \"application/x-font-ttf\":\n    case \"application/x-font-opentype\":\n    case \"application/x-font-truetype\":\n    case \"image/svg+xml\":\n    case \"image/x-icon\":\n    case \"image/vnd.microsoft.icon\":\n    case \"font/ttf\":\n    case \"font/eot\":\n    case \"font/otf\":\n    case \"font/opentype\":\n      estimatedSavings = Math.round(originalSize * 0.5);\n      break;\n    default:\n  }\n  return estimatedSavings < IGNORE_THRESHOLD_IN_BYTES ? 0 : estimatedSavings;\n}\nfunction finalize33(partialModel) {\n  let hasFailure = false;\n  if (partialModel.data) {\n    hasFailure = !partialModel.data.checklist.usesCompression.value || !partialModel.data.checklist.serverResponseIsFast.value || !partialModel.data.checklist.noRedirects.value;\n  }\n  return {\n    insightKey: InsightKeys.DOCUMENT_LATENCY,\n    strings: UIStrings4,\n    title: i18nString3(UIStrings4.title),\n    description: i18nString3(UIStrings4.description),\n    docs: \"https://developer.chrome.com/docs/performance/insights/document-latency\",\n    category: InsightCategory.ALL,\n    state: hasFailure ? \"fail\" : \"pass\",\n    ...partialModel\n  };\n}\nfunction generateInsight3(data31, context) {\n  if (!context.navigation) {\n    return finalize33({});\n  }\n  const millisToString = context.options.insightTimeFormatters?.milli ?? ((bytes) => ({ __i18nMillis: bytes }));\n  const documentRequest = data31.NetworkRequests.byId.get(context.navigationId);\n  if (!documentRequest) {\n    return finalize33({ warnings: [InsightWarning.NO_DOCUMENT_REQUEST] });\n  }\n  const serverResponseTime = getServerResponseTime(documentRequest);\n  if (serverResponseTime === null) {\n    throw new Error(\"missing document request timing\");\n  }\n  const serverResponseTooSlow = serverResponseTime > TOO_SLOW_THRESHOLD_MS;\n  let overallSavingsMs = 0;\n  if (serverResponseTime > TOO_SLOW_THRESHOLD_MS) {\n    overallSavingsMs = Math.max(serverResponseTime - TARGET_MS, 0);\n  }\n  const redirectDuration = Math.round(documentRequest.args.data.syntheticData.redirectionDuration / 1e3);\n  overallSavingsMs += redirectDuration;\n  const metricSavings = {\n    FCP: overallSavingsMs,\n    LCP: overallSavingsMs\n  };\n  const uncompressedResponseBytes = getCompressionSavings(documentRequest);\n  const noRedirects = redirectDuration === 0;\n  const serverResponseIsFast = !serverResponseTooSlow;\n  const usesCompression = uncompressedResponseBytes === 0;\n  return finalize33({\n    relatedEvents: [documentRequest],\n    data: {\n      serverResponseTime,\n      redirectDuration: Timing_exports.Milli(redirectDuration),\n      uncompressedResponseBytes,\n      documentRequest,\n      checklist: {\n        noRedirects: {\n          label: noRedirects ? i18nString3(UIStrings4.passingRedirects) : i18nString3(UIStrings4.failedRedirects, {\n            PH1: documentRequest.args.data.redirects.length,\n            PH2: millisToString(redirectDuration)\n          }),\n          value: noRedirects\n        },\n        serverResponseIsFast: {\n          label: serverResponseIsFast ? i18nString3(UIStrings4.passingServerResponseTime, { PH1: millisToString(serverResponseTime) }) : i18nString3(UIStrings4.failedServerResponseTime, { PH1: millisToString(serverResponseTime) }),\n          value: serverResponseIsFast\n        },\n        usesCompression: {\n          label: usesCompression ? i18nString3(UIStrings4.passingTextCompression) : i18nString3(UIStrings4.failedTextCompression),\n          value: usesCompression\n        }\n      }\n    },\n    metricSavings,\n    wastedBytes: uncompressedResponseBytes\n  });\n}\nfunction createOverlays3(model2) {\n  if (!model2.data?.documentRequest) {\n    return [];\n  }\n  const overlays = [];\n  const event = model2.data.documentRequest;\n  const redirectDurationMicro = Timing_exports3.milliToMicro(model2.data.redirectDuration);\n  const sections = [];\n  if (model2.data.redirectDuration) {\n    const bounds = Timing_exports3.traceWindowFromMicroSeconds(event.ts, event.ts + redirectDurationMicro);\n    sections.push({ bounds, label: i18nString3(UIStrings4.redirectsLabel), showDuration: true });\n    overlays.push({ type: \"CANDY_STRIPED_TIME_RANGE\", bounds, entry: event });\n  }\n  if (!model2.data.checklist.serverResponseIsFast.value) {\n    const serverResponseTimeMicro = Timing_exports3.milliToMicro(model2.data.serverResponseTime);\n    const sendEnd = event.args.data.timing?.sendEnd ?? Timing_exports.Milli(0);\n    const sendEndMicro = Timing_exports3.milliToMicro(sendEnd);\n    const bounds = Timing_exports3.traceWindowFromMicroSeconds(sendEndMicro, sendEndMicro + serverResponseTimeMicro);\n    sections.push({ bounds, label: i18nString3(UIStrings4.serverResponseTimeLabel), showDuration: true });\n  }\n  if (model2.data.uncompressedResponseBytes) {\n    const bounds = Timing_exports3.traceWindowFromMicroSeconds(event.args.data.syntheticData.downloadStart, event.args.data.syntheticData.downloadStart + event.args.data.syntheticData.download);\n    sections.push({ bounds, label: i18nString3(UIStrings4.uncompressedDownload), showDuration: true });\n    overlays.push({ type: \"CANDY_STRIPED_TIME_RANGE\", bounds, entry: event });\n  }\n  if (sections.length) {\n    overlays.push({\n      type: \"TIMESPAN_BREAKDOWN\",\n      sections,\n      entry: model2.data.documentRequest,\n      // Always render below because the document request is guaranteed to be\n      // the first request in the network track.\n      renderLocation: \"BELOW_EVENT\"\n    });\n  }\n  overlays.push({\n    type: \"ENTRY_SELECTED\",\n    entry: model2.data.documentRequest\n  });\n  return overlays;\n}\nvar UIStrings4, i18nString3, TOO_SLOW_THRESHOLD_MS, TARGET_MS, IGNORE_THRESHOLD_IN_BYTES;\nvar init_DocumentLatency = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/insights/DocumentLatency.js\"() {\n    init_process_global();\n    init_helpers2();\n    init_types2();\n    init_Common();\n    init_types4();\n    UIStrings4 = {\n      /**\n       * @description Title of an insight that provides a breakdown for how long it took to download the main document.\n       */\n      title: \"Document request latency\",\n      /**\n       * @description Description of an insight that provides a breakdown for how long it took to download the main document.\n       */\n      description: \"Your first network request is the most important. [Reduce its latency](https://developer.chrome.com/docs/performance/insights/document-latency) by avoiding redirects, ensuring a fast server response, and enabling text compression.\",\n      /**\n       * @description Text to tell the user that the document request does not have redirects.\n       */\n      passingRedirects: \"Avoids redirects\",\n      /**\n       * @description Text to tell the user that the document request had redirects.\n       * @example {3} PH1\n       * @example {1000 ms} PH2\n       */\n      failedRedirects: \"Had redirects ({PH1} redirects, +{PH2})\",\n      /**\n       * @description Text to tell the user that the time starting the document request to when the server started responding is acceptable.\n       * @example {600 ms} PH1\n       */\n      passingServerResponseTime: \"Server responds quickly (observed {PH1})\",\n      /**\n       * @description Text to tell the user that the time starting the document request to when the server started responding is not acceptable.\n       * @example {601 ms} PH1\n       */\n      failedServerResponseTime: \"Server responded slowly (observed {PH1})\",\n      /**\n       * @description Text to tell the user that text compression (like gzip) was applied.\n       */\n      passingTextCompression: \"Applies text compression\",\n      /**\n       * @description Text to tell the user that text compression (like gzip) was not applied.\n       */\n      failedTextCompression: \"No compression applied\",\n      /**\n       * @description Text for a label describing a network request event as having redirects.\n       */\n      redirectsLabel: \"Redirects\",\n      /**\n       * @description Text for a label describing a network request event as taking too long to start delivery by the server.\n       */\n      serverResponseTimeLabel: \"Server response time\",\n      /**\n       * @description Text for a label describing a network request event as taking longer to download because it wasn't compressed.\n       */\n      uncompressedDownload: \"Uncompressed download\"\n    };\n    i18nString3 = /* @__PURE__ */ __name((i18nId, values) => ({ i18nId, values }), \"i18nString\");\n    TOO_SLOW_THRESHOLD_MS = 600;\n    TARGET_MS = 100;\n    IGNORE_THRESHOLD_IN_BYTES = 1400;\n    __name(isDocumentLatencyInsight, \"isDocumentLatencyInsight\");\n    __name(getServerResponseTime, \"getServerResponseTime\");\n    __name(getCompressionSavings, \"getCompressionSavings\");\n    __name(finalize33, \"finalize\");\n    __name(generateInsight3, \"generateInsight\");\n    __name(createOverlays3, \"createOverlays\");\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/insights/DOMSize.js\nvar DOMSize_exports = {};\n__export(DOMSize_exports, {\n  UIStrings: () => UIStrings5,\n  createOverlays: () => createOverlays4,\n  generateInsight: () => generateInsight4,\n  i18nString: () => i18nString4,\n  isDomSizeInsight: () => isDomSizeInsight\n});\nfunction finalize34(partialModel) {\n  const relatedEvents = [...partialModel.largeLayoutUpdates, ...partialModel.largeStyleRecalcs];\n  return {\n    insightKey: InsightKeys.DOM_SIZE,\n    strings: UIStrings5,\n    title: i18nString4(UIStrings5.title),\n    description: i18nString4(UIStrings5.description),\n    docs: \"https://developer.chrome.com/docs/performance/insights/dom-size\",\n    category: InsightCategory.INP,\n    state: relatedEvents.length > 0 ? \"informative\" : \"pass\",\n    ...partialModel,\n    relatedEvents\n  };\n}\nfunction isDomSizeInsight(model2) {\n  return model2.insightKey === InsightKeys.DOM_SIZE;\n}\nfunction generateInsight4(data31, context) {\n  const isWithinContext = /* @__PURE__ */ __name((event) => Timing_exports3.eventIsInBounds(event, context.bounds), \"isWithinContext\");\n  const mainTid = context.navigation?.tid;\n  const largeLayoutUpdates = [];\n  const largeStyleRecalcs = [];\n  const threads = Threads_exports.threadsInRenderer(data31.Renderer, data31.AuctionWorklets);\n  for (const thread of threads) {\n    if (thread.type !== Threads_exports.ThreadType.MAIN_THREAD) {\n      continue;\n    }\n    if (mainTid === void 0) {\n      if (!thread.processIsOnMainFrame) {\n        continue;\n      }\n    } else if (thread.tid !== mainTid) {\n      continue;\n    }\n    const rendererThread = data31.Renderer.processes.get(thread.pid)?.threads.get(thread.tid);\n    if (!rendererThread) {\n      continue;\n    }\n    const { entries, layoutEvents, recalcStyleEvents } = rendererThread;\n    if (!entries.length) {\n      continue;\n    }\n    const first = entries[0];\n    const last = entries[entries.length - 1];\n    const timeRange = Timing_exports3.traceWindowFromMicroSeconds(first.ts, Timing_exports.Micro(last.ts + (last.dur ?? 0)));\n    if (!Timing_exports3.boundsIncludeTimeRange({ timeRange, bounds: context.bounds })) {\n      continue;\n    }\n    for (const event of layoutEvents) {\n      if (event.dur < DOM_SIZE_DURATION_THRESHOLD || !isWithinContext(event)) {\n        continue;\n      }\n      const { dirtyObjects } = event.args.beginData;\n      if (dirtyObjects > LAYOUT_OBJECTS_THRESHOLD) {\n        largeLayoutUpdates.push(event);\n      }\n    }\n    for (const event of recalcStyleEvents) {\n      if (event.dur < DOM_SIZE_DURATION_THRESHOLD || !isWithinContext(event)) {\n        continue;\n      }\n      const { elementCount } = event.args;\n      if (elementCount > STYLE_RECALC_ELEMENTS_THRESHOLD) {\n        largeStyleRecalcs.push(event);\n      }\n    }\n  }\n  const largeUpdates = [\n    ...largeLayoutUpdates.map((event) => {\n      const duration = event.dur / 1e3;\n      const size = event.args.beginData.dirtyObjects;\n      const label = i18nString4(UIStrings5.largeLayout, { PH1: size });\n      return { label, duration, size, event };\n    }),\n    ...largeStyleRecalcs.map((event) => {\n      const duration = event.dur / 1e3;\n      const size = event.args.elementCount;\n      const label = i18nString4(UIStrings5.largeStyleRecalc, { PH1: size });\n      return { label, duration, size, event };\n    })\n  ].sort((a, b) => b.duration - a.duration).slice(0, 5);\n  const domStatsEvents = data31.DOMStats.domStatsByFrameId.get(context.frameId)?.filter(isWithinContext) ?? [];\n  let maxDOMStats;\n  for (const domStats of domStatsEvents) {\n    const navigationPid = context.navigation?.pid;\n    if (navigationPid && domStats.pid !== navigationPid) {\n      continue;\n    }\n    if (!maxDOMStats || domStats.args.data.totalElements > maxDOMStats.args.data.totalElements) {\n      maxDOMStats = domStats;\n    }\n  }\n  return finalize34({\n    largeLayoutUpdates,\n    largeStyleRecalcs,\n    largeUpdates,\n    maxDOMStats\n  });\n}\nfunction createOverlays4(model2) {\n  const entries = [...model2.largeStyleRecalcs, ...model2.largeLayoutUpdates];\n  return entries.map((entry) => ({\n    type: \"ENTRY_OUTLINE\",\n    entry,\n    outlineReason: \"ERROR\"\n  }));\n}\nvar UIStrings5, i18nString4, DOM_SIZE_DURATION_THRESHOLD, LAYOUT_OBJECTS_THRESHOLD, STYLE_RECALC_ELEMENTS_THRESHOLD;\nvar init_DOMSize = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/insights/DOMSize.js\"() {\n    init_process_global();\n    init_handlers();\n    init_helpers2();\n    init_types2();\n    init_types4();\n    UIStrings5 = {\n      /**\n       * @description Title of an insight that recommends reducing the size of the DOM tree as a means to improve page responsiveness. \"DOM\" is an acronym and should not be translated.\n       */\n      title: \"Optimize DOM size\",\n      /**\n       * @description Description of an insight that recommends reducing the size of the DOM tree as a means to improve page responsiveness. \"DOM\" is an acronym and should not be translated. \"layout reflows\" are when the browser will recompute the layout of content on the page.\n       */\n      description: \"A large DOM can increase the duration of style calculations and layout reflows, impacting page responsiveness. A large DOM will also increase memory usage. [Learn how to avoid an excessive DOM size](https://developer.chrome.com/docs/performance/insights/dom-size).\",\n      /**\n       * @description Header for a column containing the names of statistics as opposed to the actual statistic values.\n       */\n      statistic: \"Statistic\",\n      /**\n       * @description Header for a column containing the value of a statistic.\n       */\n      value: \"Value\",\n      /**\n       * @description Header for a column containing the page element related to a statistic.\n       */\n      element: \"Element\",\n      /**\n       * @description Label for a value representing the total number of elements on the page.\n       */\n      totalElements: \"Total elements\",\n      /**\n       * @description Label for a value representing the maximum depth of the Document Object Model (DOM). \"DOM\" is a acronym and should not be translated.\n       */\n      maxDOMDepth: \"DOM depth\",\n      /**\n       * @description Label for a value representing the maximum number of child elements of any parent element on the page.\n       */\n      maxChildren: \"Most children\",\n      /**\n       * @description Text for a section.\n       */\n      topUpdatesDescription: \"These are the largest layout and style recalculation events. Their performance impact may be reduced by making the DOM simpler.\",\n      /**\n       * @description Label used for a time duration.\n       */\n      duration: \"Duration\",\n      /**\n       * @description Message displayed in a table detailing how big a layout (rendering) is.\n       * @example {134} PH1\n       */\n      largeLayout: \"Layout ({PH1} objects)\",\n      /**\n       * @description Message displayed in a table detailing how big a style recalculation (rendering) is.\n       * @example {134} PH1\n       */\n      largeStyleRecalc: \"Style recalculation ({PH1} elements)\"\n    };\n    i18nString4 = /* @__PURE__ */ __name((i18nId, values) => ({ i18nId, values }), \"i18nString\");\n    DOM_SIZE_DURATION_THRESHOLD = Timing_exports3.milliToMicro(Timing_exports.Milli(40));\n    LAYOUT_OBJECTS_THRESHOLD = 100;\n    STYLE_RECALC_ELEMENTS_THRESHOLD = 300;\n    __name(finalize34, \"finalize\");\n    __name(isDomSizeInsight, \"isDomSizeInsight\");\n    __name(generateInsight4, \"generateInsight\");\n    __name(createOverlays4, \"createOverlays\");\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/insights/DuplicatedJavaScript.js\nvar DuplicatedJavaScript_exports = {};\n__export(DuplicatedJavaScript_exports, {\n  UIStrings: () => UIStrings6,\n  createOverlays: () => createOverlays5,\n  generateInsight: () => generateInsight5,\n  i18nString: () => i18nString5,\n  isDuplicatedJavaScriptInsight: () => isDuplicatedJavaScriptInsight\n});\nfunction finalize35(partialModel) {\n  const requests = partialModel.scriptsWithDuplication.map((script) => script.request).filter((e) => !!e);\n  return {\n    insightKey: InsightKeys.DUPLICATE_JAVASCRIPT,\n    strings: UIStrings6,\n    title: i18nString5(UIStrings6.title),\n    description: i18nString5(UIStrings6.description),\n    docs: \"https://developer.chrome.com/docs/performance/insights/duplicated-javascript\",\n    category: InsightCategory.LCP,\n    state: Boolean(partialModel.duplication.values().next().value) ? \"fail\" : \"pass\",\n    relatedEvents: [...new Set(requests)],\n    ...partialModel\n  };\n}\nfunction isDuplicatedJavaScriptInsight(model2) {\n  return model2.insightKey === InsightKeys.DUPLICATE_JAVASCRIPT;\n}\nfunction generateInsight5(data31, context) {\n  const scripts = data31.Scripts.scripts.filter((script) => {\n    if (script.frame !== context.frameId) {\n      return false;\n    }\n    if (script.url?.startsWith(\"chrome-extension://\")) {\n      return false;\n    }\n    return Timing_exports3.timestampIsInBounds(context.bounds, script.ts);\n  });\n  const compressionRatios = /* @__PURE__ */ new Map();\n  for (const script of scripts) {\n    if (script.request) {\n      compressionRatios.set(script.request.args.data.requestId, estimateCompressionRatioForScript(script));\n    }\n  }\n  const { duplication, duplicationGroupedByNodeModules } = ScriptDuplication_exports.computeScriptDuplication({ scripts }, compressionRatios);\n  const scriptsWithDuplication = [...duplication.values().flatMap((data32) => data32.duplicates.map((d) => d.script))];\n  const wastedBytesByRequestId = /* @__PURE__ */ new Map();\n  for (const { duplicates } of duplication.values()) {\n    for (let i = 1; i < duplicates.length; i++) {\n      const sourceData = duplicates[i];\n      if (!sourceData.script.request) {\n        continue;\n      }\n      const transferSize = sourceData.attributedSize;\n      const requestId = sourceData.script.request.args.data.requestId;\n      wastedBytesByRequestId.set(requestId, (wastedBytesByRequestId.get(requestId) || 0) + transferSize);\n    }\n  }\n  return finalize35({\n    duplication,\n    duplicationGroupedByNodeModules,\n    scriptsWithDuplication: [...new Set(scriptsWithDuplication)],\n    scripts,\n    mainDocumentUrl: context.navigation?.args.data?.url ?? data31.Meta.mainFrameURL,\n    metricSavings: metricSavingsForWastedBytes(wastedBytesByRequestId, context),\n    wastedBytes: wastedBytesByRequestId.values().reduce((acc, cur) => acc + cur, 0)\n  });\n}\nfunction createOverlays5(model2) {\n  return model2.scriptsWithDuplication.map((script) => script.request).filter((e) => !!e).map((request) => {\n    return {\n      type: \"ENTRY_OUTLINE\",\n      entry: request,\n      outlineReason: \"ERROR\"\n    };\n  });\n}\nvar UIStrings6, i18nString5;\nvar init_DuplicatedJavaScript = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/insights/DuplicatedJavaScript.js\"() {\n    init_process_global();\n    init_extras();\n    init_helpers2();\n    init_Common();\n    init_types4();\n    UIStrings6 = {\n      /**\n       * @description Title of an insight that identifies multiple copies of the same JavaScript sources, and recommends removing the duplication.\n       */\n      title: \"Duplicated JavaScript\",\n      /**\n       * @description Description of an insight that identifies multiple copies of the same JavaScript sources, and recommends removing the duplication.\n       */\n      description: \"Remove large, [duplicate JavaScript modules](https://developer.chrome.com/docs/performance/insights/duplicated-javascript) from bundles to reduce unnecessary bytes consumed by network activity.\",\n      /** Label for a column in a data table; entries will be the locations of JavaScript or CSS code, e.g. the name of a Javascript package or module. */\n      columnSource: \"Source\",\n      /** Label for a column in a data table; entries will be the number of wasted bytes due to duplication of a web resource. */\n      columnDuplicatedBytes: \"Duplicated bytes\"\n    };\n    i18nString5 = /* @__PURE__ */ __name((i18nId, values) => ({ i18nId, values }), \"i18nString\");\n    __name(finalize35, \"finalize\");\n    __name(isDuplicatedJavaScriptInsight, \"isDuplicatedJavaScriptInsight\");\n    __name(generateInsight5, \"generateInsight\");\n    __name(createOverlays5, \"createOverlays\");\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/insights/FontDisplay.js\nvar FontDisplay_exports = {};\n__export(FontDisplay_exports, {\n  UIStrings: () => UIStrings7,\n  createOverlays: () => createOverlays6,\n  generateInsight: () => generateInsight6,\n  i18nString: () => i18nString6,\n  isFontDisplayInsight: () => isFontDisplayInsight\n});\nfunction finalize36(partialModel) {\n  return {\n    insightKey: InsightKeys.FONT_DISPLAY,\n    strings: UIStrings7,\n    title: i18nString6(UIStrings7.title),\n    description: i18nString6(UIStrings7.description),\n    docs: \"https://developer.chrome.com/docs/performance/insights/font-display\",\n    category: InsightCategory.INP,\n    state: partialModel.fonts.find((font) => font.wastedTime > 0) ? \"fail\" : \"pass\",\n    ...partialModel\n  };\n}\nfunction isFontDisplayInsight(model2) {\n  return model2.insightKey === InsightKeys.FONT_DISPLAY;\n}\nfunction generateInsight6(data31, context) {\n  const fonts = [];\n  for (const remoteFont of data31.LayoutShifts.remoteFonts) {\n    const event = remoteFont.beginRemoteFontLoadEvent;\n    if (!Timing_exports3.eventIsInBounds(event, context.bounds)) {\n      continue;\n    }\n    const requestId = `${event.pid}.${event.args.id}`;\n    const request = data31.NetworkRequests.byId.get(requestId);\n    if (!request) {\n      continue;\n    }\n    if (!/^(block|fallback|auto)$/.test(remoteFont.display)) {\n      continue;\n    }\n    const wastedTimeMicro = Timing_exports.Micro(request.args.data.syntheticData.finishTime - request.args.data.syntheticData.sendStartTime);\n    let wastedTime = NumberUtilities_exports.floor(Timing_exports3.microToMilli(wastedTimeMicro), 1 / 5);\n    if (wastedTime === 0) {\n      continue;\n    }\n    wastedTime = Math.min(wastedTime, 3e3);\n    fonts.push({\n      name: remoteFont.name,\n      request,\n      display: remoteFont.display,\n      wastedTime\n    });\n  }\n  fonts.sort((a, b) => b.wastedTime - a.wastedTime);\n  const savings = Math.max(...fonts.map((f) => f.wastedTime));\n  return finalize36({\n    relatedEvents: fonts.map((f) => f.request),\n    fonts,\n    metricSavings: { FCP: savings }\n  });\n}\nfunction createOverlays6(model2) {\n  return model2.fonts.map((font) => ({\n    type: \"ENTRY_OUTLINE\",\n    entry: font.request,\n    outlineReason: font.wastedTime ? \"ERROR\" : \"INFO\"\n  }));\n}\nvar UIStrings7, i18nString6;\nvar init_FontDisplay = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/insights/FontDisplay.js\"() {\n    init_process_global();\n    init_platform();\n    init_helpers2();\n    init_types2();\n    init_types4();\n    UIStrings7 = {\n      /** Title of an insight that provides details about the fonts used on the page, and the value of their `font-display` properties. */\n      title: \"Font display\",\n      /**\n       * @description Text to tell the user about the font-display CSS feature to help improve a the UX of a page.\n       */\n      description: \"Consider setting [`font-display`](https://developer.chrome.com/docs/performance/insights/font-display) to `swap` or `optional` to ensure text is consistently visible. `swap` can be further optimized to mitigate layout shifts with [font metric overrides](https://developer.chrome.com/blog/font-fallbacks).\",\n      /** Column for a font loaded by the page to render text. */\n      fontColumn: \"Font\",\n      /** Column for the amount of time wasted. */\n      wastedTimeColumn: \"Wasted time\"\n    };\n    i18nString6 = /* @__PURE__ */ __name((i18nId, values) => ({ i18nId, values }), \"i18nString\");\n    __name(finalize36, \"finalize\");\n    __name(isFontDisplayInsight, \"isFontDisplayInsight\");\n    __name(generateInsight6, \"generateInsight\");\n    __name(createOverlays6, \"createOverlays\");\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/insights/ForcedReflow.js\nvar ForcedReflow_exports = {};\n__export(ForcedReflow_exports, {\n  UIStrings: () => UIStrings8,\n  createOverlayForEvents: () => createOverlayForEvents,\n  createOverlays: () => createOverlays7,\n  generateInsight: () => generateInsight7,\n  i18nString: () => i18nString7,\n  isForcedReflowInsight: () => isForcedReflowInsight\n});\nfunction getCallFrameId(callFrame) {\n  return callFrame.scriptId + \":\" + callFrame.lineNumber + \":\" + callFrame.columnNumber;\n}\nfunction getLargestTopLevelFunctionData(forcedReflowEvents, traceParsedData) {\n  const entryToNodeMap = traceParsedData.Renderer.entryToNode;\n  const dataByTopLevelFunction = /* @__PURE__ */ new Map();\n  if (forcedReflowEvents.length === 0) {\n    return;\n  }\n  for (const event of forcedReflowEvents) {\n    const traceNode = entryToNodeMap.get(event);\n    if (!traceNode) {\n      continue;\n    }\n    let node = traceNode.parent;\n    let topLevelFunctionCall;\n    let topLevelFunctionCallEvent;\n    while (node) {\n      const eventData = node.entry;\n      if (TraceEvents_exports.isProfileCall(eventData)) {\n        topLevelFunctionCall = eventData.callFrame;\n        topLevelFunctionCallEvent = eventData;\n      } else {\n        if (TraceEvents_exports.isFunctionCall(eventData) && eventData.args.data && TraceEvents_exports.objectIsCallFrame(eventData.args.data)) {\n          topLevelFunctionCall = eventData.args.data;\n          topLevelFunctionCallEvent = eventData;\n        }\n        break;\n      }\n      node = node.parent;\n    }\n    if (!topLevelFunctionCall || !topLevelFunctionCallEvent) {\n      continue;\n    }\n    const aggregatedDataId = getCallFrameId(topLevelFunctionCall);\n    const aggregatedData = MapUtilities_exports.getWithDefault(dataByTopLevelFunction, aggregatedDataId, () => ({\n      topLevelFunctionCall,\n      totalReflowTime: 0,\n      topLevelFunctionCallEvents: []\n    }));\n    aggregatedData.totalReflowTime += event.dur ?? 0;\n    aggregatedData.topLevelFunctionCallEvents.push(topLevelFunctionCallEvent);\n  }\n  let topTimeConsumingData = void 0;\n  dataByTopLevelFunction.forEach((data31) => {\n    if (!topTimeConsumingData || data31.totalReflowTime > topTimeConsumingData.totalReflowTime) {\n      topTimeConsumingData = data31;\n    }\n  });\n  return topTimeConsumingData;\n}\nfunction finalize37(partialModel) {\n  return {\n    insightKey: InsightKeys.FORCED_REFLOW,\n    strings: UIStrings8,\n    title: i18nString7(UIStrings8.title),\n    description: i18nString7(UIStrings8.description),\n    docs: \"https://developer.chrome.com/docs/performance/insights/forced-reflow\",\n    category: InsightCategory.ALL,\n    state: partialModel.aggregatedBottomUpData.length !== 0 ? \"fail\" : \"pass\",\n    ...partialModel\n  };\n}\nfunction getBottomCallFrameForEvent(event, traceParsedData) {\n  const profileStackTrace = StackTraceForEvent_exports.get(event, traceParsedData);\n  const eventTopCallFrame = Trace_exports.getStackTraceTopCallFrameInEventPayload(event);\n  return profileStackTrace?.callFrames[0] ?? eventTopCallFrame ?? null;\n}\nfunction isForcedReflowInsight(model2) {\n  return model2.insightKey === InsightKeys.FORCED_REFLOW;\n}\nfunction generateInsight7(traceParsedData, context) {\n  const isWithinContext = /* @__PURE__ */ __name((event) => {\n    const frameId = Trace_exports.frameIDForEvent(event);\n    if (frameId !== context.frameId) {\n      return false;\n    }\n    return Timing_exports3.eventIsInBounds(event, context.bounds);\n  }, \"isWithinContext\");\n  const bottomUpDataMap = /* @__PURE__ */ new Map();\n  const events = traceParsedData.Warnings.perWarning.get(\"FORCED_REFLOW\")?.filter(isWithinContext) ?? [];\n  for (const event of events) {\n    const bottomCallFrame = getBottomCallFrameForEvent(event, traceParsedData);\n    const bottomCallId = bottomCallFrame ? getCallFrameId(bottomCallFrame) : \"UNATTRIBUTED\";\n    const bottomUpData = MapUtilities_exports.getWithDefault(bottomUpDataMap, bottomCallId, () => ({\n      bottomUpData: bottomCallFrame,\n      totalTime: 0,\n      relatedEvents: []\n    }));\n    bottomUpData.totalTime += event.dur ?? 0;\n    bottomUpData.relatedEvents.push(event);\n  }\n  const topLevelFunctionCallData = getLargestTopLevelFunctionData(events, traceParsedData);\n  return finalize37({\n    relatedEvents: events,\n    topLevelFunctionCallData,\n    aggregatedBottomUpData: [...bottomUpDataMap.values()]\n  });\n}\nfunction createOverlays7(model2) {\n  if (!model2.topLevelFunctionCallData) {\n    return [];\n  }\n  const allBottomUpEvents = [...model2.aggregatedBottomUpData.values().flatMap((data31) => data31.relatedEvents)];\n  return [\n    ...createOverlayForEvents(model2.topLevelFunctionCallData.topLevelFunctionCallEvents, \"INFO\"),\n    ...createOverlayForEvents(allBottomUpEvents)\n  ];\n}\nfunction createOverlayForEvents(events, outlineReason = \"ERROR\") {\n  return events.map((e) => ({\n    type: \"ENTRY_OUTLINE\",\n    entry: e,\n    outlineReason\n  }));\n}\nvar UIStrings8, i18nString7;\nvar init_ForcedReflow = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/insights/ForcedReflow.js\"() {\n    init_process_global();\n    init_platform();\n    init_extras();\n    init_helpers2();\n    init_types2();\n    init_types4();\n    UIStrings8 = {\n      /**\n       * @description Title of an insight that provides details about Forced reflow.\n       */\n      title: \"Forced reflow\",\n      /**\n       * @description Text to describe the forced reflow.\n       */\n      description: \"A forced reflow occurs when JavaScript queries geometric properties (such as `offsetWidth`) after styles have been invalidated by a change to the DOM state. This can result in poor performance. Learn more about [forced reflows](https://developer.chrome.com/docs/performance/insights/forced-reflow) and possible mitigations.\",\n      /**\n       * @description Title of a list to provide related stack trace data\n       */\n      relatedStackTrace: \"Stack trace\",\n      /**\n       * @description Text to describe the top time-consuming function call\n       */\n      topTimeConsumingFunctionCall: \"Top function call\",\n      /**\n       * @description Text to describe the total reflow time\n       */\n      totalReflowTime: \"Total reflow time\",\n      /**\n       * @description Text to describe CPU processor tasks that could not be attributed to any specific source code.\n       */\n      unattributed: \"[unattributed]\",\n      /**\n       * @description Text for the name of anonymous functions\n       */\n      anonymous: \"(anonymous)\"\n    };\n    i18nString7 = /* @__PURE__ */ __name((i18nId, values) => ({ i18nId, values }), \"i18nString\");\n    __name(getCallFrameId, \"getCallFrameId\");\n    __name(getLargestTopLevelFunctionData, \"getLargestTopLevelFunctionData\");\n    __name(finalize37, \"finalize\");\n    __name(getBottomCallFrameForEvent, \"getBottomCallFrameForEvent\");\n    __name(isForcedReflowInsight, \"isForcedReflowInsight\");\n    __name(generateInsight7, \"generateInsight\");\n    __name(createOverlays7, \"createOverlays\");\n    __name(createOverlayForEvents, \"createOverlayForEvents\");\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/insights/ImageDelivery.js\nvar ImageDelivery_exports = {};\n__export(ImageDelivery_exports, {\n  ImageOptimizationType: () => ImageOptimizationType,\n  UIStrings: () => UIStrings9,\n  createOverlayForRequest: () => createOverlayForRequest2,\n  createOverlays: () => createOverlays8,\n  generateInsight: () => generateInsight8,\n  getOptimizationMessage: () => getOptimizationMessage,\n  getOptimizationMessageWithBytes: () => getOptimizationMessageWithBytes,\n  i18nString: () => i18nString8,\n  isImageDeliveryInsight: () => isImageDeliveryInsight\n});\nfunction isImageDeliveryInsight(model2) {\n  return model2.insightKey === \"ImageDelivery\";\n}\nfunction getOptimizationMessage(optimization) {\n  switch (optimization.type) {\n    case ImageOptimizationType.ADJUST_COMPRESSION:\n      return i18nString8(UIStrings9.useCompression);\n    case ImageOptimizationType.MODERN_FORMAT_OR_COMPRESSION:\n      return i18nString8(UIStrings9.useModernFormat);\n    case ImageOptimizationType.VIDEO_FORMAT:\n      return i18nString8(UIStrings9.useVideoFormat);\n    case ImageOptimizationType.RESPONSIVE_SIZE:\n      return i18nString8(UIStrings9.useResponsiveSize, {\n        PH1: `${optimization.fileDimensions.width}x${optimization.fileDimensions.height}`,\n        PH2: `${optimization.displayDimensions.width}x${optimization.displayDimensions.height}`\n      });\n  }\n}\nfunction getOptimizationMessageWithBytes(optimization) {\n  const byteSavingsText = /* @__PURE__ */ ((bytes) => ({ __i18nBytes: bytes }))(optimization.byteSavings);\n  const optimizationMessage = getOptimizationMessage(optimization);\n  return i18nString8(UIStrings9.estimatedSavings, { PH1: optimizationMessage, PH2: byteSavingsText });\n}\nfunction finalize38(partialModel) {\n  return {\n    insightKey: InsightKeys.IMAGE_DELIVERY,\n    strings: UIStrings9,\n    title: i18nString8(UIStrings9.title),\n    description: i18nString8(UIStrings9.description),\n    docs: \"https://developer.chrome.com/docs/performance/insights/image-delivery\",\n    category: InsightCategory.LCP,\n    state: partialModel.optimizableImages.length > 0 ? \"fail\" : \"pass\",\n    ...partialModel,\n    relatedEvents: new Map(partialModel.optimizableImages.map((image) => [image.request, image.optimizations.map(getOptimizationMessageWithBytes)]))\n  };\n}\nfunction estimateGIFPercentSavings(request) {\n  return Math.round(29.1 * Math.log10(request.args.data.decodedBodyLength) - 100.7) / 100;\n}\nfunction getDisplayedSize(data31, paintImage) {\n  return data31.ImagePainting.paintEventToCorrectedDisplaySize.get(paintImage) ?? {\n    width: paintImage.args.data.width,\n    height: paintImage.args.data.height\n  };\n}\nfunction getPixelCounts(data31, paintImage) {\n  const { width, height } = getDisplayedSize(data31, paintImage);\n  return {\n    filePixels: paintImage.args.data.srcWidth * paintImage.args.data.srcHeight,\n    displayedPixels: width * height\n  };\n}\nfunction generateInsight8(data31, context) {\n  const isWithinContext = /* @__PURE__ */ __name((event) => Timing_exports3.eventIsInBounds(event, context.bounds), \"isWithinContext\");\n  const contextRequests = data31.NetworkRequests.byTime.filter(isWithinContext);\n  const optimizableImages = [];\n  for (const request of contextRequests) {\n    if (request.args.data.resourceType !== \"Image\") {\n      continue;\n    }\n    if (request.args.data.mimeType === \"image/svg+xml\") {\n      continue;\n    }\n    const url = request.args.data.redirects[0]?.url ?? request.args.data.url;\n    const imagePaints = data31.ImagePainting.paintImageEventForUrl.get(url)?.filter(isWithinContext);\n    if (!imagePaints?.length) {\n      continue;\n    }\n    const largestImagePaint = imagePaints.reduce((prev, curr) => {\n      const prevPixels = getPixelCounts(data31, prev).displayedPixels;\n      const currPixels = getPixelCounts(data31, curr).displayedPixels;\n      return prevPixels > currPixels ? prev : curr;\n    });\n    const { filePixels: imageFilePixels, displayedPixels: largestImageDisplayPixels } = getPixelCounts(data31, largestImagePaint);\n    const imageBytes = Math.min(request.args.data.decodedBodyLength, request.args.data.encodedDataLength);\n    const bytesPerPixel = imageBytes / imageFilePixels;\n    let optimizations = [];\n    if (request.args.data.mimeType === \"image/gif\") {\n      if (imageBytes > GIF_SIZE_THRESHOLD) {\n        const percentSavings = estimateGIFPercentSavings(request);\n        const byteSavings = Math.round(imageBytes * percentSavings);\n        optimizations.push({ type: ImageOptimizationType.VIDEO_FORMAT, byteSavings });\n      }\n    } else if (bytesPerPixel > TARGET_BYTES_PER_PIXEL_AVIF) {\n      const idealAvifImageSize = Math.round(TARGET_BYTES_PER_PIXEL_AVIF * imageFilePixels);\n      const byteSavings = imageBytes - idealAvifImageSize;\n      if (request.args.data.mimeType !== \"image/webp\" && request.args.data.mimeType !== \"image/avif\") {\n        optimizations.push({ type: ImageOptimizationType.MODERN_FORMAT_OR_COMPRESSION, byteSavings });\n      } else {\n        optimizations.push({ type: ImageOptimizationType.ADJUST_COMPRESSION, byteSavings });\n      }\n    }\n    const imageByteSavingsFromFormat = Math.max(0, ...optimizations.map((o) => o.byteSavings));\n    let imageByteSavings = imageByteSavingsFromFormat;\n    const wastedPixelRatio = 1 - largestImageDisplayPixels / imageFilePixels;\n    if (wastedPixelRatio > 0 && !largestImagePaint.args.data.isCSS) {\n      const byteSavings = Math.round(wastedPixelRatio * imageBytes);\n      const hadBreakpoints = largestImagePaint.args.data.isPicture || largestImagePaint.args.data.srcsetAttribute;\n      if (!hadBreakpoints || byteSavings > BYTE_SAVINGS_THRESHOLD_RESPONSIVE_BREAKPOINTS) {\n        imageByteSavings += Math.round(wastedPixelRatio * (imageBytes - imageByteSavingsFromFormat));\n        const { width, height } = getDisplayedSize(data31, largestImagePaint);\n        optimizations.push({\n          type: ImageOptimizationType.RESPONSIVE_SIZE,\n          byteSavings,\n          fileDimensions: {\n            width: Math.round(largestImagePaint.args.data.srcWidth),\n            height: Math.round(largestImagePaint.args.data.srcHeight)\n          },\n          displayDimensions: {\n            width: Math.round(width),\n            height: Math.round(height)\n          }\n        });\n      }\n    }\n    optimizations = optimizations.filter((optimization) => optimization.byteSavings > BYTE_SAVINGS_THRESHOLD);\n    if (optimizations.length > 0) {\n      optimizableImages.push({\n        request,\n        largestImagePaint,\n        optimizations,\n        byteSavings: imageByteSavings\n      });\n    }\n  }\n  const wastedBytesByRequestId = /* @__PURE__ */ new Map();\n  for (const image of optimizableImages) {\n    wastedBytesByRequestId.set(image.request.args.data.requestId, image.byteSavings);\n  }\n  optimizableImages.sort((a, b) => {\n    if (b.byteSavings !== a.byteSavings) {\n      return b.byteSavings - a.byteSavings;\n    }\n    return b.request.args.data.decodedBodyLength - a.request.args.data.decodedBodyLength;\n  });\n  return finalize38({\n    optimizableImages,\n    metricSavings: metricSavingsForWastedBytes(wastedBytesByRequestId, context),\n    wastedBytes: optimizableImages.reduce((total, img) => total + img.byteSavings, 0)\n  });\n}\nfunction createOverlayForRequest2(request) {\n  return {\n    type: \"ENTRY_OUTLINE\",\n    entry: request,\n    outlineReason: \"ERROR\"\n  };\n}\nfunction createOverlays8(model2) {\n  return model2.optimizableImages.map((image) => createOverlayForRequest2(image.request));\n}\nvar UIStrings9, i18nString8, TARGET_BYTES_PER_PIXEL_AVIF, GIF_SIZE_THRESHOLD, BYTE_SAVINGS_THRESHOLD, BYTE_SAVINGS_THRESHOLD_RESPONSIVE_BREAKPOINTS, ImageOptimizationType;\nvar init_ImageDelivery = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/insights/ImageDelivery.js\"() {\n    init_process_global();\n    init_helpers2();\n    init_Common();\n    init_types4();\n    UIStrings9 = {\n      /**\n       * @description Title of an insight that recommends ways to reduce the size of images downloaded and used on the page.\n       */\n      title: \"Improve image delivery\",\n      /**\n       * @description Description of an insight that recommends ways to reduce the size of images downloaded and used on the page.\n       */\n      description: \"Reducing the download time of images can improve the perceived load time of the page and LCP. [Learn more about optimizing image size](https://developer.chrome.com/docs/performance/insights/image-delivery)\",\n      /**\n       * @description Message displayed in a chip explaining that an image file size is large for the # of pixels it has and recommends possible adjustments to improve the image size.\n       */\n      useCompression: \"Increasing the image compression factor could improve this image's download size.\",\n      /**\n       * @description Message displayed in a chip explaining that an image file size is large for the # of pixels it has and recommends possible adjustments to improve the image size.\n       */\n      useModernFormat: \"Using a modern image format (WebP, AVIF) or increasing the image compression could improve this image's download size.\",\n      /**\n       * @description Message displayed in a chip advising the user to use video formats instead of GIFs because videos generally have smaller file sizes.\n       */\n      useVideoFormat: \"Using video formats instead of GIFs can improve the download size of animated content.\",\n      /**\n       * @description Message displayed in a chip explaining that an image was displayed on the page with dimensions much smaller than the image file dimensions.\n       * @example {1000x500} PH1\n       * @example {100x50} PH2\n       */\n      useResponsiveSize: \"This image file is larger than it needs to be ({PH1}) for its displayed dimensions ({PH2}). Use responsive images to reduce the image download size.\",\n      /**\n       * @description Column header for a table column containing network requests for images which can improve their file size (e.g. use a different format, increase compression, etc).\n       */\n      optimizeFile: \"Optimize file size\",\n      /**\n       * @description Table row value representing the remaining items not shown in the table due to size constraints. This row will always represent at least 2 items.\n       * @example {5} PH1\n       */\n      others: \"{PH1} others\",\n      /**\n       * @description Text status indicating that no potential optimizations were found for any image file\n       */\n      noOptimizableImages: \"No optimizable images\",\n      /**\n       * @description Text describing the estimated number of bytes that an image file optimization can save. This text is appended to another block of text describing the image optimization in more detail. \"Est\" means \"Estimated\".\n       * @example {Use the correct image dimensions to reduce the image file size.} PH1\n       * @example {50 MB} PH2\n       */\n      estimatedSavings: \"{PH1} (Est {PH2})\"\n    };\n    i18nString8 = /* @__PURE__ */ __name((i18nId, values) => ({ i18nId, values }), \"i18nString\");\n    TARGET_BYTES_PER_PIXEL_AVIF = 2 * 1 / 12;\n    GIF_SIZE_THRESHOLD = 100 * 1024;\n    BYTE_SAVINGS_THRESHOLD = 4096;\n    BYTE_SAVINGS_THRESHOLD_RESPONSIVE_BREAKPOINTS = 12288;\n    (function(ImageOptimizationType2) {\n      ImageOptimizationType2[\"ADJUST_COMPRESSION\"] = \"ADJUST_COMPRESSION\";\n      ImageOptimizationType2[\"MODERN_FORMAT_OR_COMPRESSION\"] = \"MODERN_FORMAT_OR_COMPRESSION\";\n      ImageOptimizationType2[\"VIDEO_FORMAT\"] = \"VIDEO_FORMAT\";\n      ImageOptimizationType2[\"RESPONSIVE_SIZE\"] = \"RESPONSIVE_SIZE\";\n    })(ImageOptimizationType || (ImageOptimizationType = {}));\n    __name(isImageDeliveryInsight, \"isImageDeliveryInsight\");\n    __name(getOptimizationMessage, \"getOptimizationMessage\");\n    __name(getOptimizationMessageWithBytes, \"getOptimizationMessageWithBytes\");\n    __name(finalize38, \"finalize\");\n    __name(estimateGIFPercentSavings, \"estimateGIFPercentSavings\");\n    __name(getDisplayedSize, \"getDisplayedSize\");\n    __name(getPixelCounts, \"getPixelCounts\");\n    __name(generateInsight8, \"generateInsight\");\n    __name(createOverlayForRequest2, \"createOverlayForRequest\");\n    __name(createOverlays8, \"createOverlays\");\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/insights/INPBreakdown.js\nvar INPBreakdown_exports = {};\n__export(INPBreakdown_exports, {\n  UIStrings: () => UIStrings10,\n  createOverlays: () => createOverlays9,\n  createOverlaysForSubpart: () => createOverlaysForSubpart,\n  generateInsight: () => generateInsight9,\n  i18nString: () => i18nString9,\n  isINPBreakdownInsight: () => isINPBreakdownInsight\n});\nfunction isINPBreakdownInsight(insight) {\n  return insight.insightKey === InsightKeys.INP_BREAKDOWN;\n}\nfunction finalize39(partialModel) {\n  let state = \"pass\";\n  if (partialModel.longestInteractionEvent) {\n    const classification = ModelHandlers_exports.UserInteractions.scoreClassificationForInteractionToNextPaint(partialModel.longestInteractionEvent.dur);\n    if (classification === ModelHandlers_exports.PageLoadMetrics.ScoreClassification.GOOD) {\n      state = \"informative\";\n    } else {\n      state = \"fail\";\n    }\n  }\n  return {\n    insightKey: InsightKeys.INP_BREAKDOWN,\n    strings: UIStrings10,\n    title: i18nString9(UIStrings10.title),\n    description: i18nString9(UIStrings10.description),\n    docs: \"https://developer.chrome.com/docs/performance/insights/inp-breakdown\",\n    category: InsightCategory.INP,\n    state,\n    ...partialModel\n  };\n}\nfunction generateInsight9(data31, context) {\n  const interactionEvents2 = data31.UserInteractions.interactionEventsWithNoNesting.filter((event) => {\n    return Timing_exports3.eventIsInBounds(event, context.bounds);\n  });\n  if (!interactionEvents2.length) {\n    return finalize39({});\n  }\n  const longestByInteractionId = /* @__PURE__ */ new Map();\n  for (const event of interactionEvents2) {\n    const key = event.interactionId;\n    const longest = longestByInteractionId.get(key);\n    if (!longest || event.dur > longest.dur) {\n      longestByInteractionId.set(key, event);\n    }\n  }\n  const normalizedInteractionEvents = [...longestByInteractionId.values()];\n  normalizedInteractionEvents.sort((a, b) => b.dur - a.dur);\n  const highPercentileIndex = Math.min(9, Math.floor(normalizedInteractionEvents.length / 50));\n  return finalize39({\n    relatedEvents: [normalizedInteractionEvents[0]],\n    longestInteractionEvent: normalizedInteractionEvents[0],\n    highPercentileInteractionEvent: normalizedInteractionEvents[highPercentileIndex]\n  });\n}\nfunction createOverlaysForSubpart(event, subpartIndex = -1) {\n  const p1 = Timing_exports3.traceWindowFromMicroSeconds(event.ts, event.ts + event.inputDelay);\n  const p2 = Timing_exports3.traceWindowFromMicroSeconds(p1.max, p1.max + event.mainThreadHandling);\n  const p3 = Timing_exports3.traceWindowFromMicroSeconds(p2.max, p2.max + event.presentationDelay);\n  let sections = [\n    { bounds: p1, label: i18nString9(UIStrings10.inputDelay), showDuration: true },\n    { bounds: p2, label: i18nString9(UIStrings10.processingDuration), showDuration: true },\n    { bounds: p3, label: i18nString9(UIStrings10.presentationDelay), showDuration: true }\n  ];\n  if (subpartIndex !== -1) {\n    sections = [sections[subpartIndex]];\n  }\n  return [\n    {\n      type: \"TIMESPAN_BREAKDOWN\",\n      sections,\n      renderLocation: \"BELOW_EVENT\",\n      entry: event\n    }\n  ];\n}\nfunction createOverlays9(model2) {\n  const event = model2.longestInteractionEvent;\n  if (!event) {\n    return [];\n  }\n  return createOverlaysForSubpart(event);\n}\nvar UIStrings10, i18nString9;\nvar init_INPBreakdown = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/insights/INPBreakdown.js\"() {\n    init_process_global();\n    init_handlers();\n    init_helpers2();\n    init_types4();\n    UIStrings10 = {\n      /**\n       * @description Text to tell the user about the longest user interaction.\n       */\n      description: \"Start investigating [how to improve INP](https://developer.chrome.com/docs/performance/insights/inp-breakdown) by looking at the longest subpart.\",\n      /**\n       * @description Title for the performance insight \"INP breakdown\", which shows a breakdown of INP by subparts / sections.\n       */\n      title: \"INP breakdown\",\n      /**\n       * @description Label used for the subpart/component/stage/section of a larger duration.\n       */\n      subpart: \"Subpart\",\n      /**\n       * @description Label used for a time duration.\n       */\n      duration: \"Duration\",\n      // TODO: these are repeated in InteractionBreakdown. Add a place for common strings?\n      /**\n       * @description Text shown next to the interaction event's input delay time in the detail view.\n       */\n      inputDelay: \"Input delay\",\n      /**\n       * @description Text shown next to the interaction event's thread processing duration in the detail view.\n       */\n      processingDuration: \"Processing duration\",\n      /**\n       * @description Text shown next to the interaction event's presentation delay time in the detail view.\n       */\n      presentationDelay: \"Presentation delay\",\n      /**\n       * @description Text status indicating that no user interactions were detected.\n       */\n      noInteractions: \"No interactions detected\"\n    };\n    i18nString9 = /* @__PURE__ */ __name((i18nId, values) => ({ i18nId, values }), \"i18nString\");\n    __name(isINPBreakdownInsight, \"isINPBreakdownInsight\");\n    __name(finalize39, \"finalize\");\n    __name(generateInsight9, \"generateInsight\");\n    __name(createOverlaysForSubpart, \"createOverlaysForSubpart\");\n    __name(createOverlays9, \"createOverlays\");\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/insights/LCPBreakdown.js\nvar LCPBreakdown_exports = {};\n__export(LCPBreakdown_exports, {\n  UIStrings: () => UIStrings11,\n  createOverlays: () => createOverlays10,\n  generateInsight: () => generateInsight10,\n  i18nString: () => i18nString10,\n  isLCPBreakdownInsight: () => isLCPBreakdownInsight\n});\nfunction isLCPBreakdownInsight(model2) {\n  return model2.insightKey === \"LCPBreakdown\";\n}\nfunction anyValuesNaN(...values) {\n  return values.some((v) => Number.isNaN(v));\n}\nfunction determineSubparts(nav, docRequest, lcpEvent, lcpRequest) {\n  const firstDocByteTs = calculateDocFirstByteTs(docRequest);\n  if (firstDocByteTs === null) {\n    return null;\n  }\n  const ttfb = Timing_exports3.traceWindowFromMicroSeconds(nav.ts, firstDocByteTs);\n  ttfb.label = i18nString10(UIStrings11.timeToFirstByte);\n  let renderDelay = Timing_exports3.traceWindowFromMicroSeconds(ttfb.max, lcpEvent.ts);\n  renderDelay.label = i18nString10(UIStrings11.elementRenderDelay);\n  if (!lcpRequest) {\n    if (anyValuesNaN(ttfb.range, renderDelay.range)) {\n      return null;\n    }\n    return { ttfb, renderDelay };\n  }\n  const lcpStartTs = lcpRequest.ts;\n  const lcpReqEndTs = lcpRequest.args.data.syntheticData.finishTime;\n  const loadDelay = Timing_exports3.traceWindowFromMicroSeconds(ttfb.max, lcpStartTs);\n  const loadDuration = Timing_exports3.traceWindowFromMicroSeconds(lcpStartTs, lcpReqEndTs);\n  renderDelay = Timing_exports3.traceWindowFromMicroSeconds(lcpReqEndTs, lcpEvent.ts);\n  loadDelay.label = i18nString10(UIStrings11.resourceLoadDelay);\n  loadDuration.label = i18nString10(UIStrings11.resourceLoadDuration);\n  renderDelay.label = i18nString10(UIStrings11.elementRenderDelay);\n  if (anyValuesNaN(ttfb.range, loadDelay.range, loadDuration.range, renderDelay.range)) {\n    return null;\n  }\n  return {\n    ttfb,\n    loadDelay,\n    loadDuration,\n    renderDelay\n  };\n}\nfunction finalize40(partialModel) {\n  const relatedEvents = [];\n  if (partialModel.lcpEvent) {\n    relatedEvents.push(partialModel.lcpEvent);\n  }\n  if (partialModel.lcpRequest) {\n    relatedEvents.push(partialModel.lcpRequest);\n  }\n  let state = \"pass\";\n  if (partialModel.lcpMs !== void 0) {\n    const classification = ModelHandlers_exports.PageLoadMetrics.scoreClassificationForLargestContentfulPaint(Timing_exports3.milliToMicro(partialModel.lcpMs));\n    if (classification === ModelHandlers_exports.PageLoadMetrics.ScoreClassification.GOOD) {\n      state = \"informative\";\n    } else {\n      state = \"fail\";\n    }\n  }\n  return {\n    insightKey: InsightKeys.LCP_BREAKDOWN,\n    strings: UIStrings11,\n    title: i18nString10(UIStrings11.title),\n    description: i18nString10(UIStrings11.description),\n    docs: \"https://developer.chrome.com/docs/performance/insights/lcp-breakdown\",\n    category: InsightCategory.LCP,\n    state,\n    ...partialModel,\n    relatedEvents\n  };\n}\nfunction generateInsight10(data31, context) {\n  if (!context.navigation) {\n    return finalize40({});\n  }\n  const networkRequests = data31.NetworkRequests;\n  const frameMetrics = data31.PageLoadMetrics.metricScoresByFrameId.get(context.frameId);\n  if (!frameMetrics) {\n    throw new Error(\"no frame metrics\");\n  }\n  const navMetrics = frameMetrics.get(context.navigationId);\n  if (!navMetrics) {\n    throw new Error(\"no navigation metrics\");\n  }\n  const metricScore = navMetrics.get(ModelHandlers_exports.PageLoadMetrics.MetricName.LCP);\n  const lcpEvent = metricScore?.event;\n  if (!lcpEvent || !TraceEvents_exports.isLargestContentfulPaintCandidate(lcpEvent)) {\n    return finalize40({ warnings: [InsightWarning.NO_LCP] });\n  }\n  const lcpMs = Timing_exports3.microToMilli(metricScore.timing);\n  const lcpTs = metricScore.event?.ts ? Timing_exports3.microToMilli(metricScore.event?.ts) : void 0;\n  const lcpRequest = data31.LargestImagePaint.lcpRequestByNavigationId.get(context.navigationId);\n  const docRequest = networkRequests.byId.get(context.navigationId);\n  if (!docRequest) {\n    return finalize40({ lcpMs, lcpTs, lcpEvent, lcpRequest, warnings: [InsightWarning.NO_DOCUMENT_REQUEST] });\n  }\n  return finalize40({\n    lcpMs,\n    lcpTs,\n    lcpEvent,\n    lcpRequest,\n    subparts: determineSubparts(context.navigation, docRequest, lcpEvent, lcpRequest) ?? void 0\n  });\n}\nfunction createOverlays10(model2) {\n  if (!model2.subparts || !model2.lcpTs) {\n    return [];\n  }\n  const overlays = [\n    {\n      type: \"TIMESPAN_BREAKDOWN\",\n      sections: Object.values(model2.subparts).map((subpart) => ({ bounds: subpart, label: subpart.label, showDuration: true }))\n    }\n  ];\n  if (model2.lcpRequest) {\n    overlays.push({ type: \"ENTRY_OUTLINE\", entry: model2.lcpRequest, outlineReason: \"INFO\" });\n  }\n  return overlays;\n}\nvar UIStrings11, i18nString10;\nvar init_LCPBreakdown = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/insights/LCPBreakdown.js\"() {\n    init_process_global();\n    init_handlers();\n    init_helpers2();\n    init_types2();\n    init_Common();\n    init_types4();\n    UIStrings11 = {\n      /**\n       * @description Title of an insight that provides details about the LCP metric, broken down by parts.\n       */\n      title: \"LCP breakdown\",\n      /**\n       * @description Description of a DevTools insight that presents a breakdown for the LCP metric by subparts.\n       * This is displayed after a user expands the section to see more. No character length limits.\n       */\n      description: \"Each [subpart has specific improvement strategies](https://developer.chrome.com/docs/performance/insights/lcp-breakdown). Ideally, most of the LCP time should be spent on loading the resources, not within delays.\",\n      /**\n       * @description Time to first byte title for the Largest Contentful Paint's subparts timespan breakdown.\n       */\n      timeToFirstByte: \"Time to first byte\",\n      /**\n       * @description Resource load delay title for the Largest Contentful Paint subparts timespan breakdown.\n       */\n      resourceLoadDelay: \"Resource load delay\",\n      /**\n       * @description Resource load duration title for the Largest Contentful Paint subparts timespan breakdown.\n       */\n      resourceLoadDuration: \"Resource load duration\",\n      /**\n       * @description Element render delay title for the Largest Contentful Paint subparts timespan breakdown.\n       */\n      elementRenderDelay: \"Element render delay\",\n      /**\n       * @description Label used for the subpart (section) of a larger duration.\n       */\n      subpart: \"Subpart\",\n      /**\n       * @description Label used for the duration a single subpart (section) takes up of a larger duration.\n       */\n      duration: \"Duration\",\n      /**\n       * @description Label used for the duration a single subpart (section) takes up of a larger duration. The value will be the 75th percentile of aggregate data. \"Field\" means that the data was collected from real users in the field as opposed to the developers local environment. \"Field\" is synonymous with \"Real user data\".\n       */\n      fieldDuration: \"Field p75\",\n      /**\n       * @description Text status indicating that the the Largest Contentful Paint (LCP) metric timing was not found. \"LCP\" is an acronym and should not be translated.\n       */\n      noLcp: \"No LCP detected\"\n    };\n    i18nString10 = /* @__PURE__ */ __name((i18nId, values) => ({ i18nId, values }), \"i18nString\");\n    __name(isLCPBreakdownInsight, \"isLCPBreakdownInsight\");\n    __name(anyValuesNaN, \"anyValuesNaN\");\n    __name(determineSubparts, \"determineSubparts\");\n    __name(finalize40, \"finalize\");\n    __name(generateInsight10, \"generateInsight\");\n    __name(createOverlays10, \"createOverlays\");\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/insights/LCPDiscovery.js\nvar LCPDiscovery_exports = {};\n__export(LCPDiscovery_exports, {\n  UIStrings: () => UIStrings12,\n  createOverlays: () => createOverlays11,\n  generateInsight: () => generateInsight11,\n  getImageData: () => getImageData,\n  i18nString: () => i18nString11,\n  isLCPDiscoveryInsight: () => isLCPDiscoveryInsight\n});\nfunction isLCPDiscoveryInsight(model2) {\n  return model2.insightKey === \"LCPDiscovery\";\n}\nfunction finalize41(partialModel) {\n  const relatedEvents = partialModel.lcpEvent && partialModel.lcpRequest ? (\n    // TODO: add entire request initiator chain?\n    [partialModel.lcpEvent, partialModel.lcpRequest]\n  ) : [];\n  return {\n    insightKey: InsightKeys.LCP_DISCOVERY,\n    strings: UIStrings12,\n    title: i18nString11(UIStrings12.title),\n    description: i18nString11(UIStrings12.description),\n    docs: \"https://developer.chrome.com/docs/performance/insights/lcp-discovery\",\n    category: InsightCategory.LCP,\n    state: partialModel.lcpRequest && partialModel.checklist && (!partialModel.checklist.eagerlyLoaded.value || !partialModel.checklist.requestDiscoverable.value || !partialModel.checklist.priorityHinted.value) ? \"fail\" : \"pass\",\n    ...partialModel,\n    relatedEvents\n  };\n}\nfunction generateInsight11(data31, context) {\n  if (!context.navigation) {\n    return finalize41({});\n  }\n  const networkRequests = data31.NetworkRequests;\n  const frameMetrics = data31.PageLoadMetrics.metricScoresByFrameId.get(context.frameId);\n  if (!frameMetrics) {\n    throw new Error(\"no frame metrics\");\n  }\n  const navMetrics = frameMetrics.get(context.navigationId);\n  if (!navMetrics) {\n    throw new Error(\"no navigation metrics\");\n  }\n  const metricScore = navMetrics.get(ModelHandlers_exports.PageLoadMetrics.MetricName.LCP);\n  const lcpEvent = metricScore?.event;\n  if (!lcpEvent || !TraceEvents_exports.isLargestContentfulPaintCandidate(lcpEvent)) {\n    return finalize41({ warnings: [InsightWarning.NO_LCP] });\n  }\n  const docRequest = networkRequests.byId.get(context.navigationId);\n  if (!docRequest) {\n    return finalize41({ warnings: [InsightWarning.NO_DOCUMENT_REQUEST] });\n  }\n  const lcpRequest = data31.LargestImagePaint.lcpRequestByNavigationId.get(context.navigationId);\n  if (!lcpRequest) {\n    return finalize41({ lcpEvent });\n  }\n  const initiatorUrl = lcpRequest.args.data.initiator?.url;\n  const initiatedByMainDoc = lcpRequest?.args.data.initiator?.type === \"parser\" && docRequest.args.data.url === initiatorUrl;\n  const imgPreloadedOrFoundInHTML = lcpRequest?.args.data.isLinkPreload || initiatedByMainDoc;\n  const imageLoadingAttr = lcpEvent.args.data?.loadingAttr;\n  const imageFetchPriorityHint = lcpRequest?.args.data.fetchPriorityHint;\n  const earliestDiscoveryTime = calculateDocFirstByteTs(docRequest);\n  const priorityHintFound = imageFetchPriorityHint === \"high\";\n  return finalize41({\n    lcpEvent,\n    lcpRequest,\n    earliestDiscoveryTimeTs: earliestDiscoveryTime ? Timing_exports.Micro(earliestDiscoveryTime) : void 0,\n    checklist: {\n      priorityHinted: {\n        label: priorityHintFound ? i18nString11(UIStrings12.fetchPriorityApplied) : i18nString11(UIStrings12.fetchPriorityShouldBeApplied),\n        value: priorityHintFound\n      },\n      requestDiscoverable: { label: i18nString11(UIStrings12.requestDiscoverable), value: imgPreloadedOrFoundInHTML },\n      eagerlyLoaded: { label: i18nString11(UIStrings12.lazyLoadNotApplied), value: imageLoadingAttr !== \"lazy\" }\n    }\n  });\n}\nfunction getImageData(model2) {\n  if (!model2.lcpRequest || !model2.checklist) {\n    return null;\n  }\n  const shouldIncreasePriorityHint = !model2.checklist.priorityHinted.value;\n  const shouldPreloadImage = !model2.checklist.requestDiscoverable.value;\n  const shouldRemoveLazyLoading = !model2.checklist.eagerlyLoaded.value;\n  const imageLCP = shouldIncreasePriorityHint !== void 0 && shouldPreloadImage !== void 0 && shouldRemoveLazyLoading !== void 0;\n  if (!imageLCP) {\n    return null;\n  }\n  const data31 = {\n    checklist: model2.checklist,\n    request: model2.lcpRequest,\n    discoveryDelay: null,\n    estimatedSavings: model2.metricSavings?.LCP ?? null\n  };\n  if (model2.earliestDiscoveryTimeTs && model2.lcpRequest) {\n    const discoveryDelay = model2.lcpRequest.ts - model2.earliestDiscoveryTimeTs;\n    data31.discoveryDelay = Timing_exports.Micro(discoveryDelay);\n  }\n  return data31;\n}\nfunction createOverlays11(model2) {\n  const imageResults = getImageData(model2);\n  if (!imageResults?.discoveryDelay) {\n    return [];\n  }\n  const delay = Timing_exports3.traceWindowFromMicroSeconds(Timing_exports.Micro(imageResults.request.ts - imageResults.discoveryDelay), imageResults.request.ts);\n  return [\n    {\n      type: \"ENTRY_OUTLINE\",\n      entry: imageResults.request,\n      outlineReason: \"ERROR\"\n    },\n    {\n      type: \"CANDY_STRIPED_TIME_RANGE\",\n      bounds: delay,\n      entry: imageResults.request\n    },\n    {\n      type: \"TIMESPAN_BREAKDOWN\",\n      sections: [{\n        bounds: delay,\n        // This is overridden in the component.\n        label: `${imageResults.discoveryDelay} microseconds`,\n        showDuration: false\n      }],\n      entry: imageResults.request,\n      renderLocation: \"ABOVE_EVENT\"\n    }\n  ];\n}\nvar UIStrings12, i18nString11;\nvar init_LCPDiscovery = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/insights/LCPDiscovery.js\"() {\n    init_process_global();\n    init_handlers();\n    init_helpers2();\n    init_types2();\n    init_Common();\n    init_types4();\n    UIStrings12 = {\n      /**\n       * @description Title of an insight that provides details about the LCP metric, and the network requests necessary to load it. Details how the LCP request was discoverable - in other words, the path necessary to load it (ex: network requests, JavaScript)\n       */\n      title: \"LCP request discovery\",\n      /**\n       * @description Description of an insight that provides details about the LCP metric, and the network requests necessary to load it.\n       */\n      description: \"[Optimize LCP](https://developer.chrome.com/docs/performance/insights/lcp-discovery) by making the LCP image discoverable from the HTML immediately, and avoiding lazy-loading\",\n      /**\n       * @description Text to tell the user how long after the earliest discovery time their LCP element loaded.\n       * @example {401ms} PH1\n       */\n      lcpLoadDelay: \"LCP image loaded {PH1} after earliest start point.\",\n      /**\n       * @description Text to tell the user that a fetchpriority property value of \"high\" is applied to the LCP request.\n       */\n      fetchPriorityApplied: \"fetchpriority=high applied\",\n      /**\n       * @description Text to tell the user that a fetchpriority property value of \"high\" should be applied to the LCP request.\n       */\n      fetchPriorityShouldBeApplied: \"fetchpriority=high should be applied\",\n      /**\n       * @description Text to tell the user that the LCP request is discoverable in the initial document.\n       */\n      requestDiscoverable: \"Request is discoverable in initial document\",\n      /**\n       * @description Text to tell the user that the LCP request does not have the lazy load property applied.\n       */\n      lazyLoadNotApplied: \"lazy load not applied\",\n      /**\n       * @description Text status indicating that the the Largest Contentful Paint (LCP) metric timing was not found. \"LCP\" is an acronym and should not be translated.\n       */\n      noLcp: \"No LCP detected\",\n      /**\n       * @description Text status indicating that the Largest Contentful Paint (LCP) metric was text rather than an image. \"LCP\" is an acronym and should not be translated.\n       */\n      noLcpResource: \"No LCP resource detected because the LCP is not an image\"\n    };\n    i18nString11 = /* @__PURE__ */ __name((i18nId, values) => ({ i18nId, values }), \"i18nString\");\n    __name(isLCPDiscoveryInsight, \"isLCPDiscoveryInsight\");\n    __name(finalize41, \"finalize\");\n    __name(generateInsight11, \"generateInsight\");\n    __name(getImageData, \"getImageData\");\n    __name(createOverlays11, \"createOverlays\");\n  }\n});\n\n// node_modules/legacy-javascript/legacy-javascript.js\nvar legacy_javascript_exports = {};\n__export(legacy_javascript_exports, {\n  detectLegacyJavaScript: () => detectLegacyJavaScript,\n  getCoreJsPolyfillData: () => getCoreJsPolyfillData,\n  getTransformPatterns: () => getTransformPatterns\n});\nfunction buildPolyfillExpression(object, property, coreJs3Module) {\n  const qt = /* @__PURE__ */ __name((token) => `['\"]${token}['\"]`, \"qt\");\n  let expression = \"\";\n  if (object) {\n    expression += `${object}\\\\.${property}\\\\s?=[^=]`;\n  } else {\n    expression += `(?:window\\\\.|[\\\\s;]+)${property}\\\\s?=[^=]`;\n  }\n  if (object) {\n    expression += `|${object}\\\\[${qt(property)}\\\\]\\\\s?=[^=]`;\n  }\n  expression += `|defineProperty\\\\(${object || \"window\"},\\\\s?${qt(property)}`;\n  if (object) {\n    expression += `|\\\\(${object},\\\\s*{${property}:.*},\\\\s*{${property}`;\n  }\n  if (object) {\n    const objectWithoutPrototype = object.replace(\".prototype\", \"\");\n    expression += `|{target:${qt(objectWithoutPrototype)}[^;]*},{${property}:`;\n  } else {\n  }\n  expression += `|${coreJs3Module.replaceAll(\".\", \"\\\\.\")}(?:\\\\.js)?\"`;\n  return expression;\n}\nfunction getCoreJsPolyfillData() {\n  return polyfillModuleData.filter((d) => d.corejs).map((d) => {\n    return {\n      name: d.name,\n      coreJs3Module: d.modules[0]\n    };\n  });\n}\nfunction getPolyfillPatterns() {\n  const patterns = [];\n  for (const { name, coreJs3Module } of getCoreJsPolyfillData()) {\n    const parts = name.split(\".\");\n    const object = parts.length > 1 ? parts.slice(0, parts.length - 1).join(\".\") : null;\n    const property = parts[parts.length - 1];\n    patterns.push({\n      name,\n      expression: buildPolyfillExpression(object, property, coreJs3Module)\n    });\n  }\n  return patterns;\n}\nfunction getTransformPatterns() {\n  const count = /* @__PURE__ */ __name((content, pattern) => {\n    if (typeof pattern === \"string\") {\n      return content.split(pattern).length - 1;\n    }\n    return (content.match(pattern) ?? []).length;\n  }, \"count\");\n  return [\n    // @babel/plugin-transform-classes\n    //\n    // input:\n    //\n    // class MyTestClass {\n    //   log() {\n    //     console.log(1);\n    //   }\n    // };\n    //\n    // output:\n    //\n    // function _classCallCheck(a, n) { if (!(a instanceof n)) throw new TypeError(\"Cannot call a class as a function\"); }\n    // function _defineProperties(e, r) { for (var t = 0; t < r.length; t++) { var o = r[t]; o.enumerable = o.enumerable || !1, o.configurable = !0, \"value\" in o && (o.writable = !0), Object.defineProperty(e, _toPropertyKey(o.key), o); } }\n    // function _createClass(e, r, t) { return r && _defineProperties(e.prototype, r), t && _defineProperties(e, t), Object.defineProperty(e, \"prototype\", { writable: !1 }), e; }\n    // function _toPropertyKey(t) { var i = _toPrimitive(t, \"string\"); return \"symbol\" == typeof i ? i : i + \"\"; }\n    // function _toPrimitive(t, r) { if (\"object\" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || \"default\"); if (\"object\" != typeof i) return i; throw new TypeError(\"@@toPrimitive must return a primitive value.\"); } return (\"string\" === r ? String : Number)(t); }\n    // let MyTestClass = function () {\n    //   function MyTestClass() {\n    //     _classCallCheck(this, MyTestClass);\n    //   }\n    //   return _createClass(MyTestClass, [{\n    //     key: \"log\",\n    //     value: function log() {\n    //       console.log(1);\n    //     }\n    //   }]);\n    // }();\n    {\n      name: \"@babel/plugin-transform-classes\",\n      expression: \"Cannot call a class as a function\",\n      estimateBytes: /* @__PURE__ */ __name((content) => {\n        return 1e3 + (count(content, \"_classCallCheck\") - 1) * \"_classCallCheck()\".length;\n      }, \"estimateBytes\")\n    },\n    {\n      name: \"@babel/plugin-transform-regenerator\",\n      expression: \"Generator is already running|regeneratorRuntime\",\n      // Example of this transform: https://gist.github.com/connorjclark/af8bccfff377ac44efc104a79bc75da2\n      // `regeneratorRuntime.awrap` is generated for every usage of `await`, and adds ~80 bytes each.\n      estimateBytes: /* @__PURE__ */ __name((content) => {\n        return count(content, /regeneratorRuntime\\(?\\)?\\.a?wrap/g) * 80;\n      }, \"estimateBytes\")\n    },\n    {\n      name: \"@babel/plugin-transform-spread\",\n      expression: \"Invalid attempt to spread non-iterable instance\",\n      estimateBytes: /* @__PURE__ */ __name((content) => {\n        const per = \"_toConsumableArray()\".length;\n        return 1169 + count(content, /\\.apply\\(void 0,\\s?_toConsumableArray/g) * per;\n      }, \"estimateBytes\")\n    }\n  ];\n}\nfunction estimateWastedBytes(content, matches) {\n  const polyfillResults = matches.filter((m) => !m.name.startsWith(\"@\"));\n  const transformResults = matches.filter((m) => m.name.startsWith(\"@\"));\n  let estimatedWastedBytesFromPolyfills = 0;\n  const modulesSeen = /* @__PURE__ */ new Set();\n  for (const result of polyfillResults) {\n    const modules = graph.dependencies[result.name];\n    if (!modules)\n      continue;\n    for (const module2 of modules) {\n      modulesSeen.add(module2);\n    }\n  }\n  estimatedWastedBytesFromPolyfills += [...modulesSeen].reduce((acc, moduleIndex) => {\n    return acc + graph.moduleSizes[moduleIndex];\n  }, 0);\n  estimatedWastedBytesFromPolyfills = Math.min(estimatedWastedBytesFromPolyfills, graph.maxSize);\n  let estimatedWastedBytesFromTransforms = 0;\n  for (const result of transformResults) {\n    const pattern = getTransformPatterns().find((p) => p.name === result.name);\n    if (!pattern || !pattern.estimateBytes || !content)\n      continue;\n    estimatedWastedBytesFromTransforms += pattern.estimateBytes(content);\n  }\n  const estimatedWastedBytes = estimatedWastedBytesFromPolyfills + estimatedWastedBytesFromTransforms;\n  return estimatedWastedBytes;\n}\nfunction detectLegacyJavaScript(content, map) {\n  if (!content)\n    return { matches: [], estimatedByteSavings: 0 };\n  let matches = matcher.match(content);\n  if (map) {\n    for (const { name, modules } of polyfillModuleData) {\n      if (matches.some((m) => m.name === name))\n        continue;\n      const source = map.sourceURLs().find((source2) => modules.some((module2) => {\n        return source2.endsWith(`/${module2}.js`) || source2.includes(`node_modules/${module2}/`);\n      }));\n      if (!source)\n        continue;\n      const mapping = map.mappings().find((m) => m.sourceURL === source);\n      if (mapping) {\n        matches.push({ name, line: mapping.lineNumber, column: mapping.columnNumber });\n      } else {\n        matches.push({ name, line: 0, column: 0 });\n      }\n    }\n  }\n  matches = matches.sort((a, b) => a.name > b.name ? 1 : a.name === b.name ? 0 : -1);\n  return {\n    matches,\n    estimatedByteSavings: estimateWastedBytes(content, matches)\n  };\n}\nvar polyfill_module_data_default, polyfill_graph_data_default, polyfillModuleData, graph, CodePatternMatcher, matcher;\nvar init_legacy_javascript = __esm({\n  \"node_modules/legacy-javascript/legacy-javascript.js\"() {\n    init_process_global();\n    polyfill_module_data_default = [\n      {\n        name: \"focus-visible\",\n        modules: [\n          \"focus-visible\"\n        ]\n      },\n      {\n        name: \"Error.prototype.cause\",\n        modules: [\n          \"es.error.cause\"\n        ]\n      },\n      {\n        name: \"Array.prototype.at\",\n        modules: [\n          \"es.array.at\",\n          \"esnext.array.at\"\n        ],\n        corejs: true\n      },\n      {\n        name: \"Array.prototype.concat\",\n        modules: [\n          \"es.array.concat\"\n        ],\n        corejs: true\n      },\n      {\n        name: \"Array.prototype.copyWithin\",\n        modules: [\n          \"es.array.copy-within\"\n        ],\n        corejs: true\n      },\n      {\n        name: \"Array.prototype.every\",\n        modules: [\n          \"es.array.every\"\n        ],\n        corejs: true\n      },\n      {\n        name: \"Array.prototype.fill\",\n        modules: [\n          \"es.array.fill\"\n        ],\n        corejs: true\n      },\n      {\n        name: \"Array.prototype.filter\",\n        modules: [\n          \"es.array.filter\"\n        ],\n        corejs: true\n      },\n      {\n        name: \"Array.prototype.find\",\n        modules: [\n          \"es.array.find\"\n        ],\n        corejs: true\n      },\n      {\n        name: \"Array.prototype.findIndex\",\n        modules: [\n          \"es.array.find-index\"\n        ],\n        corejs: true\n      },\n      {\n        name: \"Array.prototype.findLast\",\n        modules: [\n          \"es.array.find-last\",\n          \"esnext.array.find-last\"\n        ],\n        corejs: true\n      },\n      {\n        name: \"Array.prototype.findLastIndex\",\n        modules: [\n          \"es.array.find-last-index\",\n          \"esnext.array.find-last-index\"\n        ],\n        corejs: true\n      },\n      {\n        name: \"Array.prototype.flat\",\n        modules: [\n          \"es.array.flat\"\n        ],\n        corejs: true\n      },\n      {\n        name: \"Array.prototype.flatMap\",\n        modules: [\n          \"es.array.flat-map\"\n        ],\n        corejs: true\n      },\n      {\n        name: \"Array.prototype.forEach\",\n        modules: [\n          \"es.array.for-each\"\n        ],\n        corejs: true\n      },\n      {\n        name: \"Array.from\",\n        modules: [\n          \"es.array.from\"\n        ],\n        corejs: true\n      },\n      {\n        name: \"Array.prototype.includes\",\n        modules: [\n          \"es.array.includes\"\n        ],\n        corejs: true\n      },\n      {\n        name: \"Array.prototype.indexOf\",\n        modules: [\n          \"es.array.index-of\"\n        ],\n        corejs: true\n      },\n      {\n        name: \"Array.isArray\",\n        modules: [\n          \"es.array.is-array\"\n        ],\n        corejs: true\n      },\n      {\n        name: \"Array.prototype.join\",\n        modules: [\n          \"es.array.join\"\n        ],\n        corejs: true\n      },\n      {\n        name: \"Array.prototype.map\",\n        modules: [\n          \"es.array.map\"\n        ],\n        corejs: true\n      },\n      {\n        name: \"Array.of\",\n        modules: [\n          \"es.array.of\"\n        ],\n        corejs: true\n      },\n      {\n        name: \"Array.prototype.slice\",\n        modules: [\n          \"es.array.slice\"\n        ],\n        corejs: true\n      },\n      {\n        name: \"Array.prototype.some\",\n        modules: [\n          \"es.array.some\"\n        ],\n        corejs: true\n      },\n      {\n        name: \"Array.prototype.sort\",\n        modules: [\n          \"es.array.sort\"\n        ],\n        corejs: true\n      },\n      {\n        name: \"Array.prototype.unshift\",\n        modules: [\n          \"es.array.unshift\"\n        ],\n        corejs: true\n      },\n      {\n        name: \"Math.acosh\",\n        modules: [\n          \"es.math.acosh\"\n        ],\n        corejs: true\n      },\n      {\n        name: \"Math.asinh\",\n        modules: [\n          \"es.math.asinh\"\n        ],\n        corejs: true\n      },\n      {\n        name: \"Math.atanh\",\n        modules: [\n          \"es.math.atanh\"\n        ],\n        corejs: true\n      },\n      {\n        name: \"Math.cbrt\",\n        modules: [\n          \"es.math.cbrt\"\n        ],\n        corejs: true\n      },\n      {\n        name: \"Math.clz32\",\n        modules: [\n          \"es.math.clz32\"\n        ],\n        corejs: true\n      },\n      {\n        name: \"Math.cosh\",\n        modules: [\n          \"es.math.cosh\"\n        ],\n        corejs: true\n      },\n      {\n        name: \"Math.expm1\",\n        modules: [\n          \"es.math.expm1\"\n        ],\n        corejs: true\n      },\n      {\n        name: \"Math.fround\",\n        modules: [\n          \"es.math.fround\"\n        ],\n        corejs: true\n      },\n      {\n        name: \"Math.hypot\",\n        modules: [\n          \"es.math.hypot\"\n        ],\n        corejs: true\n      },\n      {\n        name: \"Math.imul\",\n        modules: [\n          \"es.math.imul\"\n        ],\n        corejs: true\n      },\n      {\n        name: \"Math.log10\",\n        modules: [\n          \"es.math.log10\"\n        ],\n        corejs: true\n      },\n      {\n        name: \"Math.log1p\",\n        modules: [\n          \"es.math.log1p\"\n        ],\n        corejs: true\n      },\n      {\n        name: \"Math.log2\",\n        modules: [\n          \"es.math.log2\"\n        ],\n        corejs: true\n      },\n      {\n        name: \"Math.sign\",\n        modules: [\n          \"es.math.sign\"\n        ],\n        corejs: true\n      },\n      {\n        name: \"Math.sinh\",\n        modules: [\n          \"es.math.sinh\"\n        ],\n        corejs: true\n      },\n      {\n        name: \"Math.tanh\",\n        modules: [\n          \"es.math.tanh\"\n        ],\n        corejs: true\n      },\n      {\n        name: \"Math.trunc\",\n        modules: [\n          \"es.math.trunc\"\n        ],\n        corejs: true\n      },\n      {\n        name: \"Object.assign\",\n        modules: [\n          \"es.object.assign\"\n        ],\n        corejs: true\n      },\n      {\n        name: \"Object.create\",\n        modules: [\n          \"es.object.create\"\n        ],\n        corejs: true\n      },\n      {\n        name: \"Object.entries\",\n        modules: [\n          \"es.object.entries\"\n        ],\n        corejs: true\n      },\n      {\n        name: \"Object.freeze\",\n        modules: [\n          \"es.object.freeze\"\n        ],\n        corejs: true\n      },\n      {\n        name: \"Object.fromEntries\",\n        modules: [\n          \"es.object.from-entries\"\n        ],\n        corejs: true\n      },\n      {\n        name: \"Object.getOwnPropertyDescriptor\",\n        modules: [\n          \"es.object.get-own-property-descriptor\"\n        ],\n        corejs: true\n      },\n      {\n        name: \"Object.getOwnPropertyDescriptors\",\n        modules: [\n          \"es.object.get-own-property-descriptors\"\n        ],\n        corejs: true\n      },\n      {\n        name: \"Object.getPrototypeOf\",\n        modules: [\n          \"es.object.get-prototype-of\"\n        ],\n        corejs: true\n      },\n      {\n        name: \"Object.hasOwn\",\n        modules: [\n          \"es.object.has-own\",\n          \"esnext.object.has-own\"\n        ],\n        corejs: true\n      },\n      {\n        name: \"Object.is\",\n        modules: [\n          \"es.object.is\"\n        ],\n        corejs: true\n      },\n      {\n        name: \"Object.isExtensible\",\n        modules: [\n          \"es.object.is-extensible\"\n        ],\n        corejs: true\n      },\n      {\n        name: \"Object.isFrozen\",\n        modules: [\n          \"es.object.is-frozen\"\n        ],\n        corejs: true\n      },\n      {\n        name: \"Object.isSealed\",\n        modules: [\n          \"es.object.is-sealed\"\n        ],\n        corejs: true\n      },\n      {\n        name: \"Object.keys\",\n        modules: [\n          \"es.object.keys\"\n        ],\n        corejs: true\n      },\n      {\n        name: \"Object.preventExtensions\",\n        modules: [\n          \"es.object.prevent-extensions\"\n        ],\n        corejs: true\n      },\n      {\n        name: \"Object.seal\",\n        modules: [\n          \"es.object.seal\"\n        ],\n        corejs: true\n      },\n      {\n        name: \"Object.setPrototypeOf\",\n        modules: [\n          \"es.object.set-prototype-of\"\n        ],\n        corejs: true\n      },\n      {\n        name: \"Object.values\",\n        modules: [\n          \"es.object.values\"\n        ],\n        corejs: true\n      },\n      {\n        name: \"Promise.any\",\n        modules: [\n          \"es.promise.any\",\n          \"esnext.promise.any\"\n        ],\n        corejs: true\n      },\n      {\n        name: \"Reflect.apply\",\n        modules: [\n          \"es.reflect.apply\"\n        ],\n        corejs: true\n      },\n      {\n        name: \"Reflect.construct\",\n        modules: [\n          \"es.reflect.construct\"\n        ],\n        corejs: true\n      },\n      {\n        name: \"Reflect.deleteProperty\",\n        modules: [\n          \"es.reflect.delete-property\"\n        ],\n        corejs: true\n      },\n      {\n        name: \"Reflect.get\",\n        modules: [\n          \"es.reflect.get\"\n        ],\n        corejs: true\n      },\n      {\n        name: \"Reflect.getOwnPropertyDescriptor\",\n        modules: [\n          \"es.reflect.get-own-property-descriptor\"\n        ],\n        corejs: true\n      },\n      {\n        name: \"Reflect.getPrototypeOf\",\n        modules: [\n          \"es.reflect.get-prototype-of\"\n        ],\n        corejs: true\n      },\n      {\n        name: \"Reflect.has\",\n        modules: [\n          \"es.reflect.has\"\n        ],\n        corejs: true\n      },\n      {\n        name: \"Reflect.isExtensible\",\n        modules: [\n          \"es.reflect.is-extensible\"\n        ],\n        corejs: true\n      },\n      {\n        name: \"Reflect.ownKeys\",\n        modules: [\n          \"es.reflect.own-keys\"\n        ],\n        corejs: true\n      },\n      {\n        name: \"Reflect.preventExtensions\",\n        modules: [\n          \"es.reflect.prevent-extensions\"\n        ],\n        corejs: true\n      },\n      {\n        name: \"Reflect.setPrototypeOf\",\n        modules: [\n          \"es.reflect.set-prototype-of\"\n        ],\n        corejs: true\n      },\n      {\n        name: \"String.prototype.codePointAt\",\n        modules: [\n          \"es.string.code-point-at\"\n        ],\n        corejs: true\n      },\n      {\n        name: \"String.prototype.endsWith\",\n        modules: [\n          \"es.string.ends-with\"\n        ],\n        corejs: true\n      },\n      {\n        name: \"String.fromCodePoint\",\n        modules: [\n          \"es.string.from-code-point\"\n        ],\n        corejs: true\n      },\n      {\n        name: \"String.prototype.includes\",\n        modules: [\n          \"es.string.includes\"\n        ],\n        corejs: true\n      },\n      {\n        name: \"String.prototype.matchAll\",\n        modules: [\n          \"es.string.match-all\",\n          \"esnext.string.match-all\"\n        ],\n        corejs: true\n      },\n      {\n        name: \"String.raw\",\n        modules: [\n          \"es.string.raw\"\n        ],\n        corejs: true\n      },\n      {\n        name: \"String.prototype.repeat\",\n        modules: [\n          \"es.string.repeat\"\n        ],\n        corejs: true\n      },\n      {\n        name: \"String.prototype.replaceAll\",\n        modules: [\n          \"es.string.replace-all\",\n          \"esnext.string.replace-all\"\n        ],\n        corejs: true\n      },\n      {\n        name: \"String.prototype.startsWith\",\n        modules: [\n          \"es.string.starts-with\"\n        ],\n        corejs: true\n      },\n      {\n        name: \"String.prototype.substr\",\n        modules: [\n          \"es.string.substr\"\n        ],\n        corejs: true\n      },\n      {\n        name: \"String.prototype.trim\",\n        modules: [\n          \"es.string.trim\"\n        ],\n        corejs: true\n      },\n      {\n        name: \"String.prototype.trimEnd\",\n        modules: [\n          \"es.string.trim-end\"\n        ],\n        corejs: true\n      },\n      {\n        name: \"String.prototype.trimStart\",\n        modules: [\n          \"es.string.trim-start\"\n        ],\n        corejs: true\n      },\n      {\n        name: \"String.prototype.link\",\n        modules: [\n          \"es.string.link\"\n        ],\n        corejs: true\n      },\n      {\n        name: \"Promise.allSettled\",\n        modules: [\n          \"esnext.promise.all-settled\"\n        ],\n        corejs: true\n      }\n    ];\n    polyfill_graph_data_default = {\n      moduleSizes: [26070, 498, 282, 294, 281, 467, 161, 236, 229, 765, 546, 339, 1608, 723, 729, 1545, 438, 214, 657, 111, 759, 537, 209, 281, 685, 217, 757, 631, 293, 182, 475, 79, 407, 140, 366, 792, 269, 222, 158, 280, 188, 137, 158, 105, 189, 543, 160, 742, 1436, 88, 904, 146, 314, 375, 183, 1083, 195, 503, 269, 208, 334, 350, 460, 568, 229, 1155, 334, 266, 30, 120, 309, 370, 358, 1952, 1638, 304, 153, 274, 1288, 192, 543, 74, 144, 137, 33, 336, 457, 2122, 535, 711, 1323, 117, 1961, 244, 557, 318, 119, 124, 108, 144, 96, 133, 441, 210, 1627, 1956, 693, 1426, 863, 637, 301, 51, 708, 583, 119, 600, 221, 370, 728, 1085, 552, 629, 125, 1746, 97, 441, 543, 2756, 371, 447, 548, 243, 266, 217, 99, 440, 183, 546, 137, 464, 207, 983, 503, 237, 382, 249, 675, 402, 254, 223, 164, 214, 191, 831, 218, 202, 232, 124, 249, 160, 251, 217, 717, 78, 561, 1627, 256, 386, 225, 432, 499, 394, 364, 445, 634, 667, 177, 346, 470, 663, 142, 588, 414, 617, 1559, 380, 2520, 1040, 417, 289, 238, 220, 214, 303,\n      163, 141, 510, 397, 137, 137, 133, 133, 390, 266, 137, 183, 215, 191, 485, 328, 575, 799, 533, 148, 215, 589, 589, 130, 362, 562, 471, 179, 186, 1266, 1456, 521, 1536, 427, 444, 406, 912, 150, 283, 144, 485, 470, 205, 1268, 796, 658, 306, 3751, 814, 146, 2328, 1226, 922, 237, 206, 198, 250, 283, 60, 3e3],\n      dependencies: {\n        \"Array.prototype.at\": [0, 5, 69, 105, 106, 116, 164],\n        \"Array.prototype.concat\": [0, 16, 21, 22, 26, 34, 40, 76, 78, 155, 165],\n        \"Array.prototype.copyWithin\": [0, 5, 9, 37, 69, 105, 106, 116, 166],\n        \"Array.prototype.every\": [0, 15, 17, 21, 22, 26, 53, 59, 76, 78, 155, 167],\n        \"Array.prototype.fill\": [0, 5, 10, 69, 105, 106, 116, 168],\n        \"Array.prototype.filter\": [0, 15, 16, 21, 22, 26, 53, 59, 76, 78, 155, 169],\n        \"Array.prototype.find\": [0, 5, 15, 21, 22, 26, 53, 59, 69, 76, 78, 105, 106, 116, 155, 173],\n        \"Array.prototype.findIndex\": [0, 5, 15, 21, 22, 26, 53, 59, 69, 76, 78, 105, 106, 116, 155, 170],\n        \"Array.prototype.findLast\": [0, 5, 14, 53, 59, 69, 105, 106, 116, 172],\n        \"Array.prototype.findLastIndex\": [0, 5, 14, 53, 59, 69, 105, 106, 116, 171],\n        \"Array.prototype.flat\": [0, 21, 22, 26, 40, 50, 53, 59, 76, 78, 155, 175],\n        \"Array.prototype.flatMap\": [0, 21, 22, 26, 40, 50, 53, 59, 76, 78, 155, 174],\n        \"Array.prototype.forEach\": [0, 11, 15, 17, 21, 22, 26, 53, 59, 76, 78, 155, 176],\n        \"Array.from\": [0, 12, 23, 24, 26, 34, 53, 59, 62, 63, 75, 78, 88, 155, 177],\n        \"Array.prototype.includes\": [0, 5, 69, 105, 106, 116, 178],\n        \"Array.prototype.indexOf\": [0, 17, 59, 179],\n        \"Array.isArray\": [0, 76, 180],\n        \"Array.prototype.join\": [0, 17, 181],\n        \"Array.prototype.map\": [0, 15, 16, 21, 22, 26, 53, 59, 76, 78, 155, 182],\n        \"Array.of\": [0, 26, 34, 78, 155, 183],\n        \"Array.prototype.slice\": [0, 16, 19, 26, 34, 76, 78, 155, 184],\n        \"Array.prototype.some\": [0, 15, 17, 21, 22, 26, 53, 59, 76, 78, 155, 185],\n        \"Array.prototype.sort\": [0, 17, 19, 20, 26, 37, 42, 43, 46, 155, 156, 186],\n        \"Array.prototype.unshift\": [0, 18, 37, 40, 76, 187],\n        \"Math.acosh\": [0, 97, 188],\n        \"Math.asinh\": [0, 189],\n        \"Math.atanh\": [0, 190],\n        \"Math.cbrt\": [0, 100, 191],\n        \"Math.clz32\": [0, 192],\n        \"Math.cosh\": [0, 93, 193],\n        \"Math.expm1\": [0, 93, 194],\n        \"Math.fround\": [0, 94, 95, 99, 100, 195],\n        \"Math.hypot\": [0, 196],\n        \"Math.imul\": [0, 197],\n        \"Math.log10\": [0, 96, 198],\n        \"Math.log1p\": [0, 97, 199],\n        \"Math.log2\": [0, 98, 200],\n        \"Math.sign\": [0, 100, 201],\n        \"Math.sinh\": [0, 93, 202],\n        \"Math.tanh\": [0, 93, 203],\n        \"Math.trunc\": [0, 204],\n        \"Object.assign\": [0, 104, 116, 205],\n        \"Object.create\": [0, 69, 105, 106, 116, 206],\n        \"Object.entries\": [0, 29, 112, 116, 119, 207],\n        \"Object.freeze\": [0, 8, 19, 51, 73, 109, 113, 208],\n        \"Object.fromEntries\": [0, 26, 34, 53, 59, 62, 63, 75, 87, 88, 155, 209],\n        \"Object.getOwnPropertyDescriptor\": [0, 210],\n        \"Object.getOwnPropertyDescriptors\": [0, 34, 211],\n        \"Object.getPrototypeOf\": [0, 29, 112, 212],\n        \"Object.hasOwn\": [0, 213],\n        \"Object.is\": [0, 134, 217],\n        \"Object.isExtensible\": [0, 8, 113, 214],\n        \"Object.isFrozen\": [0, 8, 215],\n        \"Object.isSealed\": [0, 8, 216],\n        \"Object.keys\": [0, 116, 218],\n        \"Object.preventExtensions\": [0, 8, 19, 51, 73, 109, 113, 219],\n        \"Object.seal\": [0, 8, 19, 51, 73, 109, 113, 220],\n        \"Object.setPrototypeOf\": [0, 4, 58, 83, 118, 221],\n        \"Object.values\": [0, 29, 112, 116, 119, 222],\n        \"Promise.any\": [0, 24, 26, 47, 53, 59, 62, 63, 75, 87, 88, 102, 122, 123, 124, 125, 155, 224],\n        \"Reflect.apply\": [0, 52, 225],\n        \"Reflect.construct\": [0, 3, 19, 26, 52, 55, 69, 78, 105, 106, 116, 155, 226],\n        \"Reflect.deleteProperty\": [0, 227],\n        \"Reflect.get\": [0, 29, 79, 112, 230],\n        \"Reflect.getOwnPropertyDescriptor\": [0, 228],\n        \"Reflect.getPrototypeOf\": [0, 29, 112, 229],\n        \"Reflect.has\": [0, 231],\n        \"Reflect.isExtensible\": [0, 8, 113, 232],\n        \"Reflect.ownKeys\": [0, 233],\n        \"Reflect.preventExtensions\": [0, 51, 234],\n        \"Reflect.setPrototypeOf\": [0, 4, 58, 83, 118, 235],\n        \"String.prototype.codePointAt\": [0, 26, 141, 155, 156, 236],\n        \"String.prototype.endsWith\": [0, 26, 28, 59, 85, 103, 155, 156, 237],\n        \"String.fromCodePoint\": [0, 238],\n        \"String.prototype.includes\": [0, 26, 28, 85, 103, 155, 156, 239],\n        \"String.prototype.matchAll\": [0, 3, 6, 26, 29, 31, 59, 69, 78, 85, 89, 90, 105, 106, 112, 116, 126, 127, 128, 129, 130, 131, 132, 135, 139, 141, 155, 156, 241],\n        \"String.raw\": [0, 26, 155, 156, 242],\n        \"String.prototype.repeat\": [0, 26, 142, 155, 156, 243],\n        \"String.prototype.replaceAll\": [0, 26, 65, 85, 128, 129, 155, 156, 244],\n        \"String.prototype.startsWith\": [0, 26, 28, 59, 85, 103, 155, 156, 245],\n        \"String.prototype.substr\": [0, 26, 155, 156, 246],\n        \"String.prototype.trim\": [0, 26, 144, 146, 155, 156, 163, 251],\n        \"String.prototype.trimEnd\": [0, 26, 143, 144, 146, 155, 156, 163, 247, 249],\n        \"String.prototype.trimStart\": [0, 26, 144, 145, 146, 155, 156, 163, 248, 250],\n        \"String.prototype.link\": [0, 26, 30, 140, 155, 156, 240],\n        \"Promise.allSettled\": [0, 24, 26, 47, 53, 59, 62, 63, 75, 87, 88, 102, 122, 123, 124, 125, 155, 223, 252],\n        \"focus-visible\": [253]\n      },\n      maxSize: 155835\n    };\n    polyfillModuleData = polyfill_module_data_default;\n    graph = polyfill_graph_data_default;\n    CodePatternMatcher = class {\n      static {\n        __name(this, \"CodePatternMatcher\");\n      }\n      /**\n       * @param {Pattern[]} patterns\n       */\n      constructor(patterns) {\n        this.patterns = patterns;\n      }\n      /**\n       * @param {string} code\n       * @return {PatternMatchResult[]}\n       */\n      match(code) {\n        if (!this.re) {\n          const patternsExpression = this.patterns.map((pattern) => `(${pattern.expression})`).join(\"|\");\n          this.re = new RegExp(`(^\\r\n|\\r|\n)|${patternsExpression}`, \"g\");\n        }\n        this.re.lastIndex = 0;\n        const seen = /* @__PURE__ */ new Set();\n        const matches = [];\n        let result;\n        let line = 0;\n        let lineBeginsAtIndex = 0;\n        while ((result = this.re.exec(code)) !== null) {\n          const captureGroups = result.slice(1);\n          const [isNewline, ...patternExpressionMatches] = captureGroups;\n          if (isNewline) {\n            line++;\n            lineBeginsAtIndex = result.index + 1;\n            continue;\n          }\n          const pattern = this.patterns[patternExpressionMatches.findIndex(Boolean)];\n          if (seen.has(pattern)) {\n            continue;\n          }\n          seen.add(pattern);\n          matches.push({\n            name: pattern.name,\n            line,\n            column: result.index - lineBeginsAtIndex\n          });\n        }\n        return matches;\n      }\n    };\n    __name(buildPolyfillExpression, \"buildPolyfillExpression\");\n    __name(getCoreJsPolyfillData, \"getCoreJsPolyfillData\");\n    __name(getPolyfillPatterns, \"getPolyfillPatterns\");\n    __name(getTransformPatterns, \"getTransformPatterns\");\n    __name(estimateWastedBytes, \"estimateWastedBytes\");\n    matcher = new CodePatternMatcher([\n      ...getPolyfillPatterns(),\n      ...getTransformPatterns()\n    ]);\n    __name(detectLegacyJavaScript, \"detectLegacyJavaScript\");\n    /**\n     * @license\n     * Copyright 2025 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n  }\n});\n\n// node_modules/@paulirish/trace_engine/third_party/legacy-javascript/legacy-javascript.js\nvar init_legacy_javascript2 = __esm({\n  \"node_modules/@paulirish/trace_engine/third_party/legacy-javascript/legacy-javascript.js\"() {\n    init_process_global();\n    init_legacy_javascript();\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/insights/LegacyJavaScript.js\nvar LegacyJavaScript_exports = {};\n__export(LegacyJavaScript_exports, {\n  UIStrings: () => UIStrings13,\n  createOverlays: () => createOverlays12,\n  generateInsight: () => generateInsight12,\n  i18nString: () => i18nString12,\n  isLegacyJavaScript: () => isLegacyJavaScript\n});\nfunction finalize42(partialModel) {\n  const requests = [...partialModel.legacyJavaScriptResults.keys()].map((script) => script.request).filter((e) => !!e);\n  return {\n    insightKey: InsightKeys.LEGACY_JAVASCRIPT,\n    strings: UIStrings13,\n    title: i18nString12(UIStrings13.title),\n    description: i18nString12(UIStrings13.description),\n    docs: \"https://developer.chrome.com/docs/performance/insights/legacy-javascript\",\n    category: InsightCategory.ALL,\n    state: requests.length ? \"fail\" : \"pass\",\n    relatedEvents: [...new Set(requests)],\n    ...partialModel\n  };\n}\nfunction isLegacyJavaScript(model2) {\n  return model2.insightKey === InsightKeys.LEGACY_JAVASCRIPT;\n}\nfunction generateInsight12(data31, context) {\n  const scripts = data31.Scripts.scripts.filter((script) => {\n    if (script.frame !== context.frameId) {\n      return false;\n    }\n    if (script.url?.startsWith(\"chrome-extension://\")) {\n      return false;\n    }\n    return Timing_exports3.timestampIsInBounds(context.bounds, script.ts) || script.request && Timing_exports3.eventIsInBounds(script.request, context.bounds);\n  });\n  const legacyJavaScriptResults = /* @__PURE__ */ new Map();\n  const wastedBytesByRequestId = /* @__PURE__ */ new Map();\n  for (const script of scripts) {\n    if (!script.content || script.content.length < BYTE_THRESHOLD) {\n      continue;\n    }\n    const result = detectLegacyJavaScript2(script.content, script.sourceMap);\n    if (result.estimatedByteSavings < BYTE_THRESHOLD) {\n      continue;\n    }\n    const compressionRatio = estimateCompressionRatioForScript(script);\n    const transferSize = Math.round(result.estimatedByteSavings * compressionRatio);\n    result.estimatedByteSavings = transferSize;\n    legacyJavaScriptResults.set(script, result);\n    if (script.request) {\n      const requestId = script.request.args.data.requestId;\n      wastedBytesByRequestId.set(requestId, transferSize);\n    }\n  }\n  const sorted2 = new Map([...legacyJavaScriptResults].sort((a, b) => b[1].estimatedByteSavings - a[1].estimatedByteSavings));\n  return finalize42({\n    legacyJavaScriptResults: sorted2,\n    metricSavings: metricSavingsForWastedBytes(wastedBytesByRequestId, context),\n    wastedBytes: wastedBytesByRequestId.values().reduce((acc, cur) => acc + cur, 0)\n  });\n}\nfunction createOverlays12(model2) {\n  return [...model2.legacyJavaScriptResults.keys()].map((script) => script.request).filter((e) => !!e).map((request) => {\n    return {\n      type: \"ENTRY_OUTLINE\",\n      entry: request,\n      outlineReason: \"ERROR\"\n    };\n  });\n}\nvar detectLegacyJavaScript2, UIStrings13, i18nString12, BYTE_THRESHOLD;\nvar init_LegacyJavaScript = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/insights/LegacyJavaScript.js\"() {\n    init_process_global();\n    init_legacy_javascript2();\n    init_helpers2();\n    init_Common();\n    init_types4();\n    ({ detectLegacyJavaScript: detectLegacyJavaScript2 } = legacy_javascript_exports);\n    UIStrings13 = {\n      /**\n       * @description Title of an insight that identifies polyfills for modern JavaScript features, and recommends their removal.\n       */\n      title: \"Legacy JavaScript\",\n      /**\n       * @description Description of an insight that identifies polyfills for modern JavaScript features, and recommends their removal.\n       */\n      description: \"Polyfills and transforms enable older browsers to use new JavaScript features. However, many aren't necessary for modern browsers. Consider modifying your JavaScript build process to not transpile [Baseline](https://web.dev/articles/baseline-and-polyfills) features, unless you know you must support older browsers. [Learn why most sites can deploy ES6+ code without transpiling](https://developer.chrome.com/docs/performance/insights/legacy-javascript)\",\n      /** Label for a column in a data table; entries will be the individual JavaScript scripts. */\n      columnScript: \"Script\",\n      /** Label for a column in a data table; entries will be the number of wasted bytes (aka the estimated savings in terms of bytes). */\n      columnWastedBytes: \"Wasted bytes\"\n    };\n    i18nString12 = /* @__PURE__ */ __name((i18nId, values) => ({ i18nId, values }), \"i18nString\");\n    BYTE_THRESHOLD = 5e3;\n    __name(finalize42, \"finalize\");\n    __name(isLegacyJavaScript, \"isLegacyJavaScript\");\n    __name(generateInsight12, \"generateInsight\");\n    __name(createOverlays12, \"createOverlays\");\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/insights/ModernHTTP.js\nvar ModernHTTP_exports = {};\n__export(ModernHTTP_exports, {\n  UIStrings: () => UIStrings14,\n  createOverlayForRequest: () => createOverlayForRequest3,\n  createOverlays: () => createOverlays13,\n  determineHttp1Requests: () => determineHttp1Requests,\n  generateInsight: () => generateInsight13,\n  i18nString: () => i18nString13,\n  isModernHTTPInsight: () => isModernHTTPInsight\n});\nfunction isModernHTTPInsight(model2) {\n  return model2.insightKey === InsightKeys.MODERN_HTTP;\n}\nfunction isMultiplexableStaticAsset(request, entityMappings3, firstPartyEntity) {\n  if (!Network_exports.STATIC_RESOURCE_TYPES.has(request.args.data.resourceType)) {\n    return false;\n  }\n  if (request.args.data.decodedBodyLength < 100) {\n    const entity = entityMappings3.entityByEvent.get(request);\n    if (entity) {\n      if (firstPartyEntity?.name === entity.name) {\n        return true;\n      }\n      if (!entity.isUnrecognized) {\n        return false;\n      }\n    }\n  }\n  return true;\n}\nfunction determineHttp1Requests(requests, entityMappings3, firstPartyEntity) {\n  const http1Requests = [];\n  const groupedByOrigin = /* @__PURE__ */ new Map();\n  for (const record of requests) {\n    const url = new URL(record.args.data.url);\n    if (!isMultiplexableStaticAsset(record, entityMappings3, firstPartyEntity)) {\n      continue;\n    }\n    if (Network_exports.isSyntheticNetworkRequestLocalhost(record)) {\n      continue;\n    }\n    const originRequests = MapUtilities_exports.getWithDefault(groupedByOrigin, url.origin, () => []);\n    originRequests.push(record);\n  }\n  const seenURLs = /* @__PURE__ */ new Set();\n  for (const request of requests) {\n    if (seenURLs.has(request.args.data.url)) {\n      continue;\n    }\n    if (request.args.data.fromServiceWorker) {\n      continue;\n    }\n    const isOldHttp = /HTTP\\/[01][.\\d]?/i.test(request.args.data.protocol);\n    if (!isOldHttp) {\n      continue;\n    }\n    const url = new URL(request.args.data.url);\n    const group = groupedByOrigin.get(url.origin) || [];\n    if (group.length < 6) {\n      continue;\n    }\n    seenURLs.add(request.args.data.url);\n    http1Requests.push(request);\n  }\n  return http1Requests;\n}\nfunction computeWasteWithGraph(urlsToChange, graph2, simulator) {\n  const simulationBefore = simulator.simulate(graph2);\n  const originalProtocols = /* @__PURE__ */ new Map();\n  graph2.traverse((node) => {\n    if (node.type !== \"network\") {\n      return;\n    }\n    if (!urlsToChange.has(node.request.url)) {\n      return;\n    }\n    originalProtocols.set(node.request.requestId, node.request.protocol);\n    node.request.protocol = \"h2\";\n  });\n  const simulationAfter = simulator.simulate(graph2);\n  graph2.traverse((node) => {\n    if (node.type !== \"network\") {\n      return;\n    }\n    const originalProtocol = originalProtocols.get(node.request.requestId);\n    if (originalProtocol === void 0) {\n      return;\n    }\n    node.request.protocol = originalProtocol;\n  });\n  const savings = simulationBefore.timeInMs - simulationAfter.timeInMs;\n  return NumberUtilities_exports.floor(savings, 1 / 10);\n}\nfunction computeMetricSavings(http1Requests, context) {\n  if (!context.navigation || !context.lantern) {\n    return;\n  }\n  const urlsToChange = new Set(http1Requests.map((r) => r.args.data.url));\n  const fcpGraph = context.lantern.metrics.firstContentfulPaint.optimisticGraph;\n  const lcpGraph = context.lantern.metrics.largestContentfulPaint.optimisticGraph;\n  return {\n    FCP: computeWasteWithGraph(urlsToChange, fcpGraph, context.lantern.simulator),\n    LCP: computeWasteWithGraph(urlsToChange, lcpGraph, context.lantern.simulator)\n  };\n}\nfunction finalize43(partialModel) {\n  return {\n    insightKey: InsightKeys.MODERN_HTTP,\n    strings: UIStrings14,\n    title: i18nString13(UIStrings14.title),\n    description: i18nString13(UIStrings14.description),\n    docs: \"https://developer.chrome.com/docs/performance/insights/modern-http\",\n    category: InsightCategory.LCP,\n    state: partialModel.http1Requests.length > 0 ? \"fail\" : \"pass\",\n    ...partialModel,\n    relatedEvents: partialModel.http1Requests\n  };\n}\nfunction generateInsight13(data31, context) {\n  const isWithinContext = /* @__PURE__ */ __name((event) => Timing_exports3.eventIsInBounds(event, context.bounds), \"isWithinContext\");\n  const contextRequests = data31.NetworkRequests.byTime.filter(isWithinContext);\n  const entityMappings3 = data31.NetworkRequests.entityMappings;\n  const firstPartyUrl = context.navigation?.args.data?.documentLoaderURL ?? data31.Meta.mainFrameURL;\n  const firstPartyEntity = helpers_exports.getEntityForUrl(firstPartyUrl, entityMappings3);\n  const http1Requests = determineHttp1Requests(contextRequests, entityMappings3, firstPartyEntity ?? null);\n  return finalize43({\n    http1Requests,\n    metricSavings: computeMetricSavings(http1Requests, context)\n  });\n}\nfunction createOverlayForRequest3(request) {\n  return {\n    type: \"ENTRY_OUTLINE\",\n    entry: request,\n    outlineReason: \"ERROR\"\n  };\n}\nfunction createOverlays13(model2) {\n  return model2.http1Requests.map((req) => createOverlayForRequest3(req)) ?? [];\n}\nvar UIStrings14, i18nString13;\nvar init_ModernHTTP = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/insights/ModernHTTP.js\"() {\n    init_process_global();\n    init_platform();\n    init_handlers();\n    init_helpers2();\n    init_types4();\n    UIStrings14 = {\n      /**\n       * @description Title of an insight that recommends using HTTP/2 over HTTP/1.1 because of the performance benefits. \"HTTP\" should not be translated.\n       */\n      title: \"Modern HTTP\",\n      /**\n       * @description Description of an insight that recommends recommends using HTTP/2 over HTTP/1.1 because of the performance benefits. \"HTTP\" should not be translated.\n       */\n      description: \"HTTP/2 and HTTP/3 offer many benefits over HTTP/1.1, such as multiplexing. [Learn more about using modern HTTP](https://developer.chrome.com/docs/performance/insights/modern-http).\",\n      /**\n       * @description Column header for a table where each cell represents a network request.\n       */\n      request: \"Request\",\n      /**\n       * @description Column header for a table where each cell represents the protocol of a network request.\n       */\n      protocol: \"Protocol\",\n      /**\n       * @description Text explaining that there were not requests that were slowed down by using HTTP/1.1. \"HTTP/1.1\" should not be translated.\n       */\n      noOldProtocolRequests: \"No requests used HTTP/1.1, or its current use of HTTP/1.1 does not present a significant optimization opportunity. HTTP/1.1 requests are only flagged if six or more static assets originate from the same origin, and they are not served from a local development environment or a third-party source.\"\n    };\n    i18nString13 = /* @__PURE__ */ __name((i18nId, values) => ({ i18nId, values }), \"i18nString\");\n    __name(isModernHTTPInsight, \"isModernHTTPInsight\");\n    __name(isMultiplexableStaticAsset, \"isMultiplexableStaticAsset\");\n    __name(determineHttp1Requests, \"determineHttp1Requests\");\n    __name(computeWasteWithGraph, \"computeWasteWithGraph\");\n    __name(computeMetricSavings, \"computeMetricSavings\");\n    __name(finalize43, \"finalize\");\n    __name(generateInsight13, \"generateInsight\");\n    __name(createOverlayForRequest3, \"createOverlayForRequest\");\n    __name(createOverlays13, \"createOverlays\");\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/insights/NetworkDependencyTree.js\nvar NetworkDependencyTree_exports = {};\n__export(NetworkDependencyTree_exports, {\n  ParsedURL: () => ParsedURL,\n  TOO_MANY_PRECONNECTS_THRESHOLD: () => TOO_MANY_PRECONNECTS_THRESHOLD,\n  UIStrings: () => UIStrings15,\n  createOverlays: () => createOverlays14,\n  generateInsight: () => generateInsight14,\n  generatePreconnectCandidates: () => generatePreconnectCandidates,\n  generatePreconnectedOrigins: () => generatePreconnectedOrigins,\n  handleLinkResponseHeader: () => handleLinkResponseHeader,\n  i18nString: () => i18nString14,\n  isNetworkDependencyTreeInsight: () => isNetworkDependencyTreeInsight,\n  normalizePath: () => normalizePath,\n  schemeIs: () => schemeIs\n});\nfunction finalize44(partialModel) {\n  return {\n    insightKey: InsightKeys.NETWORK_DEPENDENCY_TREE,\n    strings: UIStrings15,\n    title: i18nString14(UIStrings15.title),\n    description: i18nString14(UIStrings15.description),\n    docs: \"https://developer.chrome.com/docs/performance/insights/network-dependency-tree\",\n    category: InsightCategory.LCP,\n    state: partialModel.fail ? \"fail\" : \"pass\",\n    ...partialModel\n  };\n}\nfunction isCritical(request, context) {\n  if (request.args.data.requestId === context.navigationId) {\n    return true;\n  }\n  if (request.args.data.isLinkPreload) {\n    return false;\n  }\n  const isIframe = request.args.data.resourceType === \"Document\" && request.args.data.frame !== context.frameId;\n  if (nonCriticalResourceTypes.has(request.args.data.resourceType) || isIframe || // Treat any missed images, primarily favicons, as non-critical resources\n  request.args.data.mimeType.startsWith(\"image/\")) {\n    return false;\n  }\n  const initiatorUrl = request.args.data.initiator?.url || Trace_exports.getStackTraceTopCallFrameInEventPayload(request)?.url;\n  if (!initiatorUrl) {\n    return false;\n  }\n  const isBlocking = Network_exports.isSyntheticNetworkRequestEventRenderBlocking(request);\n  const isHighPriority = Network_exports.isSyntheticNetworkRequestHighPriority(request);\n  return isHighPriority || isBlocking;\n}\nfunction findMaxLeafNode(node) {\n  if (node.children.length === 0) {\n    return node;\n  }\n  let maxLeaf = node.children[0];\n  for (const child of node.children) {\n    const leaf = findMaxLeafNode(child);\n    if (leaf.timeFromInitialRequest > maxLeaf.timeFromInitialRequest) {\n      maxLeaf = leaf;\n    }\n  }\n  return maxLeaf;\n}\nfunction sortRecursively(nodes) {\n  for (const node of nodes) {\n    if (node.children.length > 0) {\n      node.children.sort((nodeA, nodeB) => {\n        const leafA = findMaxLeafNode(nodeA);\n        const leafB = findMaxLeafNode(nodeB);\n        return leafB.timeFromInitialRequest - leafA.timeFromInitialRequest;\n      });\n      sortRecursively(node.children);\n    }\n  }\n}\nfunction generateNetworkDependencyTree(context) {\n  const rootNodes = [];\n  const relatedEvents = /* @__PURE__ */ new Map();\n  let maxTime = Timing_exports.Micro(0);\n  let fail = false;\n  let longestChain = [];\n  function addChain(path7) {\n    if (path7.length === 0) {\n      return;\n    }\n    if (path7.length >= 2) {\n      fail = true;\n    }\n    const initialRequest = path7[0];\n    const lastRequest = path7[path7.length - 1];\n    const totalChainTime = Timing_exports.Micro(lastRequest.ts + lastRequest.dur - initialRequest.ts);\n    if (totalChainTime > maxTime) {\n      maxTime = totalChainTime;\n      longestChain = path7;\n    }\n    let currentNodes = rootNodes;\n    for (let depth = 0; depth < path7.length; ++depth) {\n      const request = path7[depth];\n      let found = currentNodes.find((node) => node.request === request);\n      if (!found) {\n        const timeFromInitialRequest = Timing_exports.Micro(request.ts + request.dur - initialRequest.ts);\n        found = {\n          request,\n          timeFromInitialRequest,\n          children: [],\n          relatedRequests: /* @__PURE__ */ new Set()\n        };\n        currentNodes.push(found);\n      }\n      path7.forEach((request2) => found?.relatedRequests.add(request2));\n      relatedEvents.set(request, depth < 2 ? [] : [i18nString14(UIStrings15.warningDescription)]);\n      currentNodes = found.children;\n    }\n  }\n  __name(addChain, \"addChain\");\n  const seenNodes = /* @__PURE__ */ new Set();\n  function getNextNodes(node) {\n    return node.getDependents().filter((n) => n.getDependencies().every((d) => seenNodes.has(d)));\n  }\n  __name(getNextNodes, \"getNextNodes\");\n  context.lantern?.graph.traverse((node, traversalPath) => {\n    seenNodes.add(node);\n    if (node.type !== \"network\") {\n      return;\n    }\n    const networkNode = node;\n    if (!isCritical(networkNode.rawRequest, context)) {\n      return;\n    }\n    const networkPath = traversalPath.filter((node2) => node2.type === \"network\").reverse().map((node2) => node2.rawRequest);\n    if (networkPath.some((request) => !isCritical(request, context))) {\n      return;\n    }\n    if (node.isNonNetworkProtocol) {\n      return;\n    }\n    addChain(networkPath);\n  }, getNextNodes);\n  if (longestChain.length > 0) {\n    let currentNodes = rootNodes;\n    for (const request of longestChain) {\n      const found = currentNodes.find((node) => node.request === request);\n      if (found) {\n        found.isLongest = true;\n        currentNodes = found.children;\n      } else {\n        console.error(\"Some request in the longest chain is not found\");\n      }\n    }\n  }\n  sortRecursively(rootNodes);\n  return {\n    rootNodes,\n    maxTime,\n    fail,\n    relatedEvents\n  };\n}\nfunction getSecurityOrigin(url) {\n  const parsedURL = new ParsedURL(url);\n  return parsedURL.securityOrigin();\n}\nfunction handleLinkResponseHeaderPart(trimmedPart) {\n  if (!trimmedPart) {\n    return null;\n  }\n  const urlStart = trimmedPart.indexOf(\"<\");\n  const urlEnd = trimmedPart.indexOf(\">\");\n  if (urlStart !== 0 || urlEnd === -1 || urlEnd <= urlStart) {\n    return null;\n  }\n  const url = trimmedPart.substring(urlStart + 1, urlEnd).trim();\n  if (!url) {\n    return null;\n  }\n  const paramsString = trimmedPart.substring(urlEnd + 1).trim();\n  if (paramsString) {\n    const params = paramsString.split(\";\");\n    for (const param of params) {\n      const trimmedParam = param.trim();\n      if (!trimmedParam) {\n        continue;\n      }\n      const eqIndex = trimmedParam.indexOf(\"=\");\n      if (eqIndex === -1) {\n        continue;\n      }\n      const paramName = trimmedParam.substring(0, eqIndex).trim().toLowerCase();\n      let paramValue = trimmedParam.substring(eqIndex + 1).trim();\n      if (paramValue.startsWith('\"') && paramValue.endsWith('\"')) {\n        paramValue = paramValue.substring(1, paramValue.length - 1);\n      }\n      if (paramName === \"rel\" && paramValue === \"preconnect\") {\n        return { url, headerText: trimmedPart };\n      }\n    }\n  }\n  return null;\n}\nfunction handleLinkResponseHeader(linkHeaderValue) {\n  if (!linkHeaderValue) {\n    return [];\n  }\n  const preconnectedOrigins = [];\n  for (let i = 0; i < linkHeaderValue.length; ) {\n    const firstUrlEnd = linkHeaderValue.indexOf(\">\", i);\n    if (firstUrlEnd === -1) {\n      break;\n    }\n    const commaIndex = linkHeaderValue.indexOf(\",\", firstUrlEnd);\n    const partEnd = commaIndex !== -1 ? commaIndex : linkHeaderValue.length;\n    const part = linkHeaderValue.substring(i, partEnd);\n    if (partEnd + 1 <= i) {\n      console.warn(\"unexpected infinite loop, bailing\");\n      break;\n    }\n    i = partEnd + 1;\n    const preconnectedOrigin = handleLinkResponseHeaderPart(part.trim());\n    if (preconnectedOrigin) {\n      preconnectedOrigins.push(preconnectedOrigin);\n    }\n  }\n  return preconnectedOrigins;\n}\nfunction generatePreconnectedOrigins(data31, context, contextRequests, preconnectCandidates) {\n  const preconnectedOrigins = [];\n  for (const event of data31.NetworkRequests.linkPreconnectEvents) {\n    preconnectedOrigins.push({\n      node_id: event.args.data.node_id,\n      frame: event.args.data.frame,\n      url: event.args.data.url,\n      // For each origin the page wanted to preconnect to:\n      // - if we found no network requests to that origin at all then we issue a unused warning\n      unused: !contextRequests.some((request) => getSecurityOrigin(event.args.data.url) === getSecurityOrigin(request.args.data.url)),\n      // - else (we found network requests to the same origin) and if some of those network requests is too slow (if\n      //   they are preconnect candidates), then we issue a unused warning with crossorigin hint\n      crossorigin: preconnectCandidates.some((candidate) => candidate.origin === getSecurityOrigin(event.args.data.url)),\n      source: \"DOM\"\n    });\n  }\n  const documentRequest = data31.NetworkRequests.byId.get(context.navigationId);\n  documentRequest?.args.data.responseHeaders?.forEach((header) => {\n    if (header.name.toLowerCase() === \"link\") {\n      const preconnectedOriginsFromResponseHeader = handleLinkResponseHeader(header.value);\n      preconnectedOriginsFromResponseHeader?.forEach((origin) => preconnectedOrigins.push({\n        url: origin.url,\n        headerText: origin.headerText,\n        request: documentRequest,\n        // For each origin the page wanted to preconnect to:\n        // - if we found no network requests to that origin at all then we issue a unused warning\n        unused: !contextRequests.some((request) => getSecurityOrigin(origin.url) === getSecurityOrigin(request.args.data.url)),\n        // - else (we found network requests to the same origin) and if some of those network requests is too slow (if\n        //   they are preconnect candidates), then we issue a unused warning with crossorigin hint\n        crossorigin: preconnectCandidates.some((candidate) => candidate.origin === getSecurityOrigin(origin.url)),\n        source: \"ResponseHeader\"\n      }));\n    }\n  });\n  return preconnectedOrigins;\n}\nfunction hasValidTiming(request) {\n  return !!request.args.data.timing && request.args.data.timing.connectEnd >= 0 && request.args.data.timing.connectStart >= 0;\n}\nfunction hasAlreadyConnectedToOrigin(request) {\n  const { timing } = request.args.data;\n  if (!timing) {\n    return false;\n  }\n  if (timing.dnsStart === -1 && timing.dnsEnd === -1 && timing.connectStart === -1 && timing.connectEnd === -1) {\n    return true;\n  }\n  if (timing.dnsEnd - timing.dnsStart === 0 && timing.connectEnd - timing.connectStart === 0) {\n    return true;\n  }\n  return false;\n}\nfunction socketStartTimeIsBelowThreshold(request, mainResource) {\n  const timeSinceMainEnd = Math.max(0, request.args.data.syntheticData.sendStartTime - mainResource.args.data.syntheticData.finishTime);\n  return Timing_exports3.microToMilli(timeSinceMainEnd) < PRECONNECT_SOCKET_MAX_IDLE_IN_MS;\n}\nfunction candidateRequestsByOrigin(data31, mainResource, contextRequests, lcpGraphURLs) {\n  const origins = /* @__PURE__ */ new Map();\n  contextRequests.forEach((request) => {\n    if (!hasValidTiming(request)) {\n      return;\n    }\n    if (data31.NetworkRequests.eventToInitiator.get(request) === mainResource) {\n      return;\n    }\n    const url = new URL(request.args.data.url);\n    if (url.origin === \"null\") {\n      return;\n    }\n    const mainOrigin = new URL(mainResource.args.data.url).origin;\n    if (url.origin === mainOrigin) {\n      return;\n    }\n    if (!lcpGraphURLs.has(request.args.data.url)) {\n      return;\n    }\n    if (hasAlreadyConnectedToOrigin(request)) {\n      return;\n    }\n    if (!socketStartTimeIsBelowThreshold(request, mainResource)) {\n      return;\n    }\n    const originRequests = MapUtilities_exports.getWithDefault(origins, url.origin, () => []);\n    originRequests.push(request);\n  });\n  return origins;\n}\nfunction generatePreconnectCandidates(data31, context, contextRequests) {\n  if (!context.lantern) {\n    return [];\n  }\n  const documentRequest = data31.NetworkRequests.byId.get(context.navigationId);\n  if (!documentRequest) {\n    return [];\n  }\n  const { rtt, additionalRttByOrigin } = context.lantern.simulator.getOptions();\n  const lcpGraph = context.lantern.metrics.largestContentfulPaint.pessimisticGraph;\n  const fcpGraph = context.lantern.metrics.firstContentfulPaint.pessimisticGraph;\n  const lcpGraphURLs = /* @__PURE__ */ new Set();\n  lcpGraph.traverse((node) => {\n    if (node.type === \"network\") {\n      lcpGraphURLs.add(node.request.url);\n    }\n  });\n  const fcpGraphURLs = /* @__PURE__ */ new Set();\n  fcpGraph.traverse((node) => {\n    if (node.type === \"network\") {\n      fcpGraphURLs.add(node.request.url);\n    }\n  });\n  const groupedOrigins = candidateRequestsByOrigin(data31, documentRequest, contextRequests, lcpGraphURLs);\n  let maxWastedLcp = Timing_exports.Milli(0);\n  let maxWastedFcp = Timing_exports.Milli(0);\n  let preconnectCandidates = [];\n  groupedOrigins.forEach((requests) => {\n    const firstRequestOfOrigin = requests[0];\n    if (!firstRequestOfOrigin.args.data.timing) {\n      return;\n    }\n    const firstRequestOfOriginParsedURL = new ParsedURL(firstRequestOfOrigin.args.data.url);\n    const origin = firstRequestOfOriginParsedURL.securityOrigin();\n    const additionalRtt = additionalRttByOrigin.get(origin) ?? 0;\n    let connectionTime = Timing_exports.Milli(rtt + additionalRtt);\n    if (firstRequestOfOriginParsedURL.scheme === \"https\") {\n      connectionTime = Timing_exports.Milli(connectionTime * 2);\n    }\n    const timeBetweenMainResourceAndDnsStart = Timing_exports.Micro(firstRequestOfOrigin.args.data.syntheticData.sendStartTime - documentRequest.args.data.syntheticData.finishTime + Timing_exports3.milliToMicro(firstRequestOfOrigin.args.data.timing.dnsStart));\n    const wastedMs = Math.min(connectionTime, Timing_exports3.microToMilli(timeBetweenMainResourceAndDnsStart));\n    if (wastedMs < IGNORE_THRESHOLD_IN_MILLISECONDS) {\n      return;\n    }\n    maxWastedLcp = Math.max(wastedMs, maxWastedLcp);\n    if (fcpGraphURLs.has(firstRequestOfOrigin.args.data.url)) {\n      maxWastedFcp = Math.max(wastedMs, maxWastedFcp);\n    }\n    preconnectCandidates.push({\n      origin,\n      wastedMs\n    });\n  });\n  preconnectCandidates = preconnectCandidates.sort((a, b) => b.wastedMs - a.wastedMs);\n  return preconnectCandidates.slice(0, TOO_MANY_PRECONNECTS_THRESHOLD);\n}\nfunction isNetworkDependencyTreeInsight(model2) {\n  return model2.insightKey === InsightKeys.NETWORK_DEPENDENCY_TREE;\n}\nfunction generateInsight14(data31, context) {\n  if (!context.navigation) {\n    return finalize44({\n      rootNodes: [],\n      maxTime: 0,\n      fail: false,\n      preconnectedOrigins: [],\n      preconnectCandidates: []\n    });\n  }\n  const { rootNodes, maxTime, fail, relatedEvents } = generateNetworkDependencyTree(context);\n  const isWithinContext = /* @__PURE__ */ __name((event) => Timing_exports3.eventIsInBounds(event, context.bounds), \"isWithinContext\");\n  const contextRequests = data31.NetworkRequests.byTime.filter(isWithinContext);\n  const preconnectCandidates = generatePreconnectCandidates(data31, context, contextRequests);\n  const preconnectedOrigins = generatePreconnectedOrigins(data31, context, contextRequests, preconnectCandidates);\n  return finalize44({\n    rootNodes,\n    maxTime,\n    fail,\n    relatedEvents,\n    preconnectedOrigins,\n    preconnectCandidates\n  });\n}\nfunction createOverlays14(model2) {\n  function walk(nodes, overlays2) {\n    nodes.forEach((node) => {\n      overlays2.push({\n        type: \"ENTRY_OUTLINE\",\n        entry: node.request,\n        outlineReason: \"ERROR\"\n      });\n      walk(node.children, overlays2);\n    });\n  }\n  __name(walk, \"walk\");\n  const overlays = [];\n  walk(model2.rootNodes, overlays);\n  return overlays;\n}\nfunction normalizePath(path7) {\n  if (path7.indexOf(\"..\") === -1 && path7.indexOf(\".\") === -1) {\n    return path7;\n  }\n  const segments = (path7[0] === \"/\" ? path7.substring(1) : path7).split(\"/\");\n  const normalizedSegments = [];\n  for (const segment of segments) {\n    if (segment === \".\") {\n      continue;\n    } else if (segment === \"..\") {\n      normalizedSegments.pop();\n    } else {\n      normalizedSegments.push(segment);\n    }\n  }\n  let normalizedPath = normalizedSegments.join(\"/\");\n  if (path7[0] === \"/\" && normalizedPath) {\n    normalizedPath = \"/\" + normalizedPath;\n  }\n  if (normalizedPath[normalizedPath.length - 1] !== \"/\" && (path7[path7.length - 1] === \"/\" || segments[segments.length - 1] === \".\" || segments[segments.length - 1] === \"..\")) {\n    normalizedPath = normalizedPath + \"/\";\n  }\n  return normalizedPath;\n}\nfunction schemeIs(url, scheme) {\n  try {\n    return new URL(url).protocol === scheme;\n  } catch {\n    return false;\n  }\n}\nvar UIStrings15, i18nString14, nonCriticalResourceTypes, PRECONNECT_SOCKET_MAX_IDLE_IN_MS, IGNORE_THRESHOLD_IN_MILLISECONDS, TOO_MANY_PRECONNECTS_THRESHOLD, ParsedURL;\nvar init_NetworkDependencyTree = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/insights/NetworkDependencyTree.js\"() {\n    init_process_global();\n    init_platform();\n    init_helpers2();\n    init_types2();\n    init_types4();\n    UIStrings15 = {\n      /**\n       * @description Title of an insight that recommends avoiding chaining critical requests.\n       */\n      title: \"Network dependency tree\",\n      /**\n       * @description Description of an insight that recommends avoiding chaining critical requests.\n       */\n      description: \"[Avoid chaining critical requests](https://developer.chrome.com/docs/performance/insights/network-dependency-tree) by reducing the length of chains, reducing the download size of resources, or deferring the download of unnecessary resources to improve page load.\",\n      /**\n       * @description Description of the warning that recommends avoiding chaining critical requests.\n       */\n      warningDescription: \"Avoid chaining critical requests by reducing the length of chains, reducing the download size of resources, or deferring the download of unnecessary resources to improve page load.\",\n      /**\n       * @description Text status indicating that there isn't long chaining critical network requests.\n       */\n      noNetworkDependencyTree: \"No rendering tasks impacted by network dependencies\",\n      /**\n       * @description Text for the maximum critical path latency. This refers to the longest chain of network requests that\n       * the browser must download before it can render the page.\n       */\n      maxCriticalPathLatency: \"Max critical path latency:\",\n      /** Label for a column in a data table; entries will be the network request */\n      columnRequest: \"Request\",\n      /** Label for a column in a data table; entries will be the time from main document till current network request. */\n      columnTime: \"Time\",\n      /**\n       * @description Title of the table of the detected preconnect origins.\n       */\n      preconnectOriginsTableTitle: \"Preconnected origins\",\n      /**\n       * @description Description of the table of the detected preconnect origins.\n       */\n      preconnectOriginsTableDescription: \"[preconnect](https://developer.chrome.com/docs/lighthouse/performance/uses-rel-preconnect/) hints help the browser establish a connection earlier in the page load, saving time when the first request for that origin is made. The following are the origins that the page preconnected to.\",\n      /**\n       * @description Text status indicating that there isn't any preconnected origins.\n       */\n      noPreconnectOrigins: \"no origins were preconnected\",\n      /**\n       * @description A warning message that is shown when found more than 4 preconnected links. \"preconnect\" should not be translated.\n       */\n      tooManyPreconnectLinksWarning: \"More than 4 `preconnect` connections were found. These should be used sparingly and only to the most important origins.\",\n      /**\n       * @description A warning message that is shown when the user added preconnect for some unnecessary origins. \"preconnect\" should not be translated.\n       */\n      unusedWarning: \"Unused preconnect. Only use `preconnect` for origins that the page is likely to request.\",\n      /**\n       * @description A warning message that is shown when the user forget to set the `crossorigin` HTML attribute, or setting it to an incorrect value, on the link is a common mistake when adding preconnect links. \"preconnect\" should not be translated.\n       * */\n      crossoriginWarning: \"Unused preconnect. Check that the `crossorigin` attribute is used properly.\",\n      /**\n       * @description Label for a column in a data table; entries will be the source of the origin.\n       */\n      columnSource: \"Source\",\n      /**\n       * @description Text status indicating that there isn't preconnect candidates.\n       */\n      noPreconnectCandidates: \"No additional origins are good candidates for preconnecting\",\n      /**\n       * @description Title of the table that shows the origins that the page should have preconnected to.\n       */\n      estSavingTableTitle: \"Preconnect candidates\",\n      /**\n       * @description Description of the table that recommends preconnecting to the origins to save time. \"preconnect\" should not be translated.\n       */\n      estSavingTableDescription: \"Add [preconnect](https://developer.chrome.com/docs/lighthouse/performance/uses-rel-preconnect/) hints to your most important origins, but try to use no more than 4.\",\n      /**\n       * @description Label for a column in a data table; entries will be the origin of a web resource\n       */\n      columnOrigin: \"Origin\",\n      /**\n       * @description Label for a column in a data table; entries will be the number of milliseconds the user could reduce page load by if they implemented the suggestions.\n       */\n      columnWastedMs: \"Est LCP savings\"\n    };\n    i18nString14 = /* @__PURE__ */ __name((i18nId, values) => ({ i18nId, values }), \"i18nString\");\n    nonCriticalResourceTypes = /* @__PURE__ */ new Set([\n      \"Image\",\n      \"XHR\",\n      \"Fetch\",\n      \"EventSource\"\n    ]);\n    PRECONNECT_SOCKET_MAX_IDLE_IN_MS = Timing_exports.Milli(15e3);\n    IGNORE_THRESHOLD_IN_MILLISECONDS = Timing_exports.Milli(50);\n    TOO_MANY_PRECONNECTS_THRESHOLD = 4;\n    __name(finalize44, \"finalize\");\n    __name(isCritical, \"isCritical\");\n    __name(findMaxLeafNode, \"findMaxLeafNode\");\n    __name(sortRecursively, \"sortRecursively\");\n    __name(generateNetworkDependencyTree, \"generateNetworkDependencyTree\");\n    __name(getSecurityOrigin, \"getSecurityOrigin\");\n    __name(handleLinkResponseHeaderPart, \"handleLinkResponseHeaderPart\");\n    __name(handleLinkResponseHeader, \"handleLinkResponseHeader\");\n    __name(generatePreconnectedOrigins, \"generatePreconnectedOrigins\");\n    __name(hasValidTiming, \"hasValidTiming\");\n    __name(hasAlreadyConnectedToOrigin, \"hasAlreadyConnectedToOrigin\");\n    __name(socketStartTimeIsBelowThreshold, \"socketStartTimeIsBelowThreshold\");\n    __name(candidateRequestsByOrigin, \"candidateRequestsByOrigin\");\n    __name(generatePreconnectCandidates, \"generatePreconnectCandidates\");\n    __name(isNetworkDependencyTreeInsight, \"isNetworkDependencyTreeInsight\");\n    __name(generateInsight14, \"generateInsight\");\n    __name(createOverlays14, \"createOverlays\");\n    __name(normalizePath, \"normalizePath\");\n    __name(schemeIs, \"schemeIs\");\n    ParsedURL = class _ParsedURL {\n      static {\n        __name(this, \"ParsedURL\");\n      }\n      isValid;\n      url;\n      scheme;\n      user;\n      host;\n      port;\n      path;\n      queryParams;\n      fragment;\n      folderPathComponents;\n      lastPathComponent;\n      blobInnerScheme;\n      constructor(url) {\n        this.isValid = false;\n        this.url = url;\n        this.scheme = \"\";\n        this.user = \"\";\n        this.host = \"\";\n        this.port = \"\";\n        this.path = \"\";\n        this.queryParams = \"\";\n        this.fragment = \"\";\n        this.folderPathComponents = \"\";\n        this.lastPathComponent = \"\";\n        const isBlobUrl = this.url.startsWith(\"blob:\");\n        const urlToMatch = isBlobUrl ? url.substring(5) : url;\n        const match = urlToMatch.match(_ParsedURL.urlRegex());\n        if (match) {\n          this.isValid = true;\n          if (isBlobUrl) {\n            this.blobInnerScheme = match[2].toLowerCase();\n            this.scheme = \"blob\";\n          } else {\n            this.scheme = match[2].toLowerCase();\n          }\n          this.user = match[3] ?? \"\";\n          this.host = match[4] ?? \"\";\n          this.port = match[5] ?? \"\";\n          this.path = match[6] ?? \"/\";\n          this.queryParams = match[7] ?? \"\";\n          this.fragment = match[8] ?? \"\";\n        } else {\n          if (this.url.startsWith(\"data:\")) {\n            this.scheme = \"data\";\n            return;\n          }\n          if (this.url.startsWith(\"blob:\")) {\n            this.scheme = \"blob\";\n            return;\n          }\n          if (this.url === \"about:blank\") {\n            this.scheme = \"about\";\n            return;\n          }\n          this.path = this.url;\n        }\n        const lastSlashExceptTrailingIndex = this.path.lastIndexOf(\"/\", this.path.length - 2);\n        if (lastSlashExceptTrailingIndex !== -1) {\n          this.lastPathComponent = this.path.substring(lastSlashExceptTrailingIndex + 1);\n        } else {\n          this.lastPathComponent = this.path;\n        }\n        const lastSlashIndex = this.path.lastIndexOf(\"/\");\n        if (lastSlashIndex !== -1) {\n          this.folderPathComponents = this.path.substring(0, lastSlashIndex);\n        }\n      }\n      static fromString(string) {\n        const parsedURL = new _ParsedURL(string.toString());\n        if (parsedURL.isValid) {\n          return parsedURL;\n        }\n        return null;\n      }\n      static preEncodeSpecialCharactersInPath(path7) {\n        for (const specialChar of [\"%\", \";\", \"#\", \"?\", \" \"]) {\n          path7 = path7.replaceAll(specialChar, encodeURIComponent(specialChar));\n        }\n        return path7;\n      }\n      static rawPathToEncodedPathString(path7) {\n        const partiallyEncoded = _ParsedURL.preEncodeSpecialCharactersInPath(path7);\n        if (path7.startsWith(\"/\")) {\n          return new URL(partiallyEncoded, \"file:///\").pathname;\n        }\n        return new URL(\"/\" + partiallyEncoded, \"file:///\").pathname.substr(1);\n      }\n      /**\n       * @param name Must not be encoded\n       */\n      static encodedFromParentPathAndName(parentPath, name) {\n        return _ParsedURL.concatenate(parentPath, \"/\", _ParsedURL.preEncodeSpecialCharactersInPath(name));\n      }\n      /**\n       * @param name Must not be encoded\n       */\n      static urlFromParentUrlAndName(parentUrl, name) {\n        return _ParsedURL.concatenate(parentUrl, \"/\", _ParsedURL.preEncodeSpecialCharactersInPath(name));\n      }\n      static encodedPathToRawPathString(encPath) {\n        return decodeURIComponent(encPath);\n      }\n      static rawPathToUrlString(fileSystemPath) {\n        let preEncodedPath = _ParsedURL.preEncodeSpecialCharactersInPath(fileSystemPath.replace(/\\\\/g, \"/\"));\n        preEncodedPath = preEncodedPath.replace(/\\\\/g, \"/\");\n        if (!preEncodedPath.startsWith(\"file://\")) {\n          if (preEncodedPath.startsWith(\"/\")) {\n            preEncodedPath = \"file://\" + preEncodedPath;\n          } else {\n            preEncodedPath = \"file:///\" + preEncodedPath;\n          }\n        }\n        return new URL(preEncodedPath).toString();\n      }\n      static relativePathToUrlString(relativePath, baseURL) {\n        const preEncodedPath = _ParsedURL.preEncodeSpecialCharactersInPath(relativePath.replace(/\\\\/g, \"/\"));\n        return new URL(preEncodedPath, baseURL).toString();\n      }\n      static urlToRawPathString(fileURL, isWindows2) {\n        console.assert(fileURL.startsWith(\"file://\"), \"This must be a file URL.\");\n        const decodedFileURL = decodeURIComponent(fileURL);\n        if (isWindows2) {\n          return decodedFileURL.substr(\"file:///\".length).replace(/\\//g, \"\\\\\");\n        }\n        return decodedFileURL.substr(\"file://\".length);\n      }\n      static sliceUrlToEncodedPathString(url, start) {\n        return url.substring(start);\n      }\n      static substr(devToolsPath, from, length) {\n        return devToolsPath.substr(from, length);\n      }\n      static substring(devToolsPath, start, end) {\n        return devToolsPath.substring(start, end);\n      }\n      static prepend(prefix, devToolsPath) {\n        return prefix + devToolsPath;\n      }\n      static concatenate(devToolsPath, ...appendage) {\n        return devToolsPath.concat(...appendage);\n      }\n      static trim(devToolsPath) {\n        return devToolsPath.trim();\n      }\n      static slice(devToolsPath, start, end) {\n        return devToolsPath.slice(start, end);\n      }\n      static join(devToolsPaths, separator) {\n        return devToolsPaths.join(separator);\n      }\n      static split(devToolsPath, separator, limit) {\n        return devToolsPath.split(separator, limit);\n      }\n      static toLowerCase(devToolsPath) {\n        return devToolsPath.toLowerCase();\n      }\n      static isValidUrlString(str) {\n        return new _ParsedURL(str).isValid;\n      }\n      static urlWithoutHash(url) {\n        const hashIndex = url.indexOf(\"#\");\n        if (hashIndex !== -1) {\n          return url.substr(0, hashIndex);\n        }\n        return url;\n      }\n      static urlRegex() {\n        if (_ParsedURL.urlRegexInstance) {\n          return _ParsedURL.urlRegexInstance;\n        }\n        const schemeRegex = /([A-Za-z][A-Za-z0-9+.-]*):\\/\\//;\n        const userRegex = /(?:([A-Za-z0-9\\-._~%!$&'()*+,;=:]*)@)?/;\n        const hostRegex = /((?:\\[::\\d?\\])|(?:[^\\s\\/:]*))/;\n        const portRegex = /(?::([\\d]+))?/;\n        const pathRegex = /(\\/[^#?]*)?/;\n        const queryRegex = /(?:\\?([^#]*))?/;\n        const fragmentRegex = /(?:#(.*))?/;\n        _ParsedURL.urlRegexInstance = new RegExp(\"^(\" + schemeRegex.source + userRegex.source + hostRegex.source + portRegex.source + \")\" + pathRegex.source + queryRegex.source + fragmentRegex.source + \"$\");\n        return _ParsedURL.urlRegexInstance;\n      }\n      static extractPath(url) {\n        const parsedURL = this.fromString(url);\n        return parsedURL ? parsedURL.path : \"\";\n      }\n      static extractOrigin(url) {\n        const parsedURL = this.fromString(url);\n        return parsedURL ? parsedURL.securityOrigin() : \"\";\n      }\n      static extractExtension(url) {\n        url = _ParsedURL.urlWithoutHash(url);\n        const indexOfQuestionMark = url.indexOf(\"?\");\n        if (indexOfQuestionMark !== -1) {\n          url = url.substr(0, indexOfQuestionMark);\n        }\n        const lastIndexOfSlash = url.lastIndexOf(\"/\");\n        if (lastIndexOfSlash !== -1) {\n          url = url.substr(lastIndexOfSlash + 1);\n        }\n        const lastIndexOfDot = url.lastIndexOf(\".\");\n        if (lastIndexOfDot !== -1) {\n          url = url.substr(lastIndexOfDot + 1);\n          const lastIndexOfPercent = url.indexOf(\"%\");\n          if (lastIndexOfPercent !== -1) {\n            return url.substr(0, lastIndexOfPercent);\n          }\n          return url;\n        }\n        return \"\";\n      }\n      static extractName(url) {\n        let index = url.lastIndexOf(\"/\");\n        const pathAndQuery = index !== -1 ? url.substr(index + 1) : url;\n        index = pathAndQuery.indexOf(\"?\");\n        return index < 0 ? pathAndQuery : pathAndQuery.substr(0, index);\n      }\n      static completeURL(baseURL, href) {\n        if (href.startsWith(\"data:\") || href.startsWith(\"blob:\") || href.startsWith(\"javascript:\") || href.startsWith(\"mailto:\")) {\n          return href;\n        }\n        const trimmedHref = href.trim();\n        const parsedHref = this.fromString(trimmedHref);\n        if (parsedHref?.scheme) {\n          const securityOrigin2 = parsedHref.securityOrigin();\n          const pathText2 = normalizePath(parsedHref.path);\n          const queryText2 = parsedHref.queryParams && `?${parsedHref.queryParams}`;\n          const fragmentText = parsedHref.fragment && `#${parsedHref.fragment}`;\n          return securityOrigin2 + pathText2 + queryText2 + fragmentText;\n        }\n        const parsedURL = this.fromString(baseURL);\n        if (!parsedURL) {\n          return null;\n        }\n        if (parsedURL.isDataURL()) {\n          return href;\n        }\n        if (href.length > 1 && href.charAt(0) === \"/\" && href.charAt(1) === \"/\") {\n          return parsedURL.scheme + \":\" + href;\n        }\n        const securityOrigin = parsedURL.securityOrigin();\n        const pathText = parsedURL.path;\n        const queryText = parsedURL.queryParams ? \"?\" + parsedURL.queryParams : \"\";\n        if (!href.length) {\n          return securityOrigin + pathText + queryText;\n        }\n        if (href.charAt(0) === \"#\") {\n          return securityOrigin + pathText + queryText + href;\n        }\n        if (href.charAt(0) === \"?\") {\n          return securityOrigin + pathText + href;\n        }\n        const hrefMatches = href.match(/^[^#?]*/);\n        if (!hrefMatches || !href.length) {\n          throw new Error(\"Invalid href\");\n        }\n        let hrefPath = hrefMatches[0];\n        const hrefSuffix = href.substring(hrefPath.length);\n        if (hrefPath.charAt(0) !== \"/\") {\n          hrefPath = parsedURL.folderPathComponents + \"/\" + hrefPath;\n        }\n        return securityOrigin + normalizePath(hrefPath) + hrefSuffix;\n      }\n      static splitLineAndColumn(string) {\n        const beforePathMatch = string.match(_ParsedURL.urlRegex());\n        let beforePath = \"\";\n        let pathAndAfter = string;\n        if (beforePathMatch) {\n          beforePath = beforePathMatch[1];\n          pathAndAfter = string.substring(beforePathMatch[1].length);\n        }\n        const lineColumnRegEx = /(?::(\\d+))?(?::(\\d+))?$/;\n        const lineColumnMatch = lineColumnRegEx.exec(pathAndAfter);\n        let lineNumber;\n        let columnNumber;\n        console.assert(Boolean(lineColumnMatch));\n        if (!lineColumnMatch) {\n          return { url: string, lineNumber: 0, columnNumber: 0 };\n        }\n        if (typeof lineColumnMatch[1] === \"string\") {\n          lineNumber = parseInt(lineColumnMatch[1], 10);\n          lineNumber = isNaN(lineNumber) ? void 0 : lineNumber - 1;\n        }\n        if (typeof lineColumnMatch[2] === \"string\") {\n          columnNumber = parseInt(lineColumnMatch[2], 10);\n          columnNumber = isNaN(columnNumber) ? void 0 : columnNumber - 1;\n        }\n        let url = beforePath + pathAndAfter.substring(0, pathAndAfter.length - lineColumnMatch[0].length);\n        if (lineColumnMatch[1] === void 0 && lineColumnMatch[2] === void 0) {\n          const wasmCodeOffsetRegex = /wasm-function\\[\\d+\\]:0x([a-z0-9]+)$/g;\n          const wasmCodeOffsetMatch = wasmCodeOffsetRegex.exec(pathAndAfter);\n          if (wasmCodeOffsetMatch && typeof wasmCodeOffsetMatch[1] === \"string\") {\n            url = _ParsedURL.removeWasmFunctionInfoFromURL(url);\n            columnNumber = parseInt(wasmCodeOffsetMatch[1], 16);\n            columnNumber = isNaN(columnNumber) ? void 0 : columnNumber;\n          }\n        }\n        return { url, lineNumber, columnNumber };\n      }\n      static removeWasmFunctionInfoFromURL(url) {\n        const wasmFunctionRegEx = /:wasm-function\\[\\d+\\]/;\n        const wasmFunctionIndex = url.search(wasmFunctionRegEx);\n        if (wasmFunctionIndex === -1) {\n          return url;\n        }\n        return _ParsedURL.substring(url, 0, wasmFunctionIndex);\n      }\n      static beginsWithWindowsDriveLetter(url) {\n        return /^[A-Za-z]:/.test(url);\n      }\n      static beginsWithScheme(url) {\n        return /^[A-Za-z][A-Za-z0-9+.-]*:/.test(url);\n      }\n      static isRelativeURL(url) {\n        return !this.beginsWithScheme(url) || this.beginsWithWindowsDriveLetter(url);\n      }\n      isAboutBlank() {\n        return this.url === \"about:blank\";\n      }\n      isDataURL() {\n        return this.scheme === \"data\";\n      }\n      extractDataUrlMimeType() {\n        const regexp = /^data:((?<type>\\w+)\\/(?<subtype>\\w+))?(;base64)?,/;\n        const match = this.url.match(regexp);\n        return {\n          type: match?.groups?.type,\n          subtype: match?.groups?.subtype\n        };\n      }\n      isBlobURL() {\n        return this.url.startsWith(\"blob:\");\n      }\n      lastPathComponentWithFragment() {\n        return this.lastPathComponent + (this.fragment ? \"#\" + this.fragment : \"\");\n      }\n      domain() {\n        if (this.isDataURL()) {\n          return \"data:\";\n        }\n        return this.host + (this.port ? \":\" + this.port : \"\");\n      }\n      securityOrigin() {\n        if (this.isDataURL()) {\n          return \"data:\";\n        }\n        const scheme = this.isBlobURL() ? this.blobInnerScheme : this.scheme;\n        return scheme + \"://\" + this.domain();\n      }\n      urlWithoutScheme() {\n        if (this.scheme && this.url.startsWith(this.scheme + \"://\")) {\n          return this.url.substring(this.scheme.length + 3);\n        }\n        return this.url;\n      }\n      static urlRegexInstance = null;\n    };\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/insights/RenderBlocking.js\nvar RenderBlocking_exports = {};\n__export(RenderBlocking_exports, {\n  UIStrings: () => UIStrings16,\n  createOverlayForRequest: () => createOverlayForRequest4,\n  createOverlays: () => createOverlays15,\n  generateInsight: () => generateInsight15,\n  i18nString: () => i18nString15,\n  isRenderBlockingInsight: () => isRenderBlockingInsight\n});\nfunction isRenderBlockingInsight(insight) {\n  return insight.insightKey === \"RenderBlocking\";\n}\nfunction getNodesAndTimingByRequestId(nodeTimings) {\n  const requestIdToNode = /* @__PURE__ */ new Map();\n  for (const [node, nodeTiming] of nodeTimings) {\n    if (node.type !== \"network\") {\n      continue;\n    }\n    requestIdToNode.set(node.request.requestId, { node, nodeTiming });\n  }\n  return requestIdToNode;\n}\nfunction estimateSavingsWithGraphs2(deferredIds, lanternContext) {\n  const simulator = lanternContext.simulator;\n  const fcpGraph = lanternContext.metrics.firstContentfulPaint.optimisticGraph;\n  const { nodeTimings } = lanternContext.simulator.simulate(fcpGraph);\n  const adjustedNodeTimings = new Map(nodeTimings);\n  const totalChildNetworkBytes = 0;\n  const minimalFCPGraph = fcpGraph.cloneWithRelationships((node) => {\n    const canDeferRequest = deferredIds.has(node.id);\n    return !canDeferRequest;\n  });\n  if (minimalFCPGraph.type !== \"network\") {\n    throw new Error(\"minimalFCPGraph not a NetworkNode\");\n  }\n  const estimateBeforeInline = Math.max(...Array.from(Array.from(adjustedNodeTimings).map((timing) => timing[1].endTime)));\n  const originalTransferSize = minimalFCPGraph.request.transferSize;\n  const safeTransferSize = originalTransferSize || 0;\n  minimalFCPGraph.request.transferSize = safeTransferSize + totalChildNetworkBytes;\n  const estimateAfterInline = simulator.simulate(minimalFCPGraph).timeInMs;\n  minimalFCPGraph.request.transferSize = originalTransferSize;\n  return Math.round(Math.max(estimateBeforeInline - estimateAfterInline, 0));\n}\nfunction hasImageLCP(data31, context) {\n  return data31.LargestImagePaint.lcpRequestByNavigationId.has(context.navigationId);\n}\nfunction computeSavings(data31, context, renderBlockingRequests) {\n  if (!context.lantern) {\n    return;\n  }\n  const nodesAndTimingsByRequestId = getNodesAndTimingByRequestId(context.lantern.metrics.firstContentfulPaint.optimisticEstimate.nodeTimings);\n  const metricSavings = { FCP: 0, LCP: 0 };\n  const requestIdToWastedMs = /* @__PURE__ */ new Map();\n  const deferredNodeIds = /* @__PURE__ */ new Set();\n  for (const request of renderBlockingRequests) {\n    const nodeAndTiming = nodesAndTimingsByRequestId.get(request.args.data.requestId);\n    if (!nodeAndTiming) {\n      continue;\n    }\n    const { node, nodeTiming } = nodeAndTiming;\n    node.traverse((node2) => deferredNodeIds.add(node2.id));\n    const wastedMs = Math.round(nodeTiming.duration);\n    if (wastedMs < MINIMUM_WASTED_MS) {\n      continue;\n    }\n    requestIdToWastedMs.set(node.id, wastedMs);\n  }\n  if (requestIdToWastedMs.size) {\n    metricSavings.FCP = estimateSavingsWithGraphs2(deferredNodeIds, context.lantern);\n    if (!hasImageLCP(data31, context)) {\n      metricSavings.LCP = metricSavings.FCP;\n    }\n  }\n  return { metricSavings, requestIdToWastedMs };\n}\nfunction finalize45(partialModel) {\n  return {\n    insightKey: InsightKeys.RENDER_BLOCKING,\n    strings: UIStrings16,\n    title: i18nString15(UIStrings16.title),\n    description: i18nString15(UIStrings16.description),\n    docs: \"https://developer.chrome.com/docs/performance/insights/render-blocking\",\n    category: InsightCategory.LCP,\n    state: partialModel.renderBlockingRequests.length > 0 ? \"fail\" : \"pass\",\n    ...partialModel\n  };\n}\nfunction generateInsight15(data31, context) {\n  if (!context.navigation) {\n    return finalize45({\n      renderBlockingRequests: []\n    });\n  }\n  const firstPaintTs = data31.PageLoadMetrics.metricScoresByFrameId.get(context.frameId)?.get(context.navigationId)?.get(ModelHandlers_exports.PageLoadMetrics.MetricName.FP)?.event?.ts;\n  if (!firstPaintTs) {\n    return finalize45({\n      renderBlockingRequests: [],\n      warnings: [InsightWarning.NO_FP]\n    });\n  }\n  let renderBlockingRequests = [];\n  for (const req of data31.NetworkRequests.byTime) {\n    if (req.args.data.frame !== context.frameId) {\n      continue;\n    }\n    if (!Network_exports.isSyntheticNetworkRequestEventRenderBlocking(req)) {\n      continue;\n    }\n    if (req.args.data.syntheticData.finishTime > firstPaintTs) {\n      continue;\n    }\n    if (req.args.data.renderBlocking === \"in_body_parser_blocking\") {\n      const priority = req.args.data.priority;\n      const isScript = req.args.data.resourceType === \"Script\";\n      const isBlockingScript = isScript && priority === \"High\";\n      if (priority !== \"VeryHigh\" && !isBlockingScript) {\n        continue;\n      }\n    }\n    const navigation2 = Trace_exports.getNavigationForTraceEvent(req, context.frameId, data31.Meta.navigationsByFrameId);\n    if (navigation2 === context.navigation) {\n      renderBlockingRequests.push(req);\n    }\n  }\n  const savings = computeSavings(data31, context, renderBlockingRequests);\n  renderBlockingRequests = renderBlockingRequests.sort((a, b) => {\n    return b.dur - a.dur;\n  });\n  return finalize45({\n    relatedEvents: renderBlockingRequests,\n    renderBlockingRequests,\n    ...savings\n  });\n}\nfunction createOverlayForRequest4(request) {\n  return {\n    type: \"ENTRY_OUTLINE\",\n    entry: request,\n    outlineReason: \"ERROR\"\n  };\n}\nfunction createOverlays15(model2) {\n  return model2.renderBlockingRequests.map((request) => createOverlayForRequest4(request));\n}\nvar UIStrings16, i18nString15, MINIMUM_WASTED_MS;\nvar init_RenderBlocking = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/insights/RenderBlocking.js\"() {\n    init_process_global();\n    init_handlers();\n    init_helpers2();\n    init_types4();\n    UIStrings16 = {\n      /**\n       * @description Title of an insight that provides the user with the list of network requests that blocked and therefore slowed down the page rendering and becoming visible to the user.\n       */\n      title: \"Render blocking requests\",\n      /**\n       * @description Text to describe that there are requests blocking rendering, which may affect LCP.\n       */\n      description: \"Requests are blocking the page's initial render, which may delay LCP. [Deferring or inlining](https://developer.chrome.com/docs/performance/insights/render-blocking) can move these network requests out of the critical path.\",\n      /**\n       * @description Label to describe a network request (that happens to be render-blocking).\n       */\n      renderBlockingRequest: \"Request\",\n      /**\n       * @description Label used for a time duration.\n       */\n      duration: \"Duration\",\n      /**\n       * @description Text status indicating that no requests blocked the initial render of a navigation\n       */\n      noRenderBlocking: \"No render blocking requests for this navigation\"\n    };\n    i18nString15 = /* @__PURE__ */ __name((i18nId, values) => ({ i18nId, values }), \"i18nString\");\n    __name(isRenderBlockingInsight, \"isRenderBlockingInsight\");\n    MINIMUM_WASTED_MS = 50;\n    __name(getNodesAndTimingByRequestId, \"getNodesAndTimingByRequestId\");\n    __name(estimateSavingsWithGraphs2, \"estimateSavingsWithGraphs\");\n    __name(hasImageLCP, \"hasImageLCP\");\n    __name(computeSavings, \"computeSavings\");\n    __name(finalize45, \"finalize\");\n    __name(generateInsight15, \"generateInsight\");\n    __name(createOverlayForRequest4, \"createOverlayForRequest\");\n    __name(createOverlays15, \"createOverlays\");\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/insights/SlowCSSSelector.js\nvar SlowCSSSelector_exports = {};\n__export(SlowCSSSelector_exports, {\n  UIStrings: () => UIStrings17,\n  createOverlays: () => createOverlays16,\n  generateInsight: () => generateInsight16,\n  i18nString: () => i18nString16,\n  isSlowCSSSelectorInsight: () => isSlowCSSSelectorInsight\n});\nfunction aggregateSelectorStats(data31, context) {\n  const selectorMap = /* @__PURE__ */ new Map();\n  for (const [event, value] of data31.dataForRecalcStyleEvent) {\n    if (event.args.beginData?.frame !== context.frameId) {\n      continue;\n    }\n    if (!Timing_exports3.eventIsInBounds(event, context.bounds)) {\n      continue;\n    }\n    for (const timing of value.timings) {\n      const key = timing[SelectorTimingsKey.Selector] + \"_\" + timing[SelectorTimingsKey.StyleSheetId];\n      const findTiming = selectorMap.get(key);\n      if (findTiming !== void 0) {\n        findTiming[SelectorTimingsKey.Elapsed] += timing[SelectorTimingsKey.Elapsed];\n        findTiming[SelectorTimingsKey.FastRejectCount] += timing[SelectorTimingsKey.FastRejectCount];\n        findTiming[SelectorTimingsKey.MatchAttempts] += timing[SelectorTimingsKey.MatchAttempts];\n        findTiming[SelectorTimingsKey.MatchCount] += timing[SelectorTimingsKey.MatchCount];\n      } else {\n        selectorMap.set(key, { ...timing });\n      }\n    }\n  }\n  return [...selectorMap.values()];\n}\nfunction finalize46(partialModel) {\n  return {\n    insightKey: InsightKeys.SLOW_CSS_SELECTOR,\n    strings: UIStrings17,\n    title: i18nString16(UIStrings17.title),\n    description: i18nString16(UIStrings17.description),\n    docs: \"https://developer.chrome.com/docs/performance/insights/slow-css-selector\",\n    category: InsightCategory.ALL,\n    state: partialModel.topSelectorElapsedMs && partialModel.topSelectorMatchAttempts ? \"informative\" : \"pass\",\n    ...partialModel\n  };\n}\nfunction isSlowCSSSelectorInsight(model2) {\n  return model2.insightKey === InsightKeys.SLOW_CSS_SELECTOR;\n}\nfunction generateInsight16(data31, context) {\n  const selectorStatsData = data31.SelectorStats;\n  if (!selectorStatsData) {\n    throw new Error(\"no selector stats data\");\n  }\n  const selectorTimings = aggregateSelectorStats(selectorStatsData, context);\n  let totalElapsedUs = 0;\n  let totalMatchAttempts = 0;\n  let totalMatchCount = 0;\n  selectorTimings.map((timing) => {\n    totalElapsedUs += timing[SelectorTimingsKey.Elapsed];\n    totalMatchAttempts += timing[SelectorTimingsKey.MatchAttempts];\n    totalMatchCount += timing[SelectorTimingsKey.MatchCount];\n  });\n  let topSelectorElapsedMs = null;\n  let topSelectorMatchAttempts = null;\n  if (selectorTimings.length > 0) {\n    topSelectorElapsedMs = selectorTimings.reduce((a, b) => {\n      return a[SelectorTimingsKey.Elapsed] > b[SelectorTimingsKey.Elapsed] ? a : b;\n    });\n    if (topSelectorElapsedMs && topSelectorElapsedMs[SelectorTimingsKey.Elapsed] < slowCSSSelectorThreshold) {\n      topSelectorElapsedMs = null;\n    }\n    topSelectorMatchAttempts = selectorTimings.reduce((a, b) => {\n      return a[SelectorTimingsKey.MatchAttempts] > b[SelectorTimingsKey.MatchAttempts] ? a : b;\n    });\n  }\n  return finalize46({\n    // TODO: should we identify RecalcStyle events as linked to this insight?\n    relatedEvents: [],\n    totalElapsedMs: Timing_exports.Milli(totalElapsedUs / 1e3),\n    totalMatchAttempts,\n    totalMatchCount,\n    topSelectorElapsedMs,\n    topSelectorMatchAttempts\n  });\n}\nfunction createOverlays16(_) {\n  return [];\n}\nvar UIStrings17, i18nString16, slowCSSSelectorThreshold;\nvar init_SlowCSSSelector = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/insights/SlowCSSSelector.js\"() {\n    init_process_global();\n    init_helpers2();\n    init_TraceEvents();\n    init_types2();\n    init_types4();\n    UIStrings17 = {\n      /**\n       * @description Title of an insight that provides details about slow CSS selectors.\n       */\n      title: \"CSS Selector costs\",\n      /**\n       * @description Text to describe how to improve the performance of CSS selectors.\n       */\n      description: \"If Recalculate Style costs remain high, selector optimization can reduce them. [Optimize the selectors](https://developer.chrome.com/docs/performance/insights/slow-css-selector) with both high elapsed time and high slow-path %. Simpler selectors, fewer selectors, a smaller DOM, and a shallower DOM will all reduce matching costs.\",\n      /**\n       * @description Column name for count of elements that the engine attempted to match against a style rule\n       */\n      matchAttempts: \"Match attempts\",\n      /**\n       * @description Column name for count of elements that matched a style rule\n       */\n      matchCount: \"Match count\",\n      /**\n       * @description Column name for elapsed time spent computing a style rule\n       */\n      elapsed: \"Elapsed time\",\n      /**\n       * @description Column name for the selectors that took the longest amount of time/effort.\n       */\n      topSelectors: \"Top selectors\",\n      /**\n       * @description Column name for a total sum.\n       */\n      total: \"Total\",\n      /**\n       * @description Text status indicating that no CSS selector data was found.\n       */\n      enableSelectorData: \"No CSS selector data was found. CSS selector stats need to be enabled in the performance panel settings.\",\n      /**\n       * @description top CSS selector when ranked by elapsed time in ms\n       */\n      topSelectorElapsedTime: \"Top selector elapsed time\",\n      /**\n       * @description top CSS selector when ranked by match attempt\n       */\n      topSelectorMatchAttempt: \"Top selector match attempt\"\n    };\n    i18nString16 = /* @__PURE__ */ __name((i18nId, values) => ({ i18nId, values }), \"i18nString\");\n    slowCSSSelectorThreshold = 500;\n    __name(aggregateSelectorStats, \"aggregateSelectorStats\");\n    __name(finalize46, \"finalize\");\n    __name(isSlowCSSSelectorInsight, \"isSlowCSSSelectorInsight\");\n    __name(generateInsight16, \"generateInsight\");\n    __name(createOverlays16, \"createOverlays\");\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/insights/ThirdParties.js\nvar ThirdParties_exports2 = {};\n__export(ThirdParties_exports2, {\n  UIStrings: () => UIStrings18,\n  createOverlays: () => createOverlays17,\n  createOverlaysForSummary: () => createOverlaysForSummary,\n  generateInsight: () => generateInsight17,\n  i18nString: () => i18nString17,\n  isThirdPartyInsight: () => isThirdPartyInsight\n});\nfunction getRelatedEvents(summaries, firstPartyEntity) {\n  const relatedEvents = [];\n  for (const summary of summaries) {\n    if (summary.entity !== firstPartyEntity) {\n      relatedEvents.push(...summary.relatedEvents);\n    }\n  }\n  return relatedEvents;\n}\nfunction finalize47(partialModel) {\n  return {\n    insightKey: InsightKeys.THIRD_PARTIES,\n    strings: UIStrings18,\n    title: i18nString17(UIStrings18.title),\n    description: i18nString17(UIStrings18.description),\n    docs: \"https://developer.chrome.com/docs/performance/insights/third-parties\",\n    category: InsightCategory.ALL,\n    state: partialModel.entitySummaries.find((summary) => summary.entity !== partialModel.firstPartyEntity) ? \"informative\" : \"pass\",\n    ...partialModel\n  };\n}\nfunction isThirdPartyInsight(model2) {\n  return model2.insightKey === InsightKeys.THIRD_PARTIES;\n}\nfunction generateInsight17(data31, context) {\n  const entitySummaries = ThirdParties_exports.summarizeByThirdParty(data31, context.bounds);\n  const firstPartyUrl = context.navigation?.args.data?.documentLoaderURL ?? data31.Meta.mainFrameURL;\n  const firstPartyEntity = import_third_party_web.default.getEntity(firstPartyUrl) || helpers_exports.makeUpEntity(data31.Renderer.entityMappings.createdEntityCache, firstPartyUrl);\n  return finalize47({\n    relatedEvents: getRelatedEvents(entitySummaries, firstPartyEntity),\n    firstPartyEntity,\n    entitySummaries\n  });\n}\nfunction createOverlaysForSummary(summary) {\n  const overlays = [];\n  for (const event of summary.relatedEvents) {\n    if (event.dur === void 0 || event.dur < 1e3) {\n      continue;\n    }\n    const overlay = {\n      type: \"ENTRY_OUTLINE\",\n      entry: event,\n      outlineReason: \"INFO\"\n    };\n    overlays.push(overlay);\n  }\n  return overlays;\n}\nfunction createOverlays17(model2) {\n  const overlays = [];\n  const summaries = model2.entitySummaries ?? [];\n  for (const summary of summaries) {\n    if (summary.entity === model2.firstPartyEntity) {\n      continue;\n    }\n    const summaryOverlays = createOverlaysForSummary(summary);\n    overlays.push(...summaryOverlays);\n  }\n  return overlays;\n}\nvar UIStrings18, i18nString17;\nvar init_ThirdParties2 = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/insights/ThirdParties.js\"() {\n    init_process_global();\n    init_third_party_web();\n    init_extras();\n    init_handlers();\n    init_types4();\n    UIStrings18 = {\n      /** Title of an insight that provides details about the code on a web page that the user doesn't control (referred to as \"third-party code\"). */\n      title: \"3rd parties\",\n      /**\n       * @description Description of a DevTools insight that identifies the code on the page that the user doesn't control.\n       * This is displayed after a user expands the section to see more. No character length limits.\n       */\n      description: \"3rd party code can significantly impact load performance. [Reduce and defer loading of 3rd party code](https://developer.chrome.com/docs/performance/insights/third-parties) to prioritize your page's content.\",\n      /** Label for a table column that displays the name of a third-party provider. */\n      columnThirdParty: \"3rd party\",\n      /** Label for a column in a data table; entries will be the download size of a web resource in kilobytes. */\n      columnTransferSize: \"Transfer size\",\n      /** Label for a table column that displays how much time each row spent running on the main thread, entries will be the number of milliseconds spent. */\n      columnMainThreadTime: \"Main thread time\",\n      /**\n       * @description Text block indicating that no third party content was detected on the page\n       */\n      noThirdParties: \"No third parties found\"\n    };\n    i18nString17 = /* @__PURE__ */ __name((i18nId, values) => ({ i18nId, values }), \"i18nString\");\n    __name(getRelatedEvents, \"getRelatedEvents\");\n    __name(finalize47, \"finalize\");\n    __name(isThirdPartyInsight, \"isThirdPartyInsight\");\n    __name(generateInsight17, \"generateInsight\");\n    __name(createOverlaysForSummary, \"createOverlaysForSummary\");\n    __name(createOverlays17, \"createOverlays\");\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/insights/Viewport.js\nvar Viewport_exports = {};\n__export(Viewport_exports, {\n  UIStrings: () => UIStrings19,\n  createOverlays: () => createOverlays18,\n  generateInsight: () => generateInsight18,\n  i18nString: () => i18nString18,\n  isViewportInsight: () => isViewportInsight\n});\nfunction finalize48(partialModel) {\n  return {\n    insightKey: InsightKeys.VIEWPORT,\n    strings: UIStrings19,\n    title: i18nString18(UIStrings19.title),\n    description: i18nString18(UIStrings19.description),\n    docs: \"https://developer.chrome.com/docs/performance/insights/viewport\",\n    category: InsightCategory.INP,\n    state: partialModel.mobileOptimized === false ? \"fail\" : \"pass\",\n    ...partialModel\n  };\n}\nfunction isViewportInsight(model2) {\n  return model2.insightKey === InsightKeys.VIEWPORT;\n}\nfunction generateInsight18(data31, context) {\n  const viewportEvent = data31.UserInteractions.parseMetaViewportEvents.find((event) => {\n    if (event.args.data.frame !== context.frameId) {\n      return false;\n    }\n    return Timing_exports3.eventIsInBounds(event, context.bounds);\n  });\n  const compositorEvents = data31.UserInteractions.beginCommitCompositorFrameEvents.filter((event) => {\n    if (event.args.frame !== context.frameId) {\n      return false;\n    }\n    if (viewportEvent && event.ts < viewportEvent.ts) {\n      return false;\n    }\n    return Timing_exports3.eventIsInBounds(event, context.bounds);\n  });\n  if (!compositorEvents.length) {\n    return finalize48({\n      mobileOptimized: null,\n      warnings: [InsightWarning.NO_LAYOUT]\n    });\n  }\n  for (const event of compositorEvents) {\n    if (!event.args.is_mobile_optimized) {\n      const longPointerInteractions = [...data31.UserInteractions.interactionsOverThreshold.values()].filter((interaction) => ModelHandlers_exports.UserInteractions.categoryOfInteraction(interaction) === \"POINTER\" && interaction.inputDelay >= 5e4);\n      const inputDelay = Math.max(0, ...longPointerInteractions.map((interaction) => interaction.inputDelay)) / 1e3;\n      const inpMetricSavings = NumberUtilities_exports.clamp(inputDelay, 0, 300);\n      return finalize48({\n        mobileOptimized: false,\n        viewportEvent,\n        longPointerInteractions,\n        metricSavings: { INP: inpMetricSavings }\n      });\n    }\n  }\n  return finalize48({\n    mobileOptimized: true,\n    viewportEvent\n  });\n}\nfunction createOverlays18(model2) {\n  if (!model2.longPointerInteractions) {\n    return [];\n  }\n  return model2.longPointerInteractions.map((interaction) => {\n    const delay = Math.min(interaction.inputDelay, 300 * 1e3);\n    const bounds = Timing_exports3.traceWindowFromMicroSeconds(Timing_exports.Micro(interaction.ts), Timing_exports.Micro(interaction.ts + delay));\n    return {\n      type: \"TIMESPAN_BREAKDOWN\",\n      entry: interaction,\n      sections: [{ bounds, label: i18nString18(UIStrings19.mobileTapDelayLabel), showDuration: true }],\n      renderLocation: \"ABOVE_EVENT\"\n    };\n  });\n}\nvar UIStrings19, i18nString18;\nvar init_Viewport = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/insights/Viewport.js\"() {\n    init_process_global();\n    init_platform();\n    init_handlers();\n    init_helpers2();\n    init_types2();\n    init_types4();\n    UIStrings19 = {\n      /** Title of an insight that provides details about if the page's viewport is optimized for mobile viewing. */\n      title: \"Optimize viewport for mobile\",\n      /**\n       * @description Text to tell the user how a viewport meta element can improve performance. \\xa0 is a non-breaking space\n       */\n      description: \"Tap interactions may be [delayed by up to 300 ms](https://developer.chrome.com/docs/performance/insights/viewport) if the viewport is not optimized for mobile.\",\n      /**\n       * @description Text for a label describing the portion of an interaction event that was delayed due to a bad mobile viewport.\n       */\n      mobileTapDelayLabel: \"Mobile tap delay\"\n    };\n    i18nString18 = /* @__PURE__ */ __name((i18nId, values) => ({ i18nId, values }), \"i18nString\");\n    __name(finalize48, \"finalize\");\n    __name(isViewportInsight, \"isViewportInsight\");\n    __name(generateInsight18, \"generateInsight\");\n    __name(createOverlays18, \"createOverlays\");\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/insights/Models.js\nvar Models_exports = {};\n__export(Models_exports, {\n  CLSCulprits: () => CLSCulprits_exports,\n  Cache: () => Cache_exports,\n  DOMSize: () => DOMSize_exports,\n  DocumentLatency: () => DocumentLatency_exports,\n  DuplicatedJavaScript: () => DuplicatedJavaScript_exports,\n  FontDisplay: () => FontDisplay_exports,\n  ForcedReflow: () => ForcedReflow_exports,\n  INPBreakdown: () => INPBreakdown_exports,\n  ImageDelivery: () => ImageDelivery_exports,\n  LCPBreakdown: () => LCPBreakdown_exports,\n  LCPDiscovery: () => LCPDiscovery_exports,\n  LegacyJavaScript: () => LegacyJavaScript_exports,\n  ModernHTTP: () => ModernHTTP_exports,\n  NetworkDependencyTree: () => NetworkDependencyTree_exports,\n  RenderBlocking: () => RenderBlocking_exports,\n  SlowCSSSelector: () => SlowCSSSelector_exports,\n  ThirdParties: () => ThirdParties_exports2,\n  Viewport: () => Viewport_exports\n});\nvar init_Models = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/insights/Models.js\"() {\n    init_process_global();\n    init_Cache();\n    init_CLSCulprits();\n    init_DocumentLatency();\n    init_DOMSize();\n    init_DuplicatedJavaScript();\n    init_FontDisplay();\n    init_ForcedReflow();\n    init_ImageDelivery();\n    init_INPBreakdown();\n    init_LCPBreakdown();\n    init_LCPDiscovery();\n    init_LegacyJavaScript();\n    init_ModernHTTP();\n    init_NetworkDependencyTree();\n    init_RenderBlocking();\n    init_SlowCSSSelector();\n    init_ThirdParties2();\n    init_Viewport();\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/insights/insights.js\nvar init_insights = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/insights/insights.js\"() {\n    init_process_global();\n    init_Cache();\n    init_Common();\n    init_Models();\n    init_ModernHTTP();\n    init_Statistics();\n    init_types4();\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/LanternComputationData.js\nfunction createProcessedNavigation(data31, frameId, navigationId) {\n  const scoresByNav = data31.PageLoadMetrics.metricScoresByFrameId.get(frameId);\n  if (!scoresByNav) {\n    throw new core_exports.LanternError(\"missing metric scores for frame\");\n  }\n  const scores = scoresByNav.get(navigationId);\n  if (!scores) {\n    throw new core_exports.LanternError(\"missing metric scores for specified navigation\");\n  }\n  const getTimestampOrUndefined = /* @__PURE__ */ __name((metric) => {\n    const metricScore = scores.get(metric);\n    if (!metricScore?.event) {\n      return;\n    }\n    return metricScore.event.ts;\n  }, \"getTimestampOrUndefined\");\n  const getTimestamp = /* @__PURE__ */ __name((metric) => {\n    const metricScore = scores.get(metric);\n    if (!metricScore?.event) {\n      throw new core_exports.LanternError(`missing metric: ${metric}`);\n    }\n    return metricScore.event.ts;\n  }, \"getTimestamp\");\n  return {\n    timestamps: {\n      firstContentfulPaint: getTimestamp(ModelHandlers_exports.PageLoadMetrics.MetricName.FCP),\n      largestContentfulPaint: getTimestampOrUndefined(ModelHandlers_exports.PageLoadMetrics.MetricName.LCP)\n    }\n  };\n}\nfunction createParsedUrl(url) {\n  if (typeof url === \"string\") {\n    url = new URL(url);\n  }\n  return {\n    scheme: url.protocol.split(\":\")[0],\n    // Intentional, DevTools uses different terminology\n    host: url.hostname,\n    securityOrigin: url.origin\n  };\n}\nfunction findWorkerThreads(trace) {\n  const workerThreads = /* @__PURE__ */ new Map();\n  const workerCreationEvents = [\"ServiceWorker thread\", \"DedicatedWorker thread\"];\n  for (const event of trace.traceEvents) {\n    if (event.name !== \"thread_name\" || !event.args.name) {\n      continue;\n    }\n    if (!workerCreationEvents.includes(event.args.name)) {\n      continue;\n    }\n    const tids = workerThreads.get(event.pid);\n    if (tids) {\n      tids.push(event.tid);\n    } else {\n      workerThreads.set(event.pid, [event.tid]);\n    }\n  }\n  return workerThreads;\n}\nfunction createLanternRequest(parsedTrace, workerThreads, request) {\n  if (request.args.data.hasResponse && request.args.data.connectionId === void 0) {\n    throw new core_exports.LanternError(\"Trace is too old\");\n  }\n  let url;\n  try {\n    url = new URL(request.args.data.url);\n  } catch {\n    return;\n  }\n  const timing = request.args.data.timing ? {\n    // These two timings are not included in the trace.\n    workerFetchStart: -1,\n    workerRespondWithSettled: -1,\n    receiveHeadersStart: -1,\n    ...request.args.data.timing\n  } : void 0;\n  const networkRequestTime = timing ? timing.requestTime * 1e3 : request.args.data.syntheticData.downloadStart / 1e3;\n  let fromWorker = false;\n  const tids = workerThreads.get(request.pid);\n  if (tids?.includes(request.tid)) {\n    fromWorker = true;\n  }\n  if (parsedTrace.Workers.workerIdByThread.has(request.tid)) {\n    fromWorker = true;\n  }\n  const initiator = request.args.data.initiator ?? {\n    type: \"other\"\n    /* Protocol.Network.InitiatorType.Other */\n  };\n  if (request.args.data.stackTrace) {\n    const callFrames = request.args.data.stackTrace.map((f) => {\n      return {\n        scriptId: String(f.scriptId),\n        url: f.url,\n        lineNumber: f.lineNumber - 1,\n        columnNumber: f.columnNumber - 1,\n        functionName: f.functionName\n      };\n    });\n    initiator.stack = { callFrames };\n  }\n  let resourceType = request.args.data.resourceType;\n  if (request.args.data.initiator?.fetchType === \"xmlhttprequest\") {\n    resourceType = \"XHR\";\n  } else if (request.args.data.initiator?.fetchType === \"fetch\") {\n    resourceType = \"Fetch\";\n  }\n  let resourceSize = request.args.data.decodedBodyLength ?? 0;\n  if (url.protocol === \"data:\" && resourceSize === 0) {\n    const commaIndex = url.pathname.indexOf(\",\");\n    if (url.pathname.substring(0, commaIndex).includes(\";base64\")) {\n      resourceSize = atob(url.pathname.substring(commaIndex + 1)).length;\n    } else {\n      resourceSize = url.pathname.length - commaIndex - 1;\n    }\n  }\n  return {\n    rawRequest: request,\n    requestId: request.args.data.requestId,\n    connectionId: request.args.data.connectionId ?? 0,\n    connectionReused: request.args.data.connectionReused ?? false,\n    url: request.args.data.url,\n    protocol: request.args.data.protocol,\n    parsedURL: createParsedUrl(url),\n    documentURL: request.args.data.requestingFrameUrl,\n    rendererStartTime: request.ts / 1e3,\n    networkRequestTime,\n    responseHeadersEndTime: request.args.data.syntheticData.downloadStart / 1e3,\n    networkEndTime: request.args.data.syntheticData.finishTime / 1e3,\n    transferSize: request.args.data.encodedDataLength,\n    resourceSize,\n    fromDiskCache: request.args.data.syntheticData.isDiskCached,\n    fromMemoryCache: request.args.data.syntheticData.isMemoryCached,\n    isLinkPreload: request.args.data.isLinkPreload,\n    finished: request.args.data.finished,\n    failed: request.args.data.failed,\n    statusCode: request.args.data.statusCode,\n    initiator,\n    timing,\n    resourceType,\n    mimeType: request.args.data.mimeType,\n    priority: request.args.data.priority,\n    frameId: request.args.data.frame,\n    fromWorker,\n    serverResponseTime: request.args.data.lrServerResponseTime ?? void 0,\n    // Set later.\n    redirects: void 0,\n    redirectSource: void 0,\n    redirectDestination: void 0,\n    initiatorRequest: void 0\n  };\n}\nfunction chooseInitiatorRequest(request, requestsByURL) {\n  if (request.redirectSource) {\n    return request.redirectSource;\n  }\n  const initiatorURL = graph_exports.PageDependencyGraph.getNetworkInitiators(request)[0];\n  let candidates = requestsByURL.get(initiatorURL) || [];\n  candidates = candidates.filter((c) => {\n    return c.responseHeadersEndTime <= request.rendererStartTime && c.finished && !c.failed;\n  });\n  if (candidates.length > 1) {\n    const nonPrefetchCandidates = candidates.filter((cand) => cand.resourceType !== types_exports.NetworkRequestTypes.Other);\n    if (nonPrefetchCandidates.length) {\n      candidates = nonPrefetchCandidates;\n    }\n  }\n  if (candidates.length > 1) {\n    const sameFrameCandidates = candidates.filter((cand) => cand.frameId === request.frameId);\n    if (sameFrameCandidates.length) {\n      candidates = sameFrameCandidates;\n    }\n  }\n  if (candidates.length > 1 && request.initiator.type === \"parser\") {\n    const documentCandidates = candidates.filter((cand) => cand.resourceType === types_exports.NetworkRequestTypes.Document);\n    if (documentCandidates.length) {\n      candidates = documentCandidates;\n    }\n  }\n  if (candidates.length > 1) {\n    const linkPreloadCandidates = candidates.filter((c) => c.isLinkPreload);\n    if (linkPreloadCandidates.length) {\n      const nonPreloadCandidates = candidates.filter((c) => !c.isLinkPreload);\n      const allPreloaded = nonPreloadCandidates.every((c) => c.fromDiskCache || c.fromMemoryCache);\n      if (nonPreloadCandidates.length && allPreloaded) {\n        candidates = linkPreloadCandidates;\n      }\n    }\n  }\n  return candidates.length === 1 ? candidates[0] : null;\n}\nfunction linkInitiators(lanternRequests) {\n  const requestsByURL = /* @__PURE__ */ new Map();\n  for (const request of lanternRequests) {\n    const requests = requestsByURL.get(request.url) || [];\n    requests.push(request);\n    requestsByURL.set(request.url, requests);\n  }\n  for (const request of lanternRequests) {\n    const initiatorRequest = chooseInitiatorRequest(request, requestsByURL);\n    if (initiatorRequest) {\n      request.initiatorRequest = initiatorRequest;\n    }\n  }\n}\nfunction createNetworkRequests(trace, data31, startTime = 0, endTime = Number.POSITIVE_INFINITY) {\n  const workerThreads = findWorkerThreads(trace);\n  const lanternRequestsNoRedirects = [];\n  for (const request of data31.NetworkRequests.byTime) {\n    if (request.ts >= startTime && request.ts < endTime) {\n      const lanternRequest = createLanternRequest(data31, workerThreads, request);\n      if (lanternRequest) {\n        lanternRequestsNoRedirects.push(lanternRequest);\n      }\n    }\n  }\n  const lanternRequests = [];\n  for (const request of [...lanternRequestsNoRedirects]) {\n    if (!request.rawRequest) {\n      continue;\n    }\n    const redirects = request.rawRequest.args.data.redirects;\n    if (!redirects.length) {\n      lanternRequests.push(request);\n      continue;\n    }\n    const requestChain = [];\n    for (const redirect of redirects) {\n      const redirectedRequest = structuredClone(request);\n      redirectedRequest.networkRequestTime = redirect.ts / 1e3;\n      redirectedRequest.rendererStartTime = redirectedRequest.networkRequestTime;\n      redirectedRequest.networkEndTime = (redirect.ts + redirect.dur) / 1e3;\n      redirectedRequest.responseHeadersEndTime = redirectedRequest.networkEndTime;\n      redirectedRequest.timing = {\n        requestTime: redirectedRequest.networkRequestTime / 1e3,\n        receiveHeadersStart: redirectedRequest.responseHeadersEndTime,\n        receiveHeadersEnd: redirectedRequest.responseHeadersEndTime,\n        proxyStart: -1,\n        proxyEnd: -1,\n        dnsStart: -1,\n        dnsEnd: -1,\n        connectStart: -1,\n        connectEnd: -1,\n        sslStart: -1,\n        sslEnd: -1,\n        sendStart: -1,\n        sendEnd: -1,\n        workerStart: -1,\n        workerReady: -1,\n        workerFetchStart: -1,\n        workerRespondWithSettled: -1,\n        pushStart: -1,\n        pushEnd: -1\n      };\n      redirectedRequest.url = redirect.url;\n      redirectedRequest.parsedURL = createParsedUrl(redirect.url);\n      redirectedRequest.statusCode = 302;\n      redirectedRequest.resourceType = void 0;\n      redirectedRequest.transferSize = 400;\n      requestChain.push(redirectedRequest);\n      lanternRequests.push(redirectedRequest);\n    }\n    requestChain.push(request);\n    lanternRequests.push(request);\n    for (let i = 0; i < requestChain.length; i++) {\n      const request2 = requestChain[i];\n      if (i > 0) {\n        request2.redirectSource = requestChain[i - 1];\n        request2.redirects = requestChain.slice(0, i);\n      }\n      if (i !== requestChain.length - 1) {\n        request2.redirectDestination = requestChain[i + 1];\n      }\n    }\n    for (let i = 1; i < requestChain.length; i++) {\n      requestChain[i].requestId = `${requestChain[i - 1].requestId}:redirect`;\n    }\n  }\n  linkInitiators(lanternRequests);\n  return lanternRequests;\n}\nfunction collectMainThreadEvents(trace, data31) {\n  const Meta = data31.Meta;\n  const mainFramePids = Meta.mainFrameNavigations.length ? new Set(Meta.mainFrameNavigations.map((nav) => nav.pid)) : Meta.topLevelRendererIds;\n  const rendererPidToTid = /* @__PURE__ */ new Map();\n  for (const pid of mainFramePids) {\n    const threads = Meta.threadsInProcess.get(pid) ?? [];\n    let found = false;\n    for (const [tid, thread] of threads) {\n      if (thread.args.name === \"CrRendererMain\") {\n        rendererPidToTid.set(pid, tid);\n        found = true;\n        break;\n      }\n    }\n    if (found) {\n      continue;\n    }\n    for (const [tid, thread] of threads) {\n      if (thread.args.name === \"CrBrowserMain\") {\n        rendererPidToTid.set(pid, tid);\n        found = true;\n        break;\n      }\n    }\n  }\n  return trace.traceEvents.filter((e) => rendererPidToTid.get(e.pid) === e.tid);\n}\nfunction createGraph(requests, trace, data31, url) {\n  const mainThreadEvents = collectMainThreadEvents(trace, data31);\n  if (!url) {\n    url = {\n      requestedUrl: requests[0].url,\n      mainDocumentUrl: \"\"\n    };\n    let request = requests[0];\n    while (request.redirectDestination) {\n      request = request.redirectDestination;\n    }\n    url.mainDocumentUrl = request.url;\n  }\n  return graph_exports.PageDependencyGraph.createGraph(mainThreadEvents, requests, url);\n}\nvar init_LanternComputationData = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/LanternComputationData.js\"() {\n    init_process_global();\n    init_handlers();\n    init_lantern();\n    __name(createProcessedNavigation, \"createProcessedNavigation\");\n    __name(createParsedUrl, \"createParsedUrl\");\n    __name(findWorkerThreads, \"findWorkerThreads\");\n    __name(createLanternRequest, \"createLanternRequest\");\n    __name(chooseInitiatorRequest, \"chooseInitiatorRequest\");\n    __name(linkInitiators, \"linkInitiators\");\n    __name(createNetworkRequests, \"createNetworkRequests\");\n    __name(collectMainThreadEvents, \"collectMainThreadEvents\");\n    __name(createGraph, \"createGraph\");\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/Processor.js\nfunction calculateProgress(value, phase) {\n  if (phase === 0.8) {\n    return value * (0.8 - 0.2) + 0.2;\n  }\n  return value * phase;\n}\nfunction sortHandlers(traceHandlers) {\n  const sortedMap = /* @__PURE__ */ new Map();\n  const visited = /* @__PURE__ */ new Set();\n  const visitHandler = /* @__PURE__ */ __name((handlerName) => {\n    if (sortedMap.has(handlerName)) {\n      return;\n    }\n    if (visited.has(handlerName)) {\n      let stackPath = \"\";\n      for (const handler2 of visited) {\n        if (stackPath || handler2 === handlerName) {\n          stackPath += `${handler2}->`;\n        }\n      }\n      stackPath += handlerName;\n      throw new Error(`Found dependency cycle in trace event handlers: ${stackPath}`);\n    }\n    visited.add(handlerName);\n    const handler = traceHandlers[handlerName];\n    if (!handler) {\n      return;\n    }\n    const deps17 = handler.deps?.();\n    if (deps17) {\n      deps17.forEach(visitHandler);\n    }\n    sortedMap.set(handlerName, handler);\n  }, \"visitHandler\");\n  for (const handlerName of Object.keys(traceHandlers)) {\n    visitHandler(handlerName);\n  }\n  return sortedMap;\n}\nvar _a2, TraceParseProgressEvent, TraceProcessor;\nvar init_Processor = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/Processor.js\"() {\n    init_process_global();\n    init_handlers();\n    init_helpers2();\n    init_insights();\n    init_lantern();\n    init_LanternComputationData();\n    init_types2();\n    TraceParseProgressEvent = class _TraceParseProgressEvent extends Event {\n      static {\n        __name(this, \"TraceParseProgressEvent\");\n      }\n      data;\n      static eventName = \"traceparseprogress\";\n      constructor(data31, init2 = { bubbles: true }) {\n        super(_TraceParseProgressEvent.eventName, init2);\n        this.data = data31;\n      }\n    };\n    __name(calculateProgress, \"calculateProgress\");\n    TraceProcessor = class extends EventTarget {\n      static {\n        __name(this, \"TraceProcessor\");\n      }\n      // We force the Meta handler to be enabled, so the TraceHandlers type here is\n      // the model handlers the user passes in and the Meta handler.\n      #traceHandlers;\n      #status = \"IDLE\";\n      #modelConfiguration = Configuration_exports.defaults();\n      #data = null;\n      #insights = null;\n      static createWithAllHandlers() {\n        return new _a2(ModelHandlers_exports, Configuration_exports.defaults());\n      }\n      /**\n       * This function is kept for testing with `stub`.\n       */\n      static getInsightRunners() {\n        return { ...Models_exports };\n      }\n      constructor(traceHandlers, modelConfiguration) {\n        super();\n        this.#verifyHandlers(traceHandlers);\n        this.#traceHandlers = {\n          Meta: ModelHandlers_exports.Meta,\n          ...traceHandlers\n        };\n        if (modelConfiguration) {\n          this.#modelConfiguration = modelConfiguration;\n        }\n        this.#passConfigToHandlers();\n      }\n      #passConfigToHandlers() {\n        for (const handler of Object.values(this.#traceHandlers)) {\n          if (\"handleUserConfig\" in handler && handler.handleUserConfig) {\n            handler.handleUserConfig(this.#modelConfiguration);\n          }\n        }\n      }\n      /**\n       * When the user passes in a set of handlers, we want to ensure that we have all\n       * the required handlers. Handlers can depend on other handlers, so if the user\n       * passes in FooHandler which depends on BarHandler, they must also pass in\n       * BarHandler too. This method verifies that all dependencies are met, and\n       * throws if not.\n       **/\n      #verifyHandlers(providedHandlers) {\n        if (Object.keys(providedHandlers).length === Object.keys(ModelHandlers_exports).length) {\n          return;\n        }\n        const requiredHandlerKeys = /* @__PURE__ */ new Set();\n        for (const [handlerName, handler] of Object.entries(providedHandlers)) {\n          requiredHandlerKeys.add(handlerName);\n          const deps17 = \"deps\" in handler ? handler.deps() : [];\n          for (const depName of deps17) {\n            requiredHandlerKeys.add(depName);\n          }\n        }\n        const providedHandlerKeys = new Set(Object.keys(providedHandlers));\n        requiredHandlerKeys.delete(\"Meta\");\n        for (const requiredKey of requiredHandlerKeys) {\n          if (!providedHandlerKeys.has(requiredKey)) {\n            throw new Error(`Required handler ${requiredKey} not provided.`);\n          }\n        }\n      }\n      reset() {\n        if (this.#status === \"PARSING\") {\n          throw new Error(\"Trace processor can't reset while parsing.\");\n        }\n        const handlers = Object.values(this.#traceHandlers);\n        for (const handler of handlers) {\n          handler.reset();\n        }\n        this.#data = null;\n        this.#insights = null;\n        this.#status = \"IDLE\";\n      }\n      async parse(traceEvents, options) {\n        if (this.#status !== \"IDLE\") {\n          throw new Error(`Trace processor can't start parsing when not idle. Current state: ${this.#status}`);\n        }\n        if (typeof options.isCPUProfile === \"undefined\" && options.metadata) {\n          options.isCPUProfile = options.metadata.dataOrigin === File_exports.DataOrigin.CPU_PROFILE;\n        }\n        options.logger?.start(\"total\");\n        try {\n          this.#status = \"PARSING\";\n          options.logger?.start(\"parse\");\n          await this.#computeParsedTrace(traceEvents, options);\n          options.logger?.end(\"parse\");\n          if (this.#data && !options.isCPUProfile) {\n            options.logger?.start(\"insights\");\n            this.#computeInsights(this.#data, traceEvents, options);\n            options.logger?.end(\"insights\");\n          }\n          this.#status = \"FINISHED_PARSING\";\n        } catch (e) {\n          this.#status = \"ERRORED_WHILE_PARSING\";\n          throw e;\n        } finally {\n          options.logger?.end(\"total\");\n        }\n      }\n      /**\n       * Run all the handlers and set the result to `#data`.\n       */\n      async #computeParsedTrace(traceEvents, options) {\n        const eventsPerChunk = 5e4;\n        const sortedHandlers = [...sortHandlers(this.#traceHandlers).entries()];\n        for (const [, handler] of sortedHandlers) {\n          handler.reset();\n        }\n        options.logger?.start(\"parse:handleEvent\");\n        for (let i = 0; i < traceEvents.length; ++i) {\n          if (i % eventsPerChunk === 0 && i) {\n            const percent = calculateProgress(\n              i / traceEvents.length,\n              0.2\n              /* ProgressPhase.HANDLE_EVENT */\n            );\n            this.dispatchEvent(new TraceParseProgressEvent({ percent }));\n            await new Promise((resolve) => setTimeout(resolve, 0));\n          }\n          const event = traceEvents[i];\n          for (let j = 0; j < sortedHandlers.length; ++j) {\n            const [, handler] = sortedHandlers[j];\n            handler.handleEvent(event);\n          }\n        }\n        options.logger?.end(\"parse:handleEvent\");\n        const finalizeOptions = {\n          ...options,\n          allTraceEvents: traceEvents\n        };\n        for (let i = 0; i < sortedHandlers.length; i++) {\n          const [name, handler] = sortedHandlers[i];\n          if (handler.finalize) {\n            options.logger?.start(`parse:${name}:finalize`);\n            await new Promise((resolve) => setTimeout(resolve, 0));\n            await handler.finalize(finalizeOptions);\n            options.logger?.end(`parse:${name}:finalize`);\n          }\n          const percent = calculateProgress(\n            i / sortedHandlers.length,\n            0.8\n            /* ProgressPhase.FINALIZE */\n          );\n          this.dispatchEvent(new TraceParseProgressEvent({ percent }));\n        }\n        options.logger?.start(\"parse:handler.data()\");\n        const parsedTrace = {};\n        for (const [name, handler] of Object.entries(this.#traceHandlers)) {\n          Object.assign(parsedTrace, { [name]: handler.data() });\n        }\n        options.logger?.end(\"parse:handler.data()\");\n        this.dispatchEvent(new TraceParseProgressEvent({\n          percent: 1\n          /* ProgressPhase.CLONE */\n        }));\n        this.#data = parsedTrace;\n      }\n      get data() {\n        if (this.#status !== \"FINISHED_PARSING\") {\n          return null;\n        }\n        return this.#data;\n      }\n      get insights() {\n        if (this.#status !== \"FINISHED_PARSING\") {\n          return null;\n        }\n        return this.#insights;\n      }\n      #createLanternContext(data31, traceEvents, frameId, navigationId, options) {\n        if (!data31.NetworkRequests || !data31.Workers || !data31.PageLoadMetrics) {\n          return;\n        }\n        if (!data31.NetworkRequests.byTime.length) {\n          throw new core_exports.LanternError(\"No network requests found in trace\");\n        }\n        const navStarts = data31.Meta.navigationsByFrameId.get(frameId);\n        const navStartIndex = navStarts?.findIndex((n) => n.args.data?.navigationId === navigationId);\n        if (!navStarts || navStartIndex === void 0 || navStartIndex === -1) {\n          throw new core_exports.LanternError(\"Could not find navigation start\");\n        }\n        const startTime = navStarts[navStartIndex].ts;\n        const endTime = navStartIndex + 1 < navStarts.length ? navStarts[navStartIndex + 1].ts : Number.POSITIVE_INFINITY;\n        const boundedTraceEvents = traceEvents.filter((e) => e.ts >= startTime && e.ts < endTime);\n        const trace = {\n          traceEvents: boundedTraceEvents\n        };\n        const requests = createNetworkRequests(trace, data31, startTime, endTime);\n        const graph2 = createGraph(requests, trace, data31);\n        const processedNavigation = createProcessedNavigation(data31, frameId, navigationId);\n        const networkAnalysis = core_exports.NetworkAnalyzer.analyze(requests);\n        if (!networkAnalysis) {\n          return;\n        }\n        const lanternSettings = {\n          // TODO(crbug.com/372674229): if devtools throttling was on, does this network analysis capture\n          // that? Do we need to set 'devtools' throttlingMethod?\n          networkAnalysis,\n          throttlingMethod: \"provided\",\n          ...options.lanternSettings\n        };\n        const simulator = simulation_exports.Simulator.createSimulator(lanternSettings);\n        const computeData = { graph: graph2, simulator, processedNavigation };\n        const fcpResult = metrics_exports.FirstContentfulPaint.compute(computeData);\n        const lcpResult = metrics_exports.LargestContentfulPaint.compute(computeData, { fcpResult });\n        const interactiveResult = metrics_exports.Interactive.compute(computeData, { lcpResult });\n        const tbtResult = metrics_exports.TotalBlockingTime.compute(computeData, { fcpResult, interactiveResult });\n        const metrics = {\n          firstContentfulPaint: fcpResult,\n          interactive: interactiveResult,\n          largestContentfulPaint: lcpResult,\n          totalBlockingTime: tbtResult\n        };\n        return { requests, graph: graph2, simulator, metrics };\n      }\n      /**\n       * Sort the insight models based on the impact of each insight's estimated savings, additionally weighted by the\n       * worst metrics according to field data (if present).\n       */\n      sortInsightSet(insightSet, metadata) {\n        const baselineOrder = {\n          INPBreakdown: null,\n          LCPBreakdown: null,\n          LCPDiscovery: null,\n          CLSCulprits: null,\n          RenderBlocking: null,\n          NetworkDependencyTree: null,\n          ImageDelivery: null,\n          DocumentLatency: null,\n          FontDisplay: null,\n          Viewport: null,\n          DOMSize: null,\n          ThirdParties: null,\n          DuplicatedJavaScript: null,\n          SlowCSSSelector: null,\n          ForcedReflow: null,\n          Cache: null,\n          ModernHTTP: null,\n          LegacyJavaScript: null\n        };\n        const weights = Common_exports.calculateMetricWeightsForSorting(insightSet, metadata);\n        const observedLcpMicro = Common_exports.getLCP(insightSet)?.value;\n        const observedLcp = observedLcpMicro ? Timing_exports3.microToMilli(observedLcpMicro) : Timing_exports.Milli(0);\n        const observedCls = Common_exports.getCLS(insightSet).value;\n        const observedInpMicro = Common_exports.getINP(insightSet)?.value;\n        const observedInp = observedInpMicro ? Timing_exports3.microToMilli(observedInpMicro) : Timing_exports.Milli(200);\n        const observedLcpScore = observedLcp !== void 0 ? Common_exports.evaluateLCPMetricScore(observedLcp) : void 0;\n        const observedInpScore = Common_exports.evaluateINPMetricScore(observedInp);\n        const observedClsScore = Common_exports.evaluateCLSMetricScore(observedCls);\n        const insightToSortingRank = /* @__PURE__ */ new Map();\n        for (const [name, model2] of Object.entries(insightSet.model)) {\n          const lcp = model2.metricSavings?.LCP ?? 0;\n          const inp = model2.metricSavings?.INP ?? 0;\n          const cls = model2.metricSavings?.CLS ?? 0;\n          const lcpPostSavings = observedLcp !== void 0 ? Math.max(0, observedLcp - lcp) : void 0;\n          const inpPostSavings = Math.max(0, observedInp - inp);\n          const clsPostSavings = Math.max(0, observedCls - cls);\n          let score = 0;\n          if (weights.lcp && lcp && observedLcpScore !== void 0 && lcpPostSavings !== void 0) {\n            score += weights.lcp * (Common_exports.evaluateLCPMetricScore(lcpPostSavings) - observedLcpScore);\n          }\n          if (weights.inp && inp && observedInpScore !== void 0) {\n            score += weights.inp * (Common_exports.evaluateINPMetricScore(inpPostSavings) - observedInpScore);\n          }\n          if (weights.cls && cls && observedClsScore !== void 0) {\n            score += weights.cls * (Common_exports.evaluateCLSMetricScore(clsPostSavings) - observedClsScore);\n          }\n          insightToSortingRank.set(name, score);\n        }\n        const baselineOrderKeys = Object.keys(baselineOrder);\n        const orderedKeys = Object.keys(insightSet.model);\n        orderedKeys.sort((a, b) => {\n          const a1 = baselineOrderKeys.indexOf(a);\n          const b1 = baselineOrderKeys.indexOf(b);\n          if (a1 >= 0 && b1 >= 0) {\n            return a1 - b1;\n          }\n          if (a1 >= 0) {\n            return -1;\n          }\n          if (b1 >= 0) {\n            return 1;\n          }\n          return 0;\n        });\n        orderedKeys.sort((a, b) => (insightToSortingRank.get(b) ?? 0) - (insightToSortingRank.get(a) ?? 0));\n        const newModel = {};\n        for (const key of orderedKeys) {\n          const model2 = insightSet.model[key];\n          newModel[key] = model2;\n        }\n        insightSet.model = newModel;\n      }\n      #computeInsightSet(data31, context) {\n        const logger = context.options.logger;\n        let id, urlString, navigation2;\n        if (context.navigation) {\n          id = context.navigationId;\n          urlString = data31.Meta.finalDisplayUrlByNavigationId.get(context.navigationId) ?? data31.Meta.mainFrameURL;\n          navigation2 = context.navigation;\n        } else {\n          id = TraceEvents_exports.NO_NAVIGATION;\n          urlString = data31.Meta.finalDisplayUrlByNavigationId.get(\"\") ?? data31.Meta.mainFrameURL;\n        }\n        const insightSetModel = {};\n        for (const [name, insight] of Object.entries(_a2.getInsightRunners())) {\n          let model2;\n          try {\n            logger?.start(`insights:${name}`);\n            model2 = insight.generateInsight(data31, context);\n            model2.frameId = context.frameId;\n            const navId = context.navigation?.args.data?.navigationId;\n            if (navId) {\n              model2.navigationId = navId;\n            }\n            model2.createOverlays = () => {\n              return insight.createOverlays(model2);\n            };\n          } catch (err) {\n            model2 = err;\n          } finally {\n            logger?.end(`insights:${name}`);\n          }\n          Object.assign(insightSetModel, { [name]: model2 });\n        }\n        const isNavigation = id === TraceEvents_exports.NO_NAVIGATION;\n        const trivialThreshold = Timing_exports3.milliToMicro(Timing_exports.Milli(5e3));\n        const everyInsightPasses = Object.values(insightSetModel).filter((model2) => !(model2 instanceof Error)).every((model2) => model2.state === \"pass\");\n        const noLcp = !insightSetModel.LCPBreakdown.lcpEvent;\n        const noInp = !insightSetModel.INPBreakdown.longestInteractionEvent;\n        const noLayoutShifts = insightSetModel.CLSCulprits.shifts?.size === 0;\n        const shouldExclude = isNavigation && context.bounds.range < trivialThreshold && everyInsightPasses && noLcp && noInp && noLayoutShifts;\n        if (shouldExclude) {\n          return;\n        }\n        let url;\n        try {\n          url = new URL(urlString);\n        } catch {\n          return;\n        }\n        const insightSet = {\n          id,\n          url,\n          navigation: navigation2,\n          frameId: context.frameId,\n          bounds: context.bounds,\n          model: insightSetModel\n        };\n        if (!this.#insights) {\n          this.#insights = /* @__PURE__ */ new Map();\n        }\n        this.#insights.set(insightSet.id, insightSet);\n        this.sortInsightSet(insightSet, context.options.metadata ?? null);\n      }\n      /**\n       * Run all the insights and set the result to `#insights`.\n       */\n      #computeInsights(data31, traceEvents, options) {\n        this.#insights = /* @__PURE__ */ new Map();\n        const navigations = data31.Meta.mainFrameNavigations.filter((navigation2) => navigation2.args.frame && navigation2.args.data?.navigationId);\n        this.#computeInsightsForInitialTracePeriod(data31, navigations, options);\n        for (const [index, navigation2] of navigations.entries()) {\n          const min = navigation2.ts;\n          const max = index + 1 < navigations.length ? navigations[index + 1].ts : data31.Meta.traceBounds.max;\n          const bounds = Timing_exports3.traceWindowFromMicroSeconds(min, max);\n          this.#computeInsightsForNavigation(navigation2, bounds, data31, traceEvents, options);\n        }\n      }\n      /**\n       * Computes insights for the period before the first navigation, or for the entire trace if no navigations exist.\n       */\n      #computeInsightsForInitialTracePeriod(data31, navigations, options) {\n        const bounds = navigations.length > 0 ? Timing_exports3.traceWindowFromMicroSeconds(data31.Meta.traceBounds.min, navigations[0].ts) : data31.Meta.traceBounds;\n        const context = {\n          options,\n          bounds,\n          frameId: data31.Meta.mainFrameId\n          // No navigation or lantern context applies to this initial/no-navigation period.\n        };\n        this.#computeInsightSet(data31, context);\n      }\n      /**\n       * Computes insights for a specific navigation event.\n       */\n      #computeInsightsForNavigation(navigation2, bounds, data31, traceEvents, options) {\n        const frameId = navigation2.args.frame;\n        const navigationId = navigation2.args.data?.navigationId;\n        let lantern;\n        try {\n          options.logger?.start(\"insights:createLanternContext\");\n          lantern = this.#createLanternContext(data31, traceEvents, frameId, navigationId, options);\n        } catch (e) {\n          const expectedErrors = [\n            \"mainDocumentRequest not found\",\n            \"missing metric scores for main frame\",\n            \"missing metric: FCP\",\n            \"missing metric: LCP\",\n            \"No network requests found in trace\",\n            \"Trace is too old\"\n          ];\n          if (!(e instanceof core_exports.LanternError)) {\n            console.error(e);\n          } else if (!expectedErrors.some((err) => e.message === err)) {\n            console.error(e);\n          }\n        } finally {\n          options.logger?.end(\"insights:createLanternContext\");\n        }\n        const context = {\n          options,\n          bounds,\n          frameId,\n          navigation: navigation2,\n          navigationId,\n          lantern\n        };\n        this.#computeInsightSet(data31, context);\n      }\n    };\n    _a2 = TraceProcessor;\n    __name(sortHandlers, \"sortHandlers\");\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/ModelImpl.js\nvar init_ModelImpl = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/ModelImpl.js\"() {\n    init_process_global();\n    init_platform();\n    init_handlers();\n    init_helpers2();\n    init_Processor();\n    init_types2();\n  }\n});\n\n// node_modules/@paulirish/trace_engine/core/common/common.js\nvar init_common = __esm({\n  \"node_modules/@paulirish/trace_engine/core/common/common.js\"() {\n    init_process_global();\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/Styles.js\nvar EventCategory;\nvar init_Styles = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/Styles.js\"() {\n    init_process_global();\n    init_handlers();\n    init_helpers2();\n    init_types2();\n    (function(EventCategory2) {\n      EventCategory2[\"DRAWING\"] = \"drawing\";\n      EventCategory2[\"RASTERIZING\"] = \"rasterizing\";\n      EventCategory2[\"LAYOUT\"] = \"layout\";\n      EventCategory2[\"LOADING\"] = \"loading\";\n      EventCategory2[\"EXPERIENCE\"] = \"experience\";\n      EventCategory2[\"SCRIPTING\"] = \"scripting\";\n      EventCategory2[\"MESSAGING\"] = \"messaging\";\n      EventCategory2[\"RENDERING\"] = \"rendering\";\n      EventCategory2[\"PAINTING\"] = \"painting\";\n      EventCategory2[\"GPU\"] = \"gpu\";\n      EventCategory2[\"ASYNC\"] = \"async\";\n      EventCategory2[\"OTHER\"] = \"other\";\n      EventCategory2[\"IDLE\"] = \"idle\";\n    })(EventCategory || (EventCategory = {}));\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/Name.js\nvar init_Name = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/Name.js\"() {\n    init_process_global();\n    init_common();\n    init_handlers();\n    init_Styles();\n    init_types2();\n  }\n});\n\n// node_modules/@paulirish/trace_engine/models/trace/trace.js\nvar init_trace2 = __esm({\n  \"node_modules/@paulirish/trace_engine/models/trace/trace.js\"() {\n    init_process_global();\n    init_EntityMapper();\n    init_EventsSerializer();\n    init_extras();\n    init_handlers();\n    init_helpers2();\n    init_insights();\n    init_lantern();\n    init_LanternComputationData();\n    init_ModelImpl();\n    init_Name();\n    init_Processor();\n    init_Styles();\n    init_types2();\n  }\n});\n\n// core/lib/lantern/lantern.js\nvar init_lantern2 = __esm({\n  \"core/lib/lantern/lantern.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_lantern();\n    init_trace2();\n    /**\n     * @license\n     * Copyright 2024 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n  }\n});\n\n// core/lib/tracehouse/trace-processor.js\nvar ACCEPTABLE_NAVIGATION_URL_REGEX, BASE_RESPONSE_LATENCY, SCHEDULABLE_TASK_TITLE_LH2, SCHEDULABLE_TASK_TITLE_ALT12, SCHEDULABLE_TASK_TITLE_ALT22, SCHEDULABLE_TASK_TITLE_ALT32, TraceProcessor2;\nvar init_trace_processor = __esm({\n  \"core/lib/tracehouse/trace-processor.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_lighthouse_logger();\n    /**\n     * @license\n     * Copyright 2017 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    ACCEPTABLE_NAVIGATION_URL_REGEX = /^(chrome|https?):/;\n    BASE_RESPONSE_LATENCY = 16;\n    SCHEDULABLE_TASK_TITLE_LH2 = \"RunTask\";\n    SCHEDULABLE_TASK_TITLE_ALT12 = \"ThreadControllerImpl::RunTask\";\n    SCHEDULABLE_TASK_TITLE_ALT22 = \"ThreadControllerImpl::DoWork\";\n    SCHEDULABLE_TASK_TITLE_ALT32 = \"TaskQueueManager::ProcessTaskFromWorkQueue\";\n    TraceProcessor2 = class _TraceProcessor {\n      static {\n        __name(this, \"TraceProcessor\");\n      }\n      static get TIMESPAN_MARKER_ID() {\n        return \"__lighthouseTimespanStart__\";\n      }\n      /**\n       * @return {Error}\n       */\n      static createNoNavstartError() {\n        return new Error(\"No navigationStart event found\");\n      }\n      /**\n       * @return {Error}\n       */\n      static createNoResourceSendRequestError() {\n        return new Error(\"No ResourceSendRequest event found\");\n      }\n      /**\n       * @return {Error}\n       */\n      static createNoTracingStartedError() {\n        return new Error(\"No tracingStartedInBrowser event found\");\n      }\n      /**\n       * @return {Error}\n       */\n      static createNoFirstContentfulPaintError() {\n        return new Error(\"No FirstContentfulPaint event found\");\n      }\n      /**\n       * @return {Error}\n       */\n      static createNoLighthouseMarkerError() {\n        return new Error(\"No Lighthouse timespan marker event found\");\n      }\n      /**\n       * Returns true if the event is a navigation start event of a document whose URL seems valid.\n       *\n       * @param {LH.TraceEvent} event\n       * @return {boolean}\n       */\n      static _isNavigationStartOfInterest(event) {\n        if (event.name !== \"navigationStart\") return false;\n        if (event.args.data?.documentLoaderURL === void 0) return true;\n        if (!event.args.data?.documentLoaderURL) return false;\n        return ACCEPTABLE_NAVIGATION_URL_REGEX.test(event.args.data.documentLoaderURL);\n      }\n      /**\n       * This method sorts a group of trace events that have the same timestamp. We want to...\n       *\n       * 1. Put E events first, we finish off our existing events before we start new ones.\n       * 2. Order B/X events by their duration, we want parents to start before child events.\n       * 3. If we don't have any of this to go on, just use the position in the original array (stable sort).\n       *\n       * Note that the typical group size with the same timestamp will be quite small (<10 or so events),\n       * and the number of groups typically ~1% of total trace, so the same ultra-performance-sensitive consideration\n       * given to functions that run on entire traces does not necessarily apply here.\n       *\n       * @param {number[]} tsGroupIndices\n       * @param {number[]} timestampSortedIndices\n       * @param {number} indexOfTsGroupIndicesStart\n       * @param {LH.TraceEvent[]} traceEvents\n       * @return {number[]}\n       */\n      static _sortTimestampEventGroup(tsGroupIndices, timestampSortedIndices, indexOfTsGroupIndicesStart, traceEvents) {\n        const lookupArrayIndexByTsIndex = /* @__PURE__ */ __name((i) => timestampSortedIndices[i], \"lookupArrayIndexByTsIndex\");\n        const lookupEventByTsIndex = /* @__PURE__ */ __name((i) => traceEvents[lookupArrayIndexByTsIndex(i)], \"lookupEventByTsIndex\");\n        const eEventIndices = [];\n        const bxEventIndices = [];\n        const otherEventIndices = [];\n        for (const tsIndex of tsGroupIndices) {\n          const arrayIndex = lookupArrayIndexByTsIndex(tsIndex);\n          const event = lookupEventByTsIndex(tsIndex);\n          if (event.ph === \"E\") eEventIndices.push(arrayIndex);\n          else if (event.ph === \"X\" || event.ph === \"B\") bxEventIndices.push(arrayIndex);\n          else otherEventIndices.push(arrayIndex);\n        }\n        const effectiveDuration = /* @__PURE__ */ new Map();\n        for (const index of bxEventIndices) {\n          const event = traceEvents[index];\n          if (event.ph === \"X\") {\n            effectiveDuration.set(index, event.dur);\n          } else {\n            let duration = Number.MAX_SAFE_INTEGER;\n            let additionalNestedEventsWithSameName = 0;\n            const startIndex = indexOfTsGroupIndicesStart + tsGroupIndices.length;\n            for (let j = startIndex; j < timestampSortedIndices.length; j++) {\n              const potentialMatchingEvent = lookupEventByTsIndex(j);\n              const eventMatches = potentialMatchingEvent.name === event.name && potentialMatchingEvent.pid === event.pid && potentialMatchingEvent.tid === event.tid;\n              if (!eventMatches) continue;\n              if (potentialMatchingEvent.ph === \"E\" && additionalNestedEventsWithSameName === 0) {\n                duration = potentialMatchingEvent.ts - event.ts;\n                break;\n              } else if (potentialMatchingEvent.ph === \"E\") {\n                additionalNestedEventsWithSameName--;\n              } else if (potentialMatchingEvent.ph === \"B\") {\n                additionalNestedEventsWithSameName++;\n              }\n            }\n            effectiveDuration.set(index, duration);\n          }\n        }\n        bxEventIndices.sort((indexA, indexB) => (effectiveDuration.get(indexB) || 0) - (effectiveDuration.get(indexA) || 0) || indexA - indexB);\n        otherEventIndices.sort((indexA, indexB) => indexA - indexB);\n        return [...eEventIndices, ...bxEventIndices, ...otherEventIndices];\n      }\n      /**\n       * Sorts and filters trace events by timestamp and respecting the nesting structure inherent to\n       * parent/child event relationships.\n       *\n       * @param {LH.TraceEvent[]} traceEvents\n       * @param {(e: LH.TraceEvent) => boolean} filter\n       */\n      static filteredTraceSort(traceEvents, filter) {\n        const indices = [];\n        for (let srcIndex = 0; srcIndex < traceEvents.length; srcIndex++) {\n          if (filter(traceEvents[srcIndex])) {\n            indices.push(srcIndex);\n          }\n        }\n        indices.sort((indexA, indexB) => traceEvents[indexA].ts - traceEvents[indexB].ts);\n        for (let i = 0; i < indices.length - 1; i++) {\n          const ts = traceEvents[indices[i]].ts;\n          const tsGroupIndices = [i];\n          for (let j = i + 1; j < indices.length; j++) {\n            if (traceEvents[indices[j]].ts !== ts) break;\n            tsGroupIndices.push(j);\n          }\n          if (tsGroupIndices.length === 1) continue;\n          const finalIndexOrder = _TraceProcessor._sortTimestampEventGroup(\n            tsGroupIndices,\n            indices,\n            i,\n            traceEvents\n          );\n          indices.splice(i, finalIndexOrder.length, ...finalIndexOrder);\n          i += tsGroupIndices.length - 1;\n        }\n        const sorted2 = [];\n        for (let i = 0; i < indices.length; i++) {\n          sorted2.push(traceEvents[indices[i]]);\n        }\n        return sorted2;\n      }\n      /**\n       * There should *always* be at least one top level event, having 0 typically means something is\n       * drastically wrong with the trace and we should just give up early and loudly.\n       *\n       * @param {LH.TraceEvent[]} events\n       */\n      static assertHasToplevelEvents(events) {\n        const hasToplevelTask = events.some(this.isScheduleableTask);\n        if (!hasToplevelTask) {\n          throw new Error(\"Could not find any top level events\");\n        }\n      }\n      /**\n       * Calculate duration at specified percentiles for given population of\n       * durations.\n       * If one of the durations overlaps the end of the window, the full\n       * duration should be in the duration array, but the length not included\n       * within the window should be given as `clippedLength`. For instance, if a\n       * 50ms duration occurs 10ms before the end of the window, `50` should be in\n       * the `durations` array, and `clippedLength` should be set to 40.\n       * @see https://docs.google.com/document/d/1b9slyaB9yho91YTOkAQfpCdULFkZM9LqsipcX3t7He8/preview\n       * @param {!Array<number>} durations Array of durations, sorted in ascending order.\n       * @param {number} totalTime Total time (in ms) of interval containing durations.\n       * @param {!Array<number>} percentiles Array of percentiles of interest, in ascending order.\n       * @param {number=} clippedLength Optional length clipped from a duration overlapping end of window. Default of 0.\n       * @return {!Array<{percentile: number, time: number}>}\n       * @private\n       */\n      static _riskPercentiles(durations, totalTime, percentiles, clippedLength = 0) {\n        let busyTime = 0;\n        for (let i = 0; i < durations.length; i++) {\n          busyTime += durations[i];\n        }\n        busyTime -= clippedLength;\n        let completedTime = totalTime - busyTime;\n        let duration = 0;\n        let cdfTime = completedTime;\n        const results = [];\n        let durationIndex = -1;\n        let remainingCount = durations.length + 1;\n        if (clippedLength > 0) {\n          remainingCount--;\n        }\n        for (const percentile of percentiles) {\n          const percentileTime = percentile * totalTime;\n          while (cdfTime < percentileTime && durationIndex < durations.length - 1) {\n            completedTime += duration;\n            remainingCount -= duration < 0 ? -1 : 1;\n            if (clippedLength > 0 && clippedLength < durations[durationIndex + 1]) {\n              duration = -clippedLength;\n              clippedLength = 0;\n            } else {\n              durationIndex++;\n              duration = durations[durationIndex];\n            }\n            cdfTime = completedTime + Math.abs(duration) * remainingCount;\n          }\n          results.push({\n            percentile,\n            time: Math.max(0, (percentileTime - completedTime) / remainingCount) + BASE_RESPONSE_LATENCY\n          });\n        }\n        return results;\n      }\n      /**\n       * Calculates the maximum queueing time (in ms) of high priority tasks for\n       * selected percentiles within a window of the main thread.\n       * @see https://docs.google.com/document/d/1b9slyaB9yho91YTOkAQfpCdULFkZM9LqsipcX3t7He8/preview\n       * @param {Array<ToplevelEvent>} events\n       * @param {number} startTime Start time (in ms relative to timeOrigin) of range of interest.\n       * @param {number} endTime End time (in ms relative to timeOrigin) of range of interest.\n       * @param {!Array<number>=} percentiles Optional array of percentiles to compute. Defaults to [0.5, 0.75, 0.9, 0.99, 1].\n       * @return {!Array<{percentile: number, time: number}>}\n       */\n      static getRiskToResponsiveness(events, startTime, endTime, percentiles = [0.5, 0.75, 0.9, 0.99, 1]) {\n        const totalTime = endTime - startTime;\n        percentiles.sort((a, b) => a - b);\n        const ret = this.getMainThreadTopLevelEventDurations(events, startTime, endTime);\n        return this._riskPercentiles(\n          ret.durations,\n          totalTime,\n          percentiles,\n          ret.clippedLength\n        );\n      }\n      /**\n       * Provides durations in ms of all main thread top-level events\n       * @param {Array<ToplevelEvent>} topLevelEvents\n       * @param {number} startTime Optional start time (in ms relative to timeOrigin) of range of interest. Defaults to 0.\n       * @param {number} endTime Optional end time (in ms relative to timeOrigin) of range of interest. Defaults to trace end.\n       * @return {{durations: Array<number>, clippedLength: number}}\n       */\n      static getMainThreadTopLevelEventDurations(topLevelEvents, startTime = 0, endTime = Infinity) {\n        const durations = [];\n        let clippedLength = 0;\n        for (const event of topLevelEvents) {\n          if (event.end < startTime || event.start > endTime) {\n            continue;\n          }\n          let duration = event.duration;\n          let eventStart = event.start;\n          if (eventStart < startTime) {\n            eventStart = startTime;\n            duration = event.end - startTime;\n          }\n          if (event.end > endTime) {\n            clippedLength = duration - (endTime - eventStart);\n          }\n          durations.push(duration);\n        }\n        durations.sort((a, b) => a - b);\n        return {\n          durations,\n          clippedLength\n        };\n      }\n      /**\n       * Provides the top level events on the main thread with timestamps in ms relative to timeOrigin.\n       * start.\n       * @param {LH.Artifacts.ProcessedTrace} trace\n       * @param {number=} startTime Optional start time (in ms relative to timeOrigin) of range of interest. Defaults to 0.\n       * @param {number=} endTime Optional end time (in ms relative to timeOrigin) of range of interest. Defaults to trace end.\n       * @return {Array<ToplevelEvent>}\n       */\n      static getMainThreadTopLevelEvents(trace, startTime = 0, endTime = Infinity) {\n        const topLevelEvents = [];\n        let prevToplevel = void 0;\n        for (const event of trace.mainThreadEvents) {\n          if (!this.isScheduleableTask(event) || !event.dur) continue;\n          const start = (event.ts - trace.timeOriginEvt.ts) / 1e3;\n          const end = (event.ts + event.dur - trace.timeOriginEvt.ts) / 1e3;\n          if (start > endTime || end < startTime) continue;\n          if (prevToplevel && start < prevToplevel.end) {\n            prevToplevel.end = start - 1e-3;\n          }\n          prevToplevel = {\n            start,\n            end,\n            duration: event.dur / 1e3\n          };\n          topLevelEvents.push(prevToplevel);\n        }\n        return topLevelEvents;\n      }\n      /**\n       * @param {LH.TraceEvent[]} events\n       * @return {{startingPid: number, frameId: string}}\n       */\n      static findMainFrameIds(events) {\n        const startedInBrowserEvt = events.find((e) => e.name === \"TracingStartedInBrowser\");\n        if (startedInBrowserEvt?.args.data?.frames) {\n          const mainFrame = startedInBrowserEvt.args.data.frames.find((frame) => !frame.parent);\n          const frameId = mainFrame?.frame;\n          const pid = mainFrame?.processId;\n          if (pid && frameId) {\n            return {\n              startingPid: pid,\n              frameId\n            };\n          }\n        }\n        const startedInPageEvt = events.find((e) => e.name === \"TracingStartedInPage\");\n        if (startedInPageEvt?.args?.data) {\n          const frameId = startedInPageEvt.args.data.page;\n          if (frameId) {\n            return {\n              startingPid: startedInPageEvt.pid,\n              frameId\n            };\n          }\n        }\n        const navStartEvt = events.find(\n          (e) => this._isNavigationStartOfInterest(e) && e.args.data?.isLoadingMainFrame\n        );\n        const firstResourceSendEvt = events.find((e) => e.name === \"ResourceSendRequest\");\n        if (navStartEvt?.args?.data && firstResourceSendEvt && firstResourceSendEvt.pid === navStartEvt.pid && firstResourceSendEvt.tid === navStartEvt.tid) {\n          const frameId = navStartEvt.args.frame;\n          if (frameId) {\n            return {\n              startingPid: navStartEvt.pid,\n              frameId\n            };\n          }\n        }\n        throw this.createNoTracingStartedError();\n      }\n      /**\n       * If there were any cross-origin navigations, there'll be more than one pid returned\n       * @param {{startingPid: number, frameId: string}} mainFrameInfo\n       * @param {LH.TraceEvent[]} keyEvents\n       * @return {Map<number, number>} Map where keys are process IDs and their values are thread IDs\n       */\n      static findMainFramePidTids(mainFrameInfo, keyEvents) {\n        const frameProcessEvts = keyEvents.filter(\n          (evt) => (\n            // ProcessReadyInBrowser is used when a processID isn't available when the FrameCommittedInBrowser trace event is emitted.\n            // In that case. FrameCommittedInBrowser has no processId, but a processPseudoId. and the ProcessReadyInBrowser event declares the proper processId.\n            (evt.name === \"FrameCommittedInBrowser\" || evt.name === \"ProcessReadyInBrowser\") && evt.args?.data?.frame === mainFrameInfo.frameId && evt?.args?.data?.processId\n          )\n        );\n        const mainFramePids = frameProcessEvts.length ? frameProcessEvts.map((e) => e?.args?.data?.processId) : [mainFrameInfo.startingPid];\n        const pidToTid = /* @__PURE__ */ new Map();\n        for (const pid of new Set(mainFramePids)) {\n          const threadEvents = keyEvents.filter(\n            (e) => e.cat === \"__metadata\" && e.pid === pid && e.ph === \"M\" && e.name === \"thread_name\"\n          );\n          let threadNameEvt = threadEvents.find((e) => e.args.name === \"CrRendererMain\");\n          if (!threadNameEvt) {\n            threadNameEvt = threadEvents.find((e) => e.args.name === \"CrBrowserMain\");\n          }\n          const tid = threadNameEvt?.tid;\n          if (!tid) {\n            throw new Error(\"Unable to determine tid for renderer process\");\n          }\n          pidToTid.set(pid, tid);\n        }\n        return pidToTid;\n      }\n      /**\n       * @param {LH.TraceEvent} evt\n       * @return {boolean}\n       */\n      static isScheduleableTask(evt) {\n        return evt.name === SCHEDULABLE_TASK_TITLE_LH2 || evt.name === SCHEDULABLE_TASK_TITLE_ALT12 || evt.name === SCHEDULABLE_TASK_TITLE_ALT22 || evt.name === SCHEDULABLE_TASK_TITLE_ALT32;\n      }\n      /**\n       * @param {LH.TraceEvent} evt\n       * @return {evt is LCPEvent}\n       */\n      static isLCPEvent(evt) {\n        if (evt.name !== \"largestContentfulPaint::Invalidate\" && evt.name !== \"largestContentfulPaint::Candidate\") return false;\n        return Boolean(evt.args?.frame);\n      }\n      /**\n       * @param {LH.TraceEvent} evt\n       * @return {evt is LCPCandidateEvent}\n       */\n      static isLCPCandidateEvent(evt) {\n        return Boolean(\n          evt.name === \"largestContentfulPaint::Candidate\" && evt.args?.frame && evt.args.data && evt.args.data.size !== void 0\n        );\n      }\n      /**\n       * The associated frame ID is set in different locations for different trace events.\n       * This function checks all known locations for the frame ID and returns `undefined` if it's not found.\n       *\n       * @param {LH.TraceEvent} evt\n       * @return {string|undefined}\n       */\n      static getFrameId(evt) {\n        return evt.args?.data?.frame || evt.args.data?.frameID || evt.args.frame;\n      }\n      /**\n       * Returns the maximum LCP event across all frames in `events`.\n       * Sets `invalidated` flag if LCP of every frame is invalidated.\n       *\n       * LCP's trace event was first introduced in m78. We can't surface an LCP for older Chrome versions.\n       * LCP comes from a frame's latest `largestContentfulPaint::Candidate`, but it can be invalidated by a `largestContentfulPaint::Invalidate` event.\n       *\n       * @param {LH.TraceEvent[]} events\n       * @param {LH.TraceEvent} timeOriginEvent\n       * @return {{lcp: LCPEvent | undefined, invalidated: boolean}}\n       */\n      static computeValidLCPAllFrames(events, timeOriginEvent) {\n        const lcpEvents = events.filter(this.isLCPEvent).reverse();\n        const finalLcpEventsByFrame = /* @__PURE__ */ new Map();\n        for (const e of lcpEvents) {\n          if (e.ts <= timeOriginEvent.ts) break;\n          const frame = e.args.frame;\n          if (finalLcpEventsByFrame.has(frame)) continue;\n          finalLcpEventsByFrame.set(frame, e);\n        }\n        let maxLcpAcrossFrames;\n        for (const lcp of finalLcpEventsByFrame.values()) {\n          if (!this.isLCPCandidateEvent(lcp)) continue;\n          if (!maxLcpAcrossFrames || lcp.args.data.size > maxLcpAcrossFrames.args.data.size) {\n            maxLcpAcrossFrames = lcp;\n          }\n        }\n        return {\n          lcp: maxLcpAcrossFrames,\n          // LCP events were found, but final LCP event of every frame was an invalidate event.\n          invalidated: Boolean(!maxLcpAcrossFrames && finalLcpEventsByFrame.size)\n        };\n      }\n      /**\n       * @param {Array<{id: string, url: string, parent?: string}>} frames\n       * @return {Map<string, string>}\n       */\n      static resolveRootFrames(frames2) {\n        const parentFrames = /* @__PURE__ */ new Map();\n        for (const frame of frames2) {\n          if (!frame.parent) continue;\n          parentFrames.set(frame.id, frame.parent);\n        }\n        const frameIdToRootFrameId = /* @__PURE__ */ new Map();\n        for (const frame of frames2) {\n          let cur = frame.id;\n          while (parentFrames.has(cur)) {\n            cur = /** @type {string} */\n            parentFrames.get(cur);\n          }\n          if (cur === void 0) {\n            throw new Error(\"Unexpected undefined frameId\");\n          }\n          frameIdToRootFrameId.set(frame.id, cur);\n        }\n        return frameIdToRootFrameId;\n      }\n      /**\n       * Finds key trace events, identifies main process/thread, and returns timings of trace events\n       * in milliseconds since the time origin in addition to the standard microsecond monotonic timestamps.\n       * @param {LH.Trace} trace\n       * @param {{timeOriginDeterminationMethod?: TimeOriginDeterminationMethod}} [options]\n       * @return {LH.Artifacts.ProcessedTrace}\n      */\n      static processTrace(trace, options) {\n        const { timeOriginDeterminationMethod = \"auto\" } = options || {};\n        const keyEvents = this.filteredTraceSort(trace.traceEvents, (e) => {\n          return e.cat.includes(\"blink.user_timing\") || e.cat.includes(\"loading\") || e.cat.includes(\"devtools.timeline\") || e.cat === \"__metadata\";\n        });\n        const mainFrameInfo = this.findMainFrameIds(keyEvents);\n        const rendererPidToTid = this.findMainFramePidTids(mainFrameInfo, keyEvents);\n        const processEvents = _TraceProcessor.filteredTraceSort(trace.traceEvents, (e) => rendererPidToTid.has(e.pid));\n        const framesById = /* @__PURE__ */ new Map();\n        const tracingStartedFrames = keyEvents.find((e) => e.name === \"TracingStartedInBrowser\")?.args?.data?.frames;\n        if (tracingStartedFrames) {\n          for (const frame of tracingStartedFrames) {\n            framesById.set(frame.frame, {\n              id: frame.frame,\n              url: frame.url,\n              parent: frame.parent\n            });\n          }\n        }\n        keyEvents.filter(\n          /** @return {evt is FrameCommittedEvent} */\n          (evt) => {\n            return Boolean(\n              evt.name === \"FrameCommittedInBrowser\" && evt.args.data?.frame && evt.args.data.url !== void 0\n            );\n          }\n        ).forEach((evt) => {\n          framesById.set(evt.args.data.frame, {\n            id: evt.args.data.frame,\n            url: evt.args.data.url,\n            parent: evt.args.data.parent\n          });\n        });\n        const frames2 = [...framesById.values()];\n        const frameIdToRootFrameId = this.resolveRootFrames(frames2);\n        const inspectedTreeFrameIds = [...frameIdToRootFrameId.entries()].filter(([, rootFrameId]) => rootFrameId === mainFrameInfo.frameId).map(([child]) => child);\n        function associatedToMainFrame(e) {\n          const frameId = _TraceProcessor.getFrameId(e);\n          return frameId === mainFrameInfo.frameId;\n        }\n        __name(associatedToMainFrame, \"associatedToMainFrame\");\n        function associatedToAllFrames(e) {\n          const frameId = _TraceProcessor.getFrameId(e);\n          return frameId ? inspectedTreeFrameIds.includes(frameId) : false;\n        }\n        __name(associatedToAllFrames, \"associatedToAllFrames\");\n        const frameEvents = keyEvents.filter((e) => associatedToMainFrame(e));\n        let frameTreeEvents = [];\n        if (frameIdToRootFrameId.has(mainFrameInfo.frameId)) {\n          frameTreeEvents = keyEvents.filter((e) => associatedToAllFrames(e));\n        } else {\n          lighthouse_logger_default.warn(\n            \"TraceProcessor\",\n            \"frameTreeEvents may be incomplete, make sure the trace has frame events\"\n          );\n          frameIdToRootFrameId.set(mainFrameInfo.frameId, mainFrameInfo.frameId);\n          frameTreeEvents = frameEvents;\n        }\n        const timeOriginEvt = this.computeTimeOrigin(\n          { keyEvents, frameEvents, mainFrameInfo },\n          timeOriginDeterminationMethod\n        );\n        const mainThreadEvents = processEvents.filter((e) => e.tid === rendererPidToTid.get(e.pid));\n        const traceEnd = this.computeTraceEnd(trace.traceEvents, timeOriginEvt);\n        return {\n          frames: frames2,\n          mainThreadEvents,\n          frameEvents,\n          frameTreeEvents,\n          processEvents,\n          mainFrameInfo,\n          timeOriginEvt,\n          timings: {\n            timeOrigin: 0,\n            traceEnd: traceEnd.timing\n          },\n          timestamps: {\n            timeOrigin: timeOriginEvt.ts,\n            traceEnd: traceEnd.timestamp\n          },\n          _keyEvents: keyEvents,\n          _rendererPidToTid: rendererPidToTid\n        };\n      }\n      /**\n       * Finds key navigation trace events and computes timings of events in milliseconds since the time\n       * origin in addition to the standard microsecond monotonic timestamps.\n       * @param {LH.Artifacts.ProcessedTrace} processedTrace\n       * @return {LH.Artifacts.ProcessedNavigation}\n      */\n      static processNavigation(processedTrace) {\n        const { frameEvents, frameTreeEvents, timeOriginEvt, timings, timestamps } = processedTrace;\n        const frameTimings = this.computeNavigationTimingsForFrame(frameEvents, { timeOriginEvt });\n        const fcpAllFramesEvt = frameTreeEvents.find(\n          (e) => e.name === \"firstContentfulPaint\" && e.ts > timeOriginEvt.ts\n        );\n        if (!fcpAllFramesEvt) {\n          throw this.createNoFirstContentfulPaintError();\n        }\n        const lcpAllFramesEvt = this.computeValidLCPAllFrames(frameTreeEvents, timeOriginEvt).lcp;\n        const getTiming = /* @__PURE__ */ __name((ts) => (ts - timeOriginEvt.ts) / 1e3, \"getTiming\");\n        const maybeGetTiming = /* @__PURE__ */ __name((ts) => ts === void 0 ? void 0 : getTiming(ts), \"maybeGetTiming\");\n        return {\n          timings: {\n            timeOrigin: timings.timeOrigin,\n            firstPaint: frameTimings.timings.firstPaint,\n            firstContentfulPaint: frameTimings.timings.firstContentfulPaint,\n            firstContentfulPaintAllFrames: getTiming(fcpAllFramesEvt.ts),\n            largestContentfulPaint: frameTimings.timings.largestContentfulPaint,\n            largestContentfulPaintAllFrames: maybeGetTiming(lcpAllFramesEvt?.ts),\n            load: frameTimings.timings.load,\n            domContentLoaded: frameTimings.timings.domContentLoaded,\n            traceEnd: timings.traceEnd\n          },\n          timestamps: {\n            timeOrigin: timestamps.timeOrigin,\n            firstPaint: frameTimings.timestamps.firstPaint,\n            firstContentfulPaint: frameTimings.timestamps.firstContentfulPaint,\n            firstContentfulPaintAllFrames: fcpAllFramesEvt.ts,\n            largestContentfulPaint: frameTimings.timestamps.largestContentfulPaint,\n            largestContentfulPaintAllFrames: lcpAllFramesEvt?.ts,\n            load: frameTimings.timestamps.load,\n            domContentLoaded: frameTimings.timestamps.domContentLoaded,\n            traceEnd: timestamps.traceEnd\n          },\n          firstPaintEvt: frameTimings.firstPaintEvt,\n          firstContentfulPaintEvt: frameTimings.firstContentfulPaintEvt,\n          firstContentfulPaintAllFramesEvt: fcpAllFramesEvt,\n          largestContentfulPaintEvt: frameTimings.largestContentfulPaintEvt,\n          largestContentfulPaintAllFramesEvt: lcpAllFramesEvt,\n          loadEvt: frameTimings.loadEvt,\n          domContentLoadedEvt: frameTimings.domContentLoadedEvt,\n          lcpInvalidated: frameTimings.lcpInvalidated\n        };\n      }\n      /**\n       * Computes the last observable timestamp in a set of trace events.\n       *\n       * @param {Array<LH.TraceEvent>} events\n       * @param {LH.TraceEvent} timeOriginEvt\n       * @return {{timing: number, timestamp: number}}\n       */\n      static computeTraceEnd(events, timeOriginEvt) {\n        let maxTs = -Infinity;\n        for (const event of events) {\n          maxTs = Math.max(event.ts + (event.dur || 0), maxTs);\n        }\n        return { timestamp: maxTs, timing: (maxTs - timeOriginEvt.ts) / 1e3 };\n      }\n      /**\n       * Computes the time origin using the specified method.\n       *\n       *    - firstResourceSendRequest\n       *      Uses the time that the very first network request is sent in the main frame.\n       *      Eventually should be used in place of lastNavigationStart as the default for navigations.\n       *      This method includes the cost of all redirects when evaluating a navigation (which matches lantern behavior).\n       *      The only difference between firstResourceSendRequest and the first `navigationStart` is\n       *      the unload time of `about:blank` (which is a Lighthouse implementation detail and shouldn't be included).\n       *\n       *    - lastNavigationStart\n       *      Uses the time of the last `navigationStart` event in the main frame.\n       *      The historical time origin of Lighthouse from 2016-Present.\n       *      This method excludes the cost of client-side redirects when evaluating a navigation.\n       *      Can also be skewed by several hundred milliseconds or even seconds when the browser takes a long\n       *      time to unload `about:blank`.\n       *\n       * @param {{keyEvents: Array<LH.TraceEvent>, frameEvents: Array<LH.TraceEvent>, mainFrameInfo: {frameId: string}}} traceEventSubsets\n       * @param {TimeOriginDeterminationMethod} method\n       * @return {LH.TraceEvent}\n       */\n      static computeTimeOrigin(traceEventSubsets, method) {\n        const lastNavigationStart = /* @__PURE__ */ __name(() => {\n          const frameEvents = traceEventSubsets.frameEvents;\n          return frameEvents.filter(this._isNavigationStartOfInterest).pop();\n        }, \"lastNavigationStart\");\n        const lighthouseMarker = /* @__PURE__ */ __name(() => {\n          const frameEvents = traceEventSubsets.keyEvents;\n          return frameEvents.find(\n            (evt) => evt.name === \"clock_sync\" && evt.args.sync_id === _TraceProcessor.TIMESPAN_MARKER_ID\n          );\n        }, \"lighthouseMarker\");\n        switch (method) {\n          case \"firstResourceSendRequest\": {\n            const fetchStart = traceEventSubsets.keyEvents.find((event) => {\n              if (event.name !== \"ResourceSendRequest\") return false;\n              const data31 = event.args.data || {};\n              return data31.frame === traceEventSubsets.mainFrameInfo.frameId;\n            });\n            if (!fetchStart) throw this.createNoResourceSendRequestError();\n            return fetchStart;\n          }\n          case \"lastNavigationStart\": {\n            const navigationStart = lastNavigationStart();\n            if (!navigationStart) throw this.createNoNavstartError();\n            return navigationStart;\n          }\n          case \"lighthouseMarker\": {\n            const marker = lighthouseMarker();\n            if (!marker) throw this.createNoLighthouseMarkerError();\n            return marker;\n          }\n          case \"auto\": {\n            const marker = lighthouseMarker() || lastNavigationStart();\n            if (!marker) throw this.createNoNavstartError();\n            return marker;\n          }\n        }\n      }\n      /**\n       * Computes timings of trace events of key trace events in milliseconds since the time origin\n       * in addition to the standard microsecond monotonic timestamps.\n       * @param {Array<LH.TraceEvent>} frameEvents\n       * @param {{timeOriginEvt: LH.TraceEvent}} options\n      */\n      static computeNavigationTimingsForFrame(frameEvents, options) {\n        const { timeOriginEvt } = options;\n        const firstPaint = frameEvents.find((e) => e.name === \"firstPaint\" && e.ts > timeOriginEvt.ts);\n        const firstContentfulPaint = frameEvents.find(\n          (e) => e.name === \"firstContentfulPaint\" && e.ts > timeOriginEvt.ts\n        );\n        if (!firstContentfulPaint) {\n          throw this.createNoFirstContentfulPaintError();\n        }\n        const lcpResult = this.computeValidLCPAllFrames(frameEvents, timeOriginEvt);\n        const load = frameEvents.find((e) => e.name === \"loadEventEnd\" && e.ts > timeOriginEvt.ts);\n        const domContentLoaded = frameEvents.find(\n          (e) => e.name === \"domContentLoadedEventEnd\" && e.ts > timeOriginEvt.ts\n        );\n        const getTimestamp = /* @__PURE__ */ __name((event) => event?.ts, \"getTimestamp\");\n        const timestamps = {\n          timeOrigin: timeOriginEvt.ts,\n          firstPaint: getTimestamp(firstPaint),\n          firstContentfulPaint: firstContentfulPaint.ts,\n          largestContentfulPaint: getTimestamp(lcpResult.lcp),\n          load: getTimestamp(load),\n          domContentLoaded: getTimestamp(domContentLoaded)\n        };\n        const getTiming = /* @__PURE__ */ __name((ts) => (ts - timeOriginEvt.ts) / 1e3, \"getTiming\");\n        const maybeGetTiming = /* @__PURE__ */ __name((ts) => ts === void 0 ? void 0 : getTiming(ts), \"maybeGetTiming\");\n        const timings = {\n          timeOrigin: 0,\n          firstPaint: maybeGetTiming(timestamps.firstPaint),\n          firstContentfulPaint: getTiming(timestamps.firstContentfulPaint),\n          largestContentfulPaint: maybeGetTiming(timestamps.largestContentfulPaint),\n          load: maybeGetTiming(timestamps.load),\n          domContentLoaded: maybeGetTiming(timestamps.domContentLoaded)\n        };\n        return {\n          timings,\n          timestamps,\n          timeOriginEvt,\n          firstPaintEvt: firstPaint,\n          firstContentfulPaintEvt: firstContentfulPaint,\n          largestContentfulPaintEvt: lcpResult.lcp,\n          loadEvt: load,\n          domContentLoadedEvt: domContentLoaded,\n          lcpInvalidated: lcpResult.invalidated\n        };\n      }\n    };\n  }\n});\n\n// core/lib/arbitrary-equality-map.js\nvar ArbitraryEqualityMap;\nvar init_arbitrary_equality_map = __esm({\n  \"core/lib/arbitrary-equality-map.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_lodash();\n    /**\n     * @license\n     * Copyright 2018 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    ArbitraryEqualityMap = class _ArbitraryEqualityMap {\n      static {\n        __name(this, \"ArbitraryEqualityMap\");\n      }\n      constructor() {\n        this._equalsFn = _ArbitraryEqualityMap.deepEquals;\n        this._entries = [];\n      }\n      /**\n       * @param {function(*,*):boolean} equalsFn\n       */\n      setEqualityFn(equalsFn) {\n        this._equalsFn = equalsFn;\n      }\n      /**\n       * @param {*} key\n       * @return {boolean}\n       */\n      has(key) {\n        return this._findIndexOf(key) !== -1;\n      }\n      /**\n       * @param {*} key\n       * @return {*}\n       */\n      get(key) {\n        const entry = this._entries[this._findIndexOf(key)];\n        return entry?.value;\n      }\n      /**\n       * @param {*} key\n       * @param {*} value\n       */\n      set(key, value) {\n        let index = this._findIndexOf(key);\n        if (index === -1) index = this._entries.length;\n        this._entries[index] = { key, value };\n      }\n      /**\n       * @param {*} key\n       * @return {number}\n       */\n      _findIndexOf(key) {\n        for (let i = 0; i < this._entries.length; i++) {\n          if (this._equalsFn(key, this._entries[i].key)) return i;\n        }\n        return -1;\n      }\n      /**\n       * Determines whether two objects are deeply equal. Defers to lodash isEqual, but is kept here for\n       * easy usage by consumers.\n       * See https://lodash.com/docs/4.17.5#isEqual.\n       * @param {*} objA\n       * @param {*} objB\n       * @return {boolean}\n       */\n      static deepEquals(objA, objB) {\n        return isEqual_default(objA, objB);\n      }\n    };\n  }\n});\n\n// core/computed/computed-artifact.js\nfunction makeComputedArtifact(computableArtifact, keys2) {\n  const request = /* @__PURE__ */ __name((dependencies, context) => {\n    const computedName = computableArtifact.name;\n    for (const key of keys2 || []) {\n      if (dependencies && typeof dependencies === \"object\" && dependencies[key] === void 0) {\n        const err = new Error(`missing required key \"${String(key)}\" for computed artifact ${computableArtifact.name}`);\n        if (isUnderTest) {\n          throw err;\n        } else {\n          lighthouse_logger_default.error(`lh:computed:${computedName}`, err);\n        }\n      }\n    }\n    const pickedDependencies = keys2 ? Object.fromEntries(keys2.map((key) => [key, dependencies[key]])) : dependencies;\n    const computedCache = (\n      /** @type {Map<string, ArbitraryEqualityMap>} */\n      context.computedCache\n    );\n    const cache = computedCache.get(computedName) || new ArbitraryEqualityMap();\n    computedCache.set(computedName, cache);\n    const computed = cache.get(pickedDependencies);\n    if (computed) {\n      return computed;\n    }\n    const status = { msg: `Computing artifact: ${computedName}`, id: `lh:computed:${computedName}` };\n    lighthouse_logger_default.time(status, \"verbose\");\n    const artifactPromise = (\n      /** @type {ReturnType<C['compute_']>} */\n      computableArtifact.compute_(pickedDependencies, context)\n    );\n    cache.set(pickedDependencies, artifactPromise);\n    artifactPromise.then(() => lighthouse_logger_default.timeEnd(status)).catch(() => lighthouse_logger_default.timeEnd(status));\n    return artifactPromise;\n  }, \"request\");\n  return Object.assign(computableArtifact, { request });\n}\nvar init_computed_artifact = __esm({\n  \"core/computed/computed-artifact.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_lighthouse_logger();\n    init_arbitrary_equality_map();\n    init_lh_env();\n    /**\n     * @license\n     * Copyright 2018 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    __name(makeComputedArtifact, \"makeComputedArtifact\");\n  }\n});\n\n// node_modules/tldts-icann/dist/cjs/index.js\nvar require_cjs = __commonJS({\n  \"node_modules/tldts-icann/dist/cjs/index.js\"(exports2) {\n    \"use strict\";\n    init_process_global();\n    function shareSameDomainSuffix(hostname, vhost) {\n      if (hostname.endsWith(vhost)) {\n        return hostname.length === vhost.length || hostname[hostname.length - vhost.length - 1] === \".\";\n      }\n      return false;\n    }\n    __name(shareSameDomainSuffix, \"shareSameDomainSuffix\");\n    function extractDomainWithSuffix(hostname, publicSuffix) {\n      const publicSuffixIndex = hostname.length - publicSuffix.length - 2;\n      const lastDotBeforeSuffixIndex = hostname.lastIndexOf(\".\", publicSuffixIndex);\n      if (lastDotBeforeSuffixIndex === -1) {\n        return hostname;\n      }\n      return hostname.slice(lastDotBeforeSuffixIndex + 1);\n    }\n    __name(extractDomainWithSuffix, \"extractDomainWithSuffix\");\n    function getDomain$1(suffix, hostname, options) {\n      if (options.validHosts !== null) {\n        const validHosts = options.validHosts;\n        for (const vhost of validHosts) {\n          if (\n            /*@__INLINE__*/\n            shareSameDomainSuffix(hostname, vhost)\n          ) {\n            return vhost;\n          }\n        }\n      }\n      let numberOfLeadingDots = 0;\n      if (hostname.startsWith(\".\")) {\n        while (numberOfLeadingDots < hostname.length && hostname[numberOfLeadingDots] === \".\") {\n          numberOfLeadingDots += 1;\n        }\n      }\n      if (suffix.length === hostname.length - numberOfLeadingDots) {\n        return null;\n      }\n      return (\n        /*@__INLINE__*/\n        extractDomainWithSuffix(hostname, suffix)\n      );\n    }\n    __name(getDomain$1, \"getDomain$1\");\n    function getDomainWithoutSuffix$1(domain, suffix) {\n      return domain.slice(0, -suffix.length - 1);\n    }\n    __name(getDomainWithoutSuffix$1, \"getDomainWithoutSuffix$1\");\n    function extractHostname(url, urlIsValidHostname) {\n      let start = 0;\n      let end = url.length;\n      let hasUpper = false;\n      if (!urlIsValidHostname) {\n        if (url.startsWith(\"data:\")) {\n          return null;\n        }\n        while (start < url.length && url.charCodeAt(start) <= 32) {\n          start += 1;\n        }\n        while (end > start + 1 && url.charCodeAt(end - 1) <= 32) {\n          end -= 1;\n        }\n        if (url.charCodeAt(start) === 47 && url.charCodeAt(start + 1) === 47) {\n          start += 2;\n        } else {\n          const indexOfProtocol = url.indexOf(\":/\", start);\n          if (indexOfProtocol !== -1) {\n            const protocolSize = indexOfProtocol - start;\n            const c0 = url.charCodeAt(start);\n            const c1 = url.charCodeAt(start + 1);\n            const c2 = url.charCodeAt(start + 2);\n            const c3 = url.charCodeAt(start + 3);\n            const c4 = url.charCodeAt(start + 4);\n            if (protocolSize === 5 && c0 === 104 && c1 === 116 && c2 === 116 && c3 === 112 && c4 === 115) ;\n            else if (protocolSize === 4 && c0 === 104 && c1 === 116 && c2 === 116 && c3 === 112) ;\n            else if (protocolSize === 3 && c0 === 119 && c1 === 115 && c2 === 115) ;\n            else if (protocolSize === 2 && c0 === 119 && c1 === 115) ;\n            else {\n              for (let i = start; i < indexOfProtocol; i += 1) {\n                const lowerCaseCode = url.charCodeAt(i) | 32;\n                if (!(lowerCaseCode >= 97 && lowerCaseCode <= 122 || // [a, z]\n                lowerCaseCode >= 48 && lowerCaseCode <= 57 || // [0, 9]\n                lowerCaseCode === 46 || // '.'\n                lowerCaseCode === 45 || // '-'\n                lowerCaseCode === 43)) {\n                  return null;\n                }\n              }\n            }\n            start = indexOfProtocol + 2;\n            while (url.charCodeAt(start) === 47) {\n              start += 1;\n            }\n          }\n        }\n        let indexOfIdentifier = -1;\n        let indexOfClosingBracket = -1;\n        let indexOfPort = -1;\n        for (let i = start; i < end; i += 1) {\n          const code = url.charCodeAt(i);\n          if (code === 35 || // '#'\n          code === 47 || // '/'\n          code === 63) {\n            end = i;\n            break;\n          } else if (code === 64) {\n            indexOfIdentifier = i;\n          } else if (code === 93) {\n            indexOfClosingBracket = i;\n          } else if (code === 58) {\n            indexOfPort = i;\n          } else if (code >= 65 && code <= 90) {\n            hasUpper = true;\n          }\n        }\n        if (indexOfIdentifier !== -1 && indexOfIdentifier > start && indexOfIdentifier < end) {\n          start = indexOfIdentifier + 1;\n        }\n        if (url.charCodeAt(start) === 91) {\n          if (indexOfClosingBracket !== -1) {\n            return url.slice(start + 1, indexOfClosingBracket).toLowerCase();\n          }\n          return null;\n        } else if (indexOfPort !== -1 && indexOfPort > start && indexOfPort < end) {\n          end = indexOfPort;\n        }\n      }\n      while (end > start + 1 && url.charCodeAt(end - 1) === 46) {\n        end -= 1;\n      }\n      const hostname = start !== 0 || end !== url.length ? url.slice(start, end) : url;\n      if (hasUpper) {\n        return hostname.toLowerCase();\n      }\n      return hostname;\n    }\n    __name(extractHostname, \"extractHostname\");\n    function isProbablyIpv4(hostname) {\n      if (hostname.length < 7) {\n        return false;\n      }\n      if (hostname.length > 15) {\n        return false;\n      }\n      let numberOfDots = 0;\n      for (let i = 0; i < hostname.length; i += 1) {\n        const code = hostname.charCodeAt(i);\n        if (code === 46) {\n          numberOfDots += 1;\n        } else if (code < 48 || code > 57) {\n          return false;\n        }\n      }\n      return numberOfDots === 3 && hostname.charCodeAt(0) !== 46 && hostname.charCodeAt(hostname.length - 1) !== 46;\n    }\n    __name(isProbablyIpv4, \"isProbablyIpv4\");\n    function isProbablyIpv6(hostname) {\n      if (hostname.length < 3) {\n        return false;\n      }\n      let start = hostname.startsWith(\"[\") ? 1 : 0;\n      let end = hostname.length;\n      if (hostname[end - 1] === \"]\") {\n        end -= 1;\n      }\n      if (end - start > 39) {\n        return false;\n      }\n      let hasColon = false;\n      for (; start < end; start += 1) {\n        const code = hostname.charCodeAt(start);\n        if (code === 58) {\n          hasColon = true;\n        } else if (!(code >= 48 && code <= 57 || // 0-9\n        code >= 97 && code <= 102 || // a-f\n        code >= 65 && code <= 90)) {\n          return false;\n        }\n      }\n      return hasColon;\n    }\n    __name(isProbablyIpv6, \"isProbablyIpv6\");\n    function isIp(hostname) {\n      return isProbablyIpv6(hostname) || isProbablyIpv4(hostname);\n    }\n    __name(isIp, \"isIp\");\n    function isValidAscii(code) {\n      return code >= 97 && code <= 122 || code >= 48 && code <= 57 || code > 127;\n    }\n    __name(isValidAscii, \"isValidAscii\");\n    function isValidHostname(hostname) {\n      if (hostname.length > 255) {\n        return false;\n      }\n      if (hostname.length === 0) {\n        return false;\n      }\n      if (\n        /*@__INLINE__*/\n        !isValidAscii(hostname.charCodeAt(0)) && hostname.charCodeAt(0) !== 46 && // '.' (dot)\n        hostname.charCodeAt(0) !== 95\n      ) {\n        return false;\n      }\n      let lastDotIndex = -1;\n      let lastCharCode = -1;\n      const len = hostname.length;\n      for (let i = 0; i < len; i += 1) {\n        const code = hostname.charCodeAt(i);\n        if (code === 46) {\n          if (\n            // Check that previous label is < 63 bytes long (64 = 63 + '.')\n            i - lastDotIndex > 64 || // Check that previous character was not already a '.'\n            lastCharCode === 46 || // Check that the previous label does not end with a '-' (dash)\n            lastCharCode === 45 || // Check that the previous label does not end with a '_' (underscore)\n            lastCharCode === 95\n          ) {\n            return false;\n          }\n          lastDotIndex = i;\n        } else if (!/*@__INLINE__*/\n        (isValidAscii(code) || code === 45 || code === 95)) {\n          return false;\n        }\n        lastCharCode = code;\n      }\n      return (\n        // Check that last label is shorter than 63 chars\n        len - lastDotIndex - 1 <= 63 && // Check that the last character is an allowed trailing label character.\n        // Since we already checked that the char is a valid hostname character,\n        // we only need to check that it's different from '-'.\n        lastCharCode !== 45\n      );\n    }\n    __name(isValidHostname, \"isValidHostname\");\n    function setDefaultsImpl({ allowIcannDomains = true, allowPrivateDomains = false, detectIp = true, extractHostname: extractHostname2 = true, mixedInputs = true, validHosts = null, validateHostname = true }) {\n      return {\n        allowIcannDomains,\n        allowPrivateDomains,\n        detectIp,\n        extractHostname: extractHostname2,\n        mixedInputs,\n        validHosts,\n        validateHostname\n      };\n    }\n    __name(setDefaultsImpl, \"setDefaultsImpl\");\n    var DEFAULT_OPTIONS = (\n      /*@__INLINE__*/\n      setDefaultsImpl({})\n    );\n    function setDefaults(options) {\n      if (options === void 0) {\n        return DEFAULT_OPTIONS;\n      }\n      return (\n        /*@__INLINE__*/\n        setDefaultsImpl(options)\n      );\n    }\n    __name(setDefaults, \"setDefaults\");\n    function getSubdomain$1(hostname, domain) {\n      if (domain.length === hostname.length) {\n        return \"\";\n      }\n      return hostname.slice(0, -domain.length - 1);\n    }\n    __name(getSubdomain$1, \"getSubdomain$1\");\n    function getEmptyResult() {\n      return {\n        domain: null,\n        domainWithoutSuffix: null,\n        hostname: null,\n        isIcann: null,\n        isIp: null,\n        isPrivate: null,\n        publicSuffix: null,\n        subdomain: null\n      };\n    }\n    __name(getEmptyResult, \"getEmptyResult\");\n    function resetResult(result) {\n      result.domain = null;\n      result.domainWithoutSuffix = null;\n      result.hostname = null;\n      result.isIcann = null;\n      result.isIp = null;\n      result.isPrivate = null;\n      result.publicSuffix = null;\n      result.subdomain = null;\n    }\n    __name(resetResult, \"resetResult\");\n    function parseImpl(url, step, suffixLookup2, partialOptions, result) {\n      const options = (\n        /*@__INLINE__*/\n        setDefaults(partialOptions)\n      );\n      if (typeof url !== \"string\") {\n        return result;\n      }\n      if (!options.extractHostname) {\n        result.hostname = url;\n      } else if (options.mixedInputs) {\n        result.hostname = extractHostname(url, isValidHostname(url));\n      } else {\n        result.hostname = extractHostname(url, false);\n      }\n      if (options.detectIp && result.hostname !== null) {\n        result.isIp = isIp(result.hostname);\n        if (result.isIp) {\n          return result;\n        }\n      }\n      if (options.validateHostname && options.extractHostname && result.hostname !== null && !isValidHostname(result.hostname)) {\n        result.hostname = null;\n        return result;\n      }\n      if (step === 0 || result.hostname === null) {\n        return result;\n      }\n      suffixLookup2(result.hostname, options, result);\n      if (step === 2 || result.publicSuffix === null) {\n        return result;\n      }\n      result.domain = getDomain$1(result.publicSuffix, result.hostname, options);\n      if (step === 3 || result.domain === null) {\n        return result;\n      }\n      result.subdomain = getSubdomain$1(result.hostname, result.domain);\n      if (step === 4) {\n        return result;\n      }\n      result.domainWithoutSuffix = getDomainWithoutSuffix$1(result.domain, result.publicSuffix);\n      return result;\n    }\n    __name(parseImpl, \"parseImpl\");\n    function fastPathLookup(hostname, options, out) {\n      if (!options.allowPrivateDomains && hostname.length > 3) {\n        const last = hostname.length - 1;\n        const c3 = hostname.charCodeAt(last);\n        const c2 = hostname.charCodeAt(last - 1);\n        const c1 = hostname.charCodeAt(last - 2);\n        const c0 = hostname.charCodeAt(last - 3);\n        if (c3 === 109 && c2 === 111 && c1 === 99 && c0 === 46) {\n          out.isIcann = true;\n          out.isPrivate = false;\n          out.publicSuffix = \"com\";\n          return true;\n        } else if (c3 === 103 && c2 === 114 && c1 === 111 && c0 === 46) {\n          out.isIcann = true;\n          out.isPrivate = false;\n          out.publicSuffix = \"org\";\n          return true;\n        } else if (c3 === 117 && c2 === 100 && c1 === 101 && c0 === 46) {\n          out.isIcann = true;\n          out.isPrivate = false;\n          out.publicSuffix = \"edu\";\n          return true;\n        } else if (c3 === 118 && c2 === 111 && c1 === 103 && c0 === 46) {\n          out.isIcann = true;\n          out.isPrivate = false;\n          out.publicSuffix = \"gov\";\n          return true;\n        } else if (c3 === 116 && c2 === 101 && c1 === 110 && c0 === 46) {\n          out.isIcann = true;\n          out.isPrivate = false;\n          out.publicSuffix = \"net\";\n          return true;\n        } else if (c3 === 101 && c2 === 100 && c1 === 46) {\n          out.isIcann = true;\n          out.isPrivate = false;\n          out.publicSuffix = \"de\";\n          return true;\n        }\n      }\n      return false;\n    }\n    __name(fastPathLookup, \"fastPathLookup\");\n    var exceptions = /* @__PURE__ */ (function() {\n      const _68 = [1, {}], _69 = [0, { \"city\": _68 }];\n      const exceptions2 = [0, { \"ck\": [0, { \"www\": _68 }], \"jp\": [0, { \"kawasaki\": _69, \"kitakyushu\": _69, \"kobe\": _69, \"nagoya\": _69, \"sapporo\": _69, \"sendai\": _69, \"yokohama\": _69 }] }];\n      return exceptions2;\n    })();\n    var rules = /* @__PURE__ */ (function() {\n      const _70 = [1, {}], _71 = [1, { \"com\": _70, \"edu\": _70, \"gov\": _70, \"mil\": _70, \"net\": _70, \"org\": _70 }], _72 = [1, { \"com\": _70, \"edu\": _70, \"gov\": _70, \"net\": _70, \"org\": _70 }], _73 = [1, { \"gov\": _70 }], _74 = [0, { \"*\": _70 }], _75 = [1, { \"co\": _70, \"com\": _70, \"edu\": _70, \"gov\": _70, \"net\": _70, \"org\": _70 }], _76 = [1, { \"com\": _70, \"edu\": _70, \"net\": _70, \"org\": _70 }], _77 = [1, { \"co\": _70, \"net\": _70, \"org\": _70 }], _78 = [1, { \"co\": _70, \"com\": _70, \"edu\": _70, \"gov\": _70, \"mil\": _70, \"net\": _70, \"nom\": _70, \"org\": _70 }], _79 = [1, { \"biz\": _70, \"com\": _70, \"edu\": _70, \"gov\": _70, \"info\": _70, \"net\": _70, \"org\": _70 }], _80 = [1, { \"gs\": _70 }], _81 = [0, { \"nes\": _70 }], _82 = [1, { \"k12\": _70, \"cc\": _70, \"lib\": _70 }], _83 = [1, { \"cc\": _70 }], _84 = [1, { \"cc\": _70, \"lib\": _70 }];\n      const rules2 = [0, { \"ac\": _71, \"ad\": _70, \"ae\": [1, { \"ac\": _70, \"co\": _70, \"gov\": _70, \"mil\": _70, \"net\": _70, \"org\": _70, \"sch\": _70 }], \"aero\": [1, { \"airline\": _70, \"airport\": _70, \"accident-investigation\": _70, \"accident-prevention\": _70, \"aerobatic\": _70, \"aeroclub\": _70, \"aerodrome\": _70, \"agents\": _70, \"air-surveillance\": _70, \"air-traffic-control\": _70, \"aircraft\": _70, \"airtraffic\": _70, \"ambulance\": _70, \"association\": _70, \"author\": _70, \"ballooning\": _70, \"broker\": _70, \"caa\": _70, \"cargo\": _70, \"catering\": _70, \"certification\": _70, \"championship\": _70, \"charter\": _70, \"civilaviation\": _70, \"club\": _70, \"conference\": _70, \"consultant\": _70, \"consulting\": _70, \"control\": _70, \"council\": _70, \"crew\": _70, \"design\": _70, \"dgca\": _70, \"educator\": _70, \"emergency\": _70, \"engine\": _70, \"engineer\": _70, \"entertainment\": _70, \"equipment\": _70, \"exchange\": _70, \"express\": _70, \"federation\": _70, \"flight\": _70, \"freight\": _70, \"fuel\": _70, \"gliding\": _70, \"government\": _70, \"\\\ngroundhandling\": _70, \"group\": _70, \"hanggliding\": _70, \"homebuilt\": _70, \"insurance\": _70, \"journal\": _70, \"journalist\": _70, \"leasing\": _70, \"logistics\": _70, \"magazine\": _70, \"maintenance\": _70, \"marketplace\": _70, \"media\": _70, \"microlight\": _70, \"modelling\": _70, \"navigation\": _70, \"parachuting\": _70, \"paragliding\": _70, \"passenger-association\": _70, \"pilot\": _70, \"press\": _70, \"production\": _70, \"recreation\": _70, \"repbody\": _70, \"res\": _70, \"research\": _70, \"rotorcraft\": _70, \"safety\": _70, \"scientist\": _70, \"services\": _70, \"show\": _70, \"skydiving\": _70, \"software\": _70, \"student\": _70, \"taxi\": _70, \"trader\": _70, \"trading\": _70, \"trainer\": _70, \"union\": _70, \"workinggroup\": _70, \"works\": _70 }], \"af\": _72, \"ag\": [1, { \"co\": _70, \"com\": _70, \"net\": _70, \"nom\": _70, \"org\": _70 }], \"ai\": [1, { \"com\": _70, \"net\": _70, \"off\": _70, \"org\": _70 }], \"al\": _71, \"am\": [1, { \"co\": _70, \"com\": _70, \"commune\": _70, \"net\": _70, \"org\": _70 }], \"ao\": [1, { \"co\": _70, \"ed\": _70, \"edu\": _70, \"go\\\nv\": _70, \"gv\": _70, \"it\": _70, \"og\": _70, \"org\": _70, \"pb\": _70 }], \"aq\": _70, \"ar\": [1, { \"bet\": _70, \"com\": _70, \"coop\": _70, \"edu\": _70, \"gob\": _70, \"gov\": _70, \"int\": _70, \"mil\": _70, \"musica\": _70, \"mutual\": _70, \"net\": _70, \"org\": _70, \"seg\": _70, \"senasa\": _70, \"tur\": _70 }], \"arpa\": [1, { \"e164\": _70, \"home\": _70, \"in-addr\": _70, \"ip6\": _70, \"iris\": _70, \"uri\": _70, \"urn\": _70 }], \"as\": _73, \"asia\": _70, \"at\": [1, { \"ac\": [1, { \"sth\": _70 }], \"co\": _70, \"gv\": _70, \"or\": _70 }], \"au\": [1, { \"asn\": _70, \"com\": _70, \"edu\": [1, { \"act\": _70, \"catholic\": _70, \"nsw\": _70, \"nt\": _70, \"qld\": _70, \"sa\": _70, \"tas\": _70, \"vic\": _70, \"wa\": _70 }], \"gov\": [1, { \"qld\": _70, \"sa\": _70, \"tas\": _70, \"vic\": _70, \"wa\": _70 }], \"id\": _70, \"net\": _70, \"org\": _70, \"conf\": _70, \"oz\": _70, \"act\": _70, \"nsw\": _70, \"nt\": _70, \"qld\": _70, \"sa\": _70, \"tas\": _70, \"vic\": _70, \"wa\": _70 }], \"aw\": [1, { \"com\": _70 }], \"ax\": _70, \"az\": [1, { \"biz\": _70, \"co\": _70, \"com\": _70, \"edu\": _70, \"gov\": _70, \"info\": _70,\n      \"int\": _70, \"mil\": _70, \"name\": _70, \"net\": _70, \"org\": _70, \"pp\": _70, \"pro\": _70 }], \"ba\": _71, \"bb\": [1, { \"biz\": _70, \"co\": _70, \"com\": _70, \"edu\": _70, \"gov\": _70, \"info\": _70, \"net\": _70, \"org\": _70, \"store\": _70, \"tv\": _70 }], \"bd\": _74, \"be\": [1, { \"ac\": _70 }], \"bf\": _73, \"bg\": [1, { \"0\": _70, \"1\": _70, \"2\": _70, \"3\": _70, \"4\": _70, \"5\": _70, \"6\": _70, \"7\": _70, \"8\": _70, \"9\": _70, \"a\": _70, \"b\": _70, \"c\": _70, \"d\": _70, \"e\": _70, \"f\": _70, \"g\": _70, \"h\": _70, \"i\": _70, \"j\": _70, \"k\": _70, \"l\": _70, \"m\": _70, \"n\": _70, \"o\": _70, \"p\": _70, \"q\": _70, \"r\": _70, \"s\": _70, \"t\": _70, \"u\": _70, \"v\": _70, \"w\": _70, \"x\": _70, \"y\": _70, \"z\": _70 }], \"bh\": _72, \"bi\": [1, { \"co\": _70, \"com\": _70, \"edu\": _70, \"or\": _70, \"org\": _70 }], \"biz\": _70, \"bj\": [1, { \"africa\": _70, \"agro\": _70, \"architectes\": _70, \"assur\": _70, \"avocats\": _70, \"co\": _70, \"com\": _70, \"eco\": _70, \"econo\": _70, \"edu\": _70, \"info\": _70, \"loisirs\": _70, \"money\": _70, \"net\": _70, \"org\": _70, \"ote\": _70, \"restaurant\": _70,\n      \"resto\": _70, \"tourism\": _70, \"univ\": _70 }], \"bm\": _72, \"bn\": _72, \"bo\": [1, { \"com\": _70, \"edu\": _70, \"gob\": _70, \"int\": _70, \"mil\": _70, \"net\": _70, \"org\": _70, \"tv\": _70, \"web\": _70, \"academia\": _70, \"agro\": _70, \"arte\": _70, \"blog\": _70, \"bolivia\": _70, \"ciencia\": _70, \"cooperativa\": _70, \"democracia\": _70, \"deporte\": _70, \"ecologia\": _70, \"economia\": _70, \"empresa\": _70, \"indigena\": _70, \"industria\": _70, \"info\": _70, \"medicina\": _70, \"movimiento\": _70, \"musica\": _70, \"natural\": _70, \"nombre\": _70, \"noticias\": _70, \"patria\": _70, \"plurinacional\": _70, \"politica\": _70, \"profesional\": _70, \"pueblo\": _70, \"revista\": _70, \"salud\": _70, \"tecnologia\": _70, \"tksat\": _70, \"transporte\": _70, \"wiki\": _70 }], \"br\": [1, { \"9guacu\": _70, \"abc\": _70, \"adm\": _70, \"adv\": _70, \"agr\": _70, \"aju\": _70, \"am\": _70, \"anani\": _70, \"aparecida\": _70, \"api\": _70, \"app\": _70, \"arq\": _70, \"art\": _70, \"ato\": _70, \"b\": _70, \"barueri\": _70, \"belem\": _70, \"bet\": _70, \"bhz\": _70, \"bib\": _70, \"bio\": _70, \"b\\\nlog\": _70, \"bmd\": _70, \"boavista\": _70, \"bsb\": _70, \"campinagrande\": _70, \"campinas\": _70, \"caxias\": _70, \"cim\": _70, \"cng\": _70, \"cnt\": _70, \"com\": _70, \"contagem\": _70, \"coop\": _70, \"coz\": _70, \"cri\": _70, \"cuiaba\": _70, \"curitiba\": _70, \"def\": _70, \"des\": _70, \"det\": _70, \"dev\": _70, \"ecn\": _70, \"eco\": _70, \"edu\": _70, \"emp\": _70, \"enf\": _70, \"eng\": _70, \"esp\": _70, \"etc\": _70, \"eti\": _70, \"far\": _70, \"feira\": _70, \"flog\": _70, \"floripa\": _70, \"fm\": _70, \"fnd\": _70, \"fortal\": _70, \"fot\": _70, \"foz\": _70, \"fst\": _70, \"g12\": _70, \"geo\": _70, \"ggf\": _70, \"goiania\": _70, \"gov\": [1, { \"ac\": _70, \"al\": _70, \"am\": _70, \"ap\": _70, \"ba\": _70, \"ce\": _70, \"df\": _70, \"es\": _70, \"go\": _70, \"ma\": _70, \"mg\": _70, \"ms\": _70, \"mt\": _70, \"pa\": _70, \"pb\": _70, \"pe\": _70, \"pi\": _70, \"pr\": _70, \"rj\": _70, \"rn\": _70, \"ro\": _70, \"rr\": _70, \"rs\": _70, \"sc\": _70, \"se\": _70, \"sp\": _70, \"to\": _70 }], \"gru\": _70, \"ia\": _70, \"imb\": _70, \"ind\": _70, \"inf\": _70, \"jab\": _70, \"jampa\": _70, \"jdf\": _70, \"joinville\": _70,\n      \"jor\": _70, \"jus\": _70, \"leg\": _70, \"leilao\": _70, \"lel\": _70, \"log\": _70, \"londrina\": _70, \"macapa\": _70, \"maceio\": _70, \"manaus\": _70, \"maringa\": _70, \"mat\": _70, \"med\": _70, \"mil\": _70, \"morena\": _70, \"mp\": _70, \"mus\": _70, \"natal\": _70, \"net\": _70, \"niteroi\": _70, \"nom\": _74, \"not\": _70, \"ntr\": _70, \"odo\": _70, \"ong\": _70, \"org\": _70, \"osasco\": _70, \"palmas\": _70, \"poa\": _70, \"ppg\": _70, \"pro\": _70, \"psc\": _70, \"psi\": _70, \"pvh\": _70, \"qsl\": _70, \"radio\": _70, \"rec\": _70, \"recife\": _70, \"rep\": _70, \"ribeirao\": _70, \"rio\": _70, \"riobranco\": _70, \"riopreto\": _70, \"salvador\": _70, \"sampa\": _70, \"santamaria\": _70, \"santoandre\": _70, \"saobernardo\": _70, \"saogonca\": _70, \"seg\": _70, \"sjc\": _70, \"slg\": _70, \"slz\": _70, \"social\": _70, \"sorocaba\": _70, \"srv\": _70, \"taxi\": _70, \"tc\": _70, \"tec\": _70, \"teo\": _70, \"the\": _70, \"tmp\": _70, \"trd\": _70, \"tur\": _70, \"tv\": _70, \"udi\": _70, \"vet\": _70, \"vix\": _70, \"vlog\": _70, \"wiki\": _70, \"xyz\": _70, \"zlg\": _70 }], \"bs\": _72, \"bt\": _72, \"bv\": _70,\n      \"bw\": [1, { \"ac\": _70, \"co\": _70, \"gov\": _70, \"net\": _70, \"org\": _70 }], \"by\": [1, { \"gov\": _70, \"mil\": _70, \"com\": _70, \"of\": _70 }], \"bz\": _75, \"ca\": [1, { \"ab\": _70, \"bc\": _70, \"mb\": _70, \"nb\": _70, \"nf\": _70, \"nl\": _70, \"ns\": _70, \"nt\": _70, \"nu\": _70, \"on\": _70, \"pe\": _70, \"qc\": _70, \"sk\": _70, \"yk\": _70, \"gc\": _70 }], \"cat\": _70, \"cc\": _70, \"cd\": _73, \"cf\": _70, \"cg\": _70, \"ch\": _70, \"ci\": [1, { \"ac\": _70, \"xn--aroport-bya\": _70, \"aéroport\": _70, \"asso\": _70, \"co\": _70, \"com\": _70, \"ed\": _70, \"edu\": _70, \"go\": _70, \"gouv\": _70, \"int\": _70, \"net\": _70, \"or\": _70, \"org\": _70 }], \"ck\": _74, \"cl\": [1, { \"co\": _70, \"gob\": _70, \"gov\": _70, \"mil\": _70 }], \"cm\": [1, { \"co\": _70, \"com\": _70, \"gov\": _70, \"net\": _70 }], \"cn\": [1, { \"ac\": _70, \"com\": _70, \"edu\": _70, \"gov\": _70, \"mil\": _70, \"net\": _70, \"org\": _70, \"xn--55qx5d\": _70, \"公司\": _70, \"xn--od0alg\": _70, \"網絡\": _70, \"xn--io0a7i\": _70, \"网络\": _70, \"ah\": _70, \"bj\": _70, \"cq\": _70, \"fj\": _70, \"gd\": _70, \"gs\": _70, \"gx\": _70,\n      \"gz\": _70, \"ha\": _70, \"hb\": _70, \"he\": _70, \"hi\": _70, \"hk\": _70, \"hl\": _70, \"hn\": _70, \"jl\": _70, \"js\": _70, \"jx\": _70, \"ln\": _70, \"mo\": _70, \"nm\": _70, \"nx\": _70, \"qh\": _70, \"sc\": _70, \"sd\": _70, \"sh\": _70, \"sn\": _70, \"sx\": _70, \"tj\": _70, \"tw\": _70, \"xj\": _70, \"xz\": _70, \"yn\": _70, \"zj\": _70 }], \"co\": [1, { \"com\": _70, \"edu\": _70, \"gov\": _70, \"mil\": _70, \"net\": _70, \"nom\": _70, \"org\": _70 }], \"com\": _70, \"coop\": _70, \"cr\": [1, { \"ac\": _70, \"co\": _70, \"ed\": _70, \"fi\": _70, \"go\": _70, \"or\": _70, \"sa\": _70 }], \"cu\": [1, { \"com\": _70, \"edu\": _70, \"gob\": _70, \"inf\": _70, \"nat\": _70, \"net\": _70, \"org\": _70 }], \"cv\": [1, { \"com\": _70, \"edu\": _70, \"id\": _70, \"int\": _70, \"net\": _70, \"nome\": _70, \"org\": _70, \"publ\": _70 }], \"cw\": _76, \"cx\": _73, \"cy\": [1, { \"ac\": _70, \"biz\": _70, \"com\": _70, \"ekloges\": _70, \"gov\": _70, \"ltd\": _70, \"mil\": _70, \"net\": _70, \"org\": _70, \"press\": _70, \"pro\": _70, \"tm\": _70 }], \"cz\": _73, \"de\": _70, \"dj\": _70, \"dk\": _70, \"dm\": _75, \"do\": [1, { \"art\": _70, \"co\\\nm\": _70, \"edu\": _70, \"gob\": _70, \"gov\": _70, \"mil\": _70, \"net\": _70, \"org\": _70, \"sld\": _70, \"web\": _70 }], \"dz\": [1, { \"art\": _70, \"asso\": _70, \"com\": _70, \"edu\": _70, \"gov\": _70, \"net\": _70, \"org\": _70, \"pol\": _70, \"soc\": _70, \"tm\": _70 }], \"ec\": [1, { \"abg\": _70, \"adm\": _70, \"agron\": _70, \"arqt\": _70, \"art\": _70, \"bar\": _70, \"chef\": _70, \"com\": _70, \"cont\": _70, \"cpa\": _70, \"cue\": _70, \"dent\": _70, \"dgn\": _70, \"disco\": _70, \"doc\": _70, \"edu\": _70, \"eng\": _70, \"esm\": _70, \"fin\": _70, \"fot\": _70, \"gal\": _70, \"gob\": _70, \"gov\": _70, \"gye\": _70, \"ibr\": _70, \"info\": _70, \"k12\": _70, \"lat\": _70, \"loj\": _70, \"med\": _70, \"mil\": _70, \"mktg\": _70, \"mon\": _70, \"net\": _70, \"ntr\": _70, \"odont\": _70, \"org\": _70, \"pro\": _70, \"prof\": _70, \"psic\": _70, \"psiq\": _70, \"pub\": _70, \"rio\": _70, \"rrpp\": _70, \"sal\": _70, \"tech\": _70, \"tul\": _70, \"tur\": _70, \"uio\": _70, \"vet\": _70, \"xxx\": _70 }], \"edu\": _70, \"ee\": [1, { \"aip\": _70, \"com\": _70, \"edu\": _70, \"fie\": _70, \"gov\": _70, \"lib\": _70, \"med\": _70, \"org\": _70,\n      \"pri\": _70, \"riik\": _70 }], \"eg\": [1, { \"ac\": _70, \"com\": _70, \"edu\": _70, \"eun\": _70, \"gov\": _70, \"info\": _70, \"me\": _70, \"mil\": _70, \"name\": _70, \"net\": _70, \"org\": _70, \"sci\": _70, \"sport\": _70, \"tv\": _70 }], \"er\": _74, \"es\": [1, { \"com\": _70, \"edu\": _70, \"gob\": _70, \"nom\": _70, \"org\": _70 }], \"et\": [1, { \"biz\": _70, \"com\": _70, \"edu\": _70, \"gov\": _70, \"info\": _70, \"name\": _70, \"net\": _70, \"org\": _70 }], \"eu\": _70, \"fi\": [1, { \"aland\": _70 }], \"fj\": [1, { \"ac\": _70, \"biz\": _70, \"com\": _70, \"gov\": _70, \"info\": _70, \"mil\": _70, \"name\": _70, \"net\": _70, \"org\": _70, \"pro\": _70 }], \"fk\": _74, \"fm\": _76, \"fo\": _70, \"fr\": [1, { \"asso\": _70, \"com\": _70, \"gouv\": _70, \"nom\": _70, \"prd\": _70, \"tm\": _70, \"avoues\": _70, \"cci\": _70, \"greta\": _70, \"huissier-justice\": _70 }], \"ga\": _70, \"gb\": _70, \"gd\": [1, { \"edu\": _70, \"gov\": _70 }], \"ge\": [1, { \"com\": _70, \"edu\": _70, \"gov\": _70, \"net\": _70, \"org\": _70, \"pvt\": _70, \"school\": _70 }], \"gf\": _70, \"gg\": _77, \"gh\": [1, { \"biz\": _70, \"com\": _70,\n      \"edu\": _70, \"gov\": _70, \"mil\": _70, \"net\": _70, \"org\": _70 }], \"gi\": [1, { \"com\": _70, \"edu\": _70, \"gov\": _70, \"ltd\": _70, \"mod\": _70, \"org\": _70 }], \"gl\": [1, { \"co\": _70, \"com\": _70, \"edu\": _70, \"net\": _70, \"org\": _70 }], \"gm\": _70, \"gn\": [1, { \"ac\": _70, \"com\": _70, \"edu\": _70, \"gov\": _70, \"net\": _70, \"org\": _70 }], \"gov\": _70, \"gp\": [1, { \"asso\": _70, \"com\": _70, \"edu\": _70, \"mobi\": _70, \"net\": _70, \"org\": _70 }], \"gq\": _70, \"gr\": _72, \"gs\": _70, \"gt\": [1, { \"com\": _70, \"edu\": _70, \"gob\": _70, \"ind\": _70, \"mil\": _70, \"net\": _70, \"org\": _70 }], \"gu\": [1, { \"com\": _70, \"edu\": _70, \"gov\": _70, \"guam\": _70, \"info\": _70, \"net\": _70, \"org\": _70, \"web\": _70 }], \"gw\": _70, \"gy\": _75, \"hk\": [1, { \"com\": _70, \"edu\": _70, \"gov\": _70, \"idv\": _70, \"net\": _70, \"org\": _70, \"xn--ciqpn\": _70, \"个人\": _70, \"xn--gmqw5a\": _70, \"個人\": _70, \"xn--55qx5d\": _70, \"公司\": _70, \"xn--mxtq1m\": _70, \"政府\": _70, \"xn--lcvr32d\": _70, \"敎育\": _70, \"xn--wcvs22d\": _70, \"教育\": _70, \"xn--gmq050i\": _70,\n      \"箇人\": _70, \"xn--uc0atv\": _70, \"組織\": _70, \"xn--uc0ay4a\": _70, \"組织\": _70, \"xn--od0alg\": _70, \"網絡\": _70, \"xn--zf0avx\": _70, \"網络\": _70, \"xn--mk0axi\": _70, \"组織\": _70, \"xn--tn0ag\": _70, \"组织\": _70, \"xn--od0aq3b\": _70, \"网絡\": _70, \"xn--io0a7i\": _70, \"网络\": _70 }], \"hm\": _70, \"hn\": [1, { \"com\": _70, \"edu\": _70, \"gob\": _70, \"mil\": _70, \"net\": _70, \"org\": _70 }], \"hr\": [1, { \"com\": _70, \"from\": _70, \"iz\": _70, \"name\": _70 }], \"ht\": [1, { \"adult\": _70, \"art\": _70, \"asso\": _70, \"com\": _70, \"coop\": _70, \"edu\": _70, \"firm\": _70, \"gouv\": _70, \"info\": _70, \"med\": _70, \"net\": _70, \"org\": _70, \"perso\": _70, \"pol\": _70, \"pro\": _70, \"rel\": _70, \"shop\": _70 }], \"hu\": [1, { \"2000\": _70, \"agrar\": _70, \"bolt\": _70, \"casino\": _70, \"city\": _70, \"co\": _70, \"erotica\": _70, \"erotika\": _70, \"film\": _70, \"forum\": _70, \"games\": _70, \"hotel\": _70, \"info\": _70, \"ingatlan\": _70, \"jogasz\": _70, \"konyvelo\": _70, \"lakas\": _70, \"media\": _70, \"news\": _70, \"org\": _70, \"priv\": _70, \"rekla\\\nm\": _70, \"sex\": _70, \"shop\": _70, \"sport\": _70, \"suli\": _70, \"szex\": _70, \"tm\": _70, \"tozsde\": _70, \"utazas\": _70, \"video\": _70 }], \"id\": [1, { \"ac\": _70, \"biz\": _70, \"co\": _70, \"desa\": _70, \"go\": _70, \"kop\": _70, \"mil\": _70, \"my\": _70, \"net\": _70, \"or\": _70, \"ponpes\": _70, \"sch\": _70, \"web\": _70 }], \"ie\": _73, \"il\": [1, { \"ac\": _70, \"co\": _70, \"gov\": _70, \"idf\": _70, \"k12\": _70, \"muni\": _70, \"net\": _70, \"org\": _70 }], \"xn--4dbrk0ce\": [1, { \"xn--4dbgdty6c\": _70, \"xn--5dbhl8d\": _70, \"xn--8dbq2a\": _70, \"xn--hebda8b\": _70 }], \"ישראל\": [1, { \"אקדמיה\": _70, \"ישוב\": _70, \"צהל\": _70, \"ממשל\": _70 }], \"im\": [1, { \"ac\": _70, \"co\": [1, { \"ltd\": _70, \"plc\": _70 }], \"com\": _70, \"net\": _70, \"org\": _70, \"tt\": _70, \"tv\": _70 }], \"in\": [1, { \"5g\": _70, \"6g\": _70, \"ac\": _70, \"ai\": _70, \"am\": _70, \"bihar\": _70, \"biz\": _70, \"business\": _70, \"ca\": _70, \"cn\": _70, \"co\": _70, \"com\": _70, \"coop\": _70, \"cs\": _70, \"delhi\": _70, \"dr\": _70, \"edu\": _70, \"er\": _70, \"firm\": _70, \"gen\": _70, \"go\\\nv\": _70, \"gujarat\": _70, \"ind\": _70, \"info\": _70, \"int\": _70, \"internet\": _70, \"io\": _70, \"me\": _70, \"mil\": _70, \"net\": _70, \"nic\": _70, \"org\": _70, \"pg\": _70, \"post\": _70, \"pro\": _70, \"res\": _70, \"travel\": _70, \"tv\": _70, \"uk\": _70, \"up\": _70, \"us\": _70 }], \"info\": _70, \"int\": [1, { \"eu\": _70 }], \"io\": _78, \"iq\": _71, \"ir\": [1, { \"ac\": _70, \"co\": _70, \"gov\": _70, \"id\": _70, \"net\": _70, \"org\": _70, \"sch\": _70, \"xn--mgba3a4f16a\": _70, \"ایران\": _70, \"xn--mgba3a4fra\": _70, \"ايران\": _70 }], \"is\": _70, \"it\": [1, { \"edu\": _70, \"gov\": _70, \"abr\": _70, \"abruzzo\": _70, \"aosta-valley\": _70, \"aostavalley\": _70, \"bas\": _70, \"basilicata\": _70, \"cal\": _70, \"calabria\": _70, \"cam\": _70, \"campania\": _70, \"emilia-romagna\": _70, \"emiliaromagna\": _70, \"emr\": _70, \"friuli-v-giulia\": _70, \"friuli-ve-giulia\": _70, \"friuli-vegiulia\": _70, \"friuli-venezia-giulia\": _70, \"friuli-veneziagiulia\": _70, \"friuli-vgiulia\": _70, \"friuliv-giulia\": _70, \"friulive-giulia\": _70, \"friulivegiulia\": _70, \"friulivene\\\nzia-giulia\": _70, \"friuliveneziagiulia\": _70, \"friulivgiulia\": _70, \"fvg\": _70, \"laz\": _70, \"lazio\": _70, \"lig\": _70, \"liguria\": _70, \"lom\": _70, \"lombardia\": _70, \"lombardy\": _70, \"lucania\": _70, \"mar\": _70, \"marche\": _70, \"mol\": _70, \"molise\": _70, \"piedmont\": _70, \"piemonte\": _70, \"pmn\": _70, \"pug\": _70, \"puglia\": _70, \"sar\": _70, \"sardegna\": _70, \"sardinia\": _70, \"sic\": _70, \"sicilia\": _70, \"sicily\": _70, \"taa\": _70, \"tos\": _70, \"toscana\": _70, \"trentin-sud-tirol\": _70, \"xn--trentin-sd-tirol-rzb\": _70, \"trentin-süd-tirol\": _70, \"trentin-sudtirol\": _70, \"xn--trentin-sdtirol-7vb\": _70, \"trentin-südtirol\": _70, \"trentin-sued-tirol\": _70, \"trentin-suedtirol\": _70, \"trentino\": _70, \"trentino-a-adige\": _70, \"trentino-aadige\": _70, \"trentino-alto-adige\": _70, \"trentino-altoadige\": _70, \"trentino-s-tirol\": _70, \"trentino-stirol\": _70, \"trentino-sud-tirol\": _70, \"xn--trentino-sd-tirol-c3b\": _70, \"trentino-süd-tirol\": _70, \"trentino-sudtirol\": _70, \"xn--trentino-sdtirol-szb\": _70, \"trenti\\\nno-südtirol\": _70, \"trentino-sued-tirol\": _70, \"trentino-suedtirol\": _70, \"trentinoa-adige\": _70, \"trentinoaadige\": _70, \"trentinoalto-adige\": _70, \"trentinoaltoadige\": _70, \"trentinos-tirol\": _70, \"trentinostirol\": _70, \"trentinosud-tirol\": _70, \"xn--trentinosd-tirol-rzb\": _70, \"trentinosüd-tirol\": _70, \"trentinosudtirol\": _70, \"xn--trentinosdtirol-7vb\": _70, \"trentinosüdtirol\": _70, \"trentinosued-tirol\": _70, \"trentinosuedtirol\": _70, \"trentinsud-tirol\": _70, \"xn--trentinsd-tirol-6vb\": _70, \"trentinsüd-tirol\": _70, \"trentinsudtirol\": _70, \"xn--trentinsdtirol-nsb\": _70, \"trentinsüdtirol\": _70, \"trentinsued-tirol\": _70, \"trentinsuedtirol\": _70, \"tuscany\": _70, \"umb\": _70, \"umbria\": _70, \"val-d-aosta\": _70, \"val-daosta\": _70, \"vald-aosta\": _70, \"valdaosta\": _70, \"valle-aosta\": _70, \"valle-d-aosta\": _70, \"valle-daosta\": _70, \"valleaosta\": _70, \"valled-aosta\": _70, \"valledaosta\": _70, \"vallee-aoste\": _70, \"xn--valle-aoste-ebb\": _70, \"vallée-aoste\": _70, \"vallee-d-aoste\": _70, \"xn--v\\\nalle-d-aoste-ehb\": _70, \"vallée-d-aoste\": _70, \"valleeaoste\": _70, \"xn--valleaoste-e7a\": _70, \"valléeaoste\": _70, \"valleedaoste\": _70, \"xn--valledaoste-ebb\": _70, \"valléedaoste\": _70, \"vao\": _70, \"vda\": _70, \"ven\": _70, \"veneto\": _70, \"ag\": _70, \"agrigento\": _70, \"al\": _70, \"alessandria\": _70, \"alto-adige\": _70, \"altoadige\": _70, \"an\": _70, \"ancona\": _70, \"andria-barletta-trani\": _70, \"andria-trani-barletta\": _70, \"andriabarlettatrani\": _70, \"andriatranibarletta\": _70, \"ao\": _70, \"aosta\": _70, \"aoste\": _70, \"ap\": _70, \"aq\": _70, \"aquila\": _70, \"ar\": _70, \"arezzo\": _70, \"ascoli-piceno\": _70, \"ascolipiceno\": _70, \"asti\": _70, \"at\": _70, \"av\": _70, \"avellino\": _70, \"ba\": _70, \"balsan\": _70, \"balsan-sudtirol\": _70, \"xn--balsan-sdtirol-nsb\": _70, \"balsan-südtirol\": _70, \"balsan-suedtirol\": _70, \"bari\": _70, \"barletta-trani-andria\": _70, \"barlettatraniandria\": _70, \"belluno\": _70, \"benevento\": _70, \"bergamo\": _70, \"bg\": _70, \"bi\": _70, \"biella\": _70, \"bl\": _70, \"bn\": _70, \"bo\": _70, \"bol\\\nogna\": _70, \"bolzano\": _70, \"bolzano-altoadige\": _70, \"bozen\": _70, \"bozen-sudtirol\": _70, \"xn--bozen-sdtirol-2ob\": _70, \"bozen-südtirol\": _70, \"bozen-suedtirol\": _70, \"br\": _70, \"brescia\": _70, \"brindisi\": _70, \"bs\": _70, \"bt\": _70, \"bulsan\": _70, \"bulsan-sudtirol\": _70, \"xn--bulsan-sdtirol-nsb\": _70, \"bulsan-südtirol\": _70, \"bulsan-suedtirol\": _70, \"bz\": _70, \"ca\": _70, \"cagliari\": _70, \"caltanissetta\": _70, \"campidano-medio\": _70, \"campidanomedio\": _70, \"campobasso\": _70, \"carbonia-iglesias\": _70, \"carboniaiglesias\": _70, \"carrara-massa\": _70, \"carraramassa\": _70, \"caserta\": _70, \"catania\": _70, \"catanzaro\": _70, \"cb\": _70, \"ce\": _70, \"cesena-forli\": _70, \"xn--cesena-forl-mcb\": _70, \"cesena-forlì\": _70, \"cesenaforli\": _70, \"xn--cesenaforl-i8a\": _70, \"cesenaforlì\": _70, \"ch\": _70, \"chieti\": _70, \"ci\": _70, \"cl\": _70, \"cn\": _70, \"co\": _70, \"como\": _70, \"cosenza\": _70, \"cr\": _70, \"cremona\": _70, \"crotone\": _70, \"cs\": _70, \"ct\": _70, \"cuneo\": _70, \"cz\": _70, \"dell-ogliastra\": _70, \"\\\ndellogliastra\": _70, \"en\": _70, \"enna\": _70, \"fc\": _70, \"fe\": _70, \"fermo\": _70, \"ferrara\": _70, \"fg\": _70, \"fi\": _70, \"firenze\": _70, \"florence\": _70, \"fm\": _70, \"foggia\": _70, \"forli-cesena\": _70, \"xn--forl-cesena-fcb\": _70, \"forlì-cesena\": _70, \"forlicesena\": _70, \"xn--forlcesena-c8a\": _70, \"forlìcesena\": _70, \"fr\": _70, \"frosinone\": _70, \"ge\": _70, \"genoa\": _70, \"genova\": _70, \"go\": _70, \"gorizia\": _70, \"gr\": _70, \"grosseto\": _70, \"iglesias-carbonia\": _70, \"iglesiascarbonia\": _70, \"im\": _70, \"imperia\": _70, \"is\": _70, \"isernia\": _70, \"kr\": _70, \"la-spezia\": _70, \"laquila\": _70, \"laspezia\": _70, \"latina\": _70, \"lc\": _70, \"le\": _70, \"lecce\": _70, \"lecco\": _70, \"li\": _70, \"livorno\": _70, \"lo\": _70, \"lodi\": _70, \"lt\": _70, \"lu\": _70, \"lucca\": _70, \"macerata\": _70, \"mantova\": _70, \"massa-carrara\": _70, \"massacarrara\": _70, \"matera\": _70, \"mb\": _70, \"mc\": _70, \"me\": _70, \"medio-campidano\": _70, \"mediocampidano\": _70, \"messina\": _70, \"mi\": _70, \"milan\": _70, \"milano\": _70, \"mn\": _70, \"m\\\no\": _70, \"modena\": _70, \"monza\": _70, \"monza-brianza\": _70, \"monza-e-della-brianza\": _70, \"monzabrianza\": _70, \"monzaebrianza\": _70, \"monzaedellabrianza\": _70, \"ms\": _70, \"mt\": _70, \"na\": _70, \"naples\": _70, \"napoli\": _70, \"no\": _70, \"novara\": _70, \"nu\": _70, \"nuoro\": _70, \"og\": _70, \"ogliastra\": _70, \"olbia-tempio\": _70, \"olbiatempio\": _70, \"or\": _70, \"oristano\": _70, \"ot\": _70, \"pa\": _70, \"padova\": _70, \"padua\": _70, \"palermo\": _70, \"parma\": _70, \"pavia\": _70, \"pc\": _70, \"pd\": _70, \"pe\": _70, \"perugia\": _70, \"pesaro-urbino\": _70, \"pesarourbino\": _70, \"pescara\": _70, \"pg\": _70, \"pi\": _70, \"piacenza\": _70, \"pisa\": _70, \"pistoia\": _70, \"pn\": _70, \"po\": _70, \"pordenone\": _70, \"potenza\": _70, \"pr\": _70, \"prato\": _70, \"pt\": _70, \"pu\": _70, \"pv\": _70, \"pz\": _70, \"ra\": _70, \"ragusa\": _70, \"ravenna\": _70, \"rc\": _70, \"re\": _70, \"reggio-calabria\": _70, \"reggio-emilia\": _70, \"reggiocalabria\": _70, \"reggioemilia\": _70, \"rg\": _70, \"ri\": _70, \"rieti\": _70, \"rimini\": _70, \"rm\": _70, \"rn\": _70, \"ro\": _70,\n      \"roma\": _70, \"rome\": _70, \"rovigo\": _70, \"sa\": _70, \"salerno\": _70, \"sassari\": _70, \"savona\": _70, \"si\": _70, \"siena\": _70, \"siracusa\": _70, \"so\": _70, \"sondrio\": _70, \"sp\": _70, \"sr\": _70, \"ss\": _70, \"xn--sdtirol-n2a\": _70, \"südtirol\": _70, \"suedtirol\": _70, \"sv\": _70, \"ta\": _70, \"taranto\": _70, \"te\": _70, \"tempio-olbia\": _70, \"tempioolbia\": _70, \"teramo\": _70, \"terni\": _70, \"tn\": _70, \"to\": _70, \"torino\": _70, \"tp\": _70, \"tr\": _70, \"trani-andria-barletta\": _70, \"trani-barletta-andria\": _70, \"traniandriabarletta\": _70, \"tranibarlettaandria\": _70, \"trapani\": _70, \"trento\": _70, \"treviso\": _70, \"trieste\": _70, \"ts\": _70, \"turin\": _70, \"tv\": _70, \"ud\": _70, \"udine\": _70, \"urbino-pesaro\": _70, \"urbinopesaro\": _70, \"va\": _70, \"varese\": _70, \"vb\": _70, \"vc\": _70, \"ve\": _70, \"venezia\": _70, \"venice\": _70, \"verbania\": _70, \"vercelli\": _70, \"verona\": _70, \"vi\": _70, \"vibo-valentia\": _70, \"vibovalentia\": _70, \"vicenza\": _70, \"viterbo\": _70, \"vr\": _70, \"vs\": _70, \"vt\": _70, \"vv\": _70 }], \"\\\nje\": _77, \"jm\": _74, \"jo\": [1, { \"agri\": _70, \"ai\": _70, \"com\": _70, \"edu\": _70, \"eng\": _70, \"fm\": _70, \"gov\": _70, \"mil\": _70, \"net\": _70, \"org\": _70, \"per\": _70, \"phd\": _70, \"sch\": _70, \"tv\": _70 }], \"jobs\": _70, \"jp\": [1, { \"ac\": _70, \"ad\": _70, \"co\": _70, \"ed\": _70, \"go\": _70, \"gr\": _70, \"lg\": _70, \"ne\": _70, \"or\": _70, \"aichi\": [1, { \"aisai\": _70, \"ama\": _70, \"anjo\": _70, \"asuke\": _70, \"chiryu\": _70, \"chita\": _70, \"fuso\": _70, \"gamagori\": _70, \"handa\": _70, \"hazu\": _70, \"hekinan\": _70, \"higashiura\": _70, \"ichinomiya\": _70, \"inazawa\": _70, \"inuyama\": _70, \"isshiki\": _70, \"iwakura\": _70, \"kanie\": _70, \"kariya\": _70, \"kasugai\": _70, \"kira\": _70, \"kiyosu\": _70, \"komaki\": _70, \"konan\": _70, \"kota\": _70, \"mihama\": _70, \"miyoshi\": _70, \"nishio\": _70, \"nisshin\": _70, \"obu\": _70, \"oguchi\": _70, \"oharu\": _70, \"okazaki\": _70, \"owariasahi\": _70, \"seto\": _70, \"shikatsu\": _70, \"shinshiro\": _70, \"shitara\": _70, \"tahara\": _70, \"takahama\": _70, \"tobishima\": _70, \"toei\": _70, \"togo\": _70, \"tokai\": _70,\n      \"tokoname\": _70, \"toyoake\": _70, \"toyohashi\": _70, \"toyokawa\": _70, \"toyone\": _70, \"toyota\": _70, \"tsushima\": _70, \"yatomi\": _70 }], \"akita\": [1, { \"akita\": _70, \"daisen\": _70, \"fujisato\": _70, \"gojome\": _70, \"hachirogata\": _70, \"happou\": _70, \"higashinaruse\": _70, \"honjo\": _70, \"honjyo\": _70, \"ikawa\": _70, \"kamikoani\": _70, \"kamioka\": _70, \"katagami\": _70, \"kazuno\": _70, \"kitaakita\": _70, \"kosaka\": _70, \"kyowa\": _70, \"misato\": _70, \"mitane\": _70, \"moriyoshi\": _70, \"nikaho\": _70, \"noshiro\": _70, \"odate\": _70, \"oga\": _70, \"ogata\": _70, \"semboku\": _70, \"yokote\": _70, \"yurihonjo\": _70 }], \"aomori\": [1, { \"aomori\": _70, \"gonohe\": _70, \"hachinohe\": _70, \"hashikami\": _70, \"hiranai\": _70, \"hirosaki\": _70, \"itayanagi\": _70, \"kuroishi\": _70, \"misawa\": _70, \"mutsu\": _70, \"nakadomari\": _70, \"noheji\": _70, \"oirase\": _70, \"owani\": _70, \"rokunohe\": _70, \"sannohe\": _70, \"shichinohe\": _70, \"shingo\": _70, \"takko\": _70, \"towada\": _70, \"tsugaru\": _70, \"tsuruta\": _70 }], \"chiba\": [1, { \"abiko\": _70,\n      \"asahi\": _70, \"chonan\": _70, \"chosei\": _70, \"choshi\": _70, \"chuo\": _70, \"funabashi\": _70, \"futtsu\": _70, \"hanamigawa\": _70, \"ichihara\": _70, \"ichikawa\": _70, \"ichinomiya\": _70, \"inzai\": _70, \"isumi\": _70, \"kamagaya\": _70, \"kamogawa\": _70, \"kashiwa\": _70, \"katori\": _70, \"katsuura\": _70, \"kimitsu\": _70, \"kisarazu\": _70, \"kozaki\": _70, \"kujukuri\": _70, \"kyonan\": _70, \"matsudo\": _70, \"midori\": _70, \"mihama\": _70, \"minamiboso\": _70, \"mobara\": _70, \"mutsuzawa\": _70, \"nagara\": _70, \"nagareyama\": _70, \"narashino\": _70, \"narita\": _70, \"noda\": _70, \"oamishirasato\": _70, \"omigawa\": _70, \"onjuku\": _70, \"otaki\": _70, \"sakae\": _70, \"sakura\": _70, \"shimofusa\": _70, \"shirako\": _70, \"shiroi\": _70, \"shisui\": _70, \"sodegaura\": _70, \"sosa\": _70, \"tako\": _70, \"tateyama\": _70, \"togane\": _70, \"tohnosho\": _70, \"tomisato\": _70, \"urayasu\": _70, \"yachimata\": _70, \"yachiyo\": _70, \"yokaichiba\": _70, \"yokoshibahikari\": _70, \"yotsukaido\": _70 }], \"ehime\": [1, { \"ainan\": _70, \"honai\": _70, \"ikata\": _70, \"imabar\\\ni\": _70, \"iyo\": _70, \"kamijima\": _70, \"kihoku\": _70, \"kumakogen\": _70, \"masaki\": _70, \"matsuno\": _70, \"matsuyama\": _70, \"namikata\": _70, \"niihama\": _70, \"ozu\": _70, \"saijo\": _70, \"seiyo\": _70, \"shikokuchuo\": _70, \"tobe\": _70, \"toon\": _70, \"uchiko\": _70, \"uwajima\": _70, \"yawatahama\": _70 }], \"fukui\": [1, { \"echizen\": _70, \"eiheiji\": _70, \"fukui\": _70, \"ikeda\": _70, \"katsuyama\": _70, \"mihama\": _70, \"minamiechizen\": _70, \"obama\": _70, \"ohi\": _70, \"ono\": _70, \"sabae\": _70, \"sakai\": _70, \"takahama\": _70, \"tsuruga\": _70, \"wakasa\": _70 }], \"fukuoka\": [1, { \"ashiya\": _70, \"buzen\": _70, \"chikugo\": _70, \"chikuho\": _70, \"chikujo\": _70, \"chikushino\": _70, \"chikuzen\": _70, \"chuo\": _70, \"dazaifu\": _70, \"fukuchi\": _70, \"hakata\": _70, \"higashi\": _70, \"hirokawa\": _70, \"hisayama\": _70, \"iizuka\": _70, \"inatsuki\": _70, \"kaho\": _70, \"kasuga\": _70, \"kasuya\": _70, \"kawara\": _70, \"keisen\": _70, \"koga\": _70, \"kurate\": _70, \"kurogi\": _70, \"kurume\": _70, \"minami\": _70, \"miyako\": _70, \"miyama\": _70, \"miyawaka\": _70,\n      \"mizumaki\": _70, \"munakata\": _70, \"nakagawa\": _70, \"nakama\": _70, \"nishi\": _70, \"nogata\": _70, \"ogori\": _70, \"okagaki\": _70, \"okawa\": _70, \"oki\": _70, \"omuta\": _70, \"onga\": _70, \"onojo\": _70, \"oto\": _70, \"saigawa\": _70, \"sasaguri\": _70, \"shingu\": _70, \"shinyoshitomi\": _70, \"shonai\": _70, \"soeda\": _70, \"sue\": _70, \"tachiarai\": _70, \"tagawa\": _70, \"takata\": _70, \"toho\": _70, \"toyotsu\": _70, \"tsuiki\": _70, \"ukiha\": _70, \"umi\": _70, \"usui\": _70, \"yamada\": _70, \"yame\": _70, \"yanagawa\": _70, \"yukuhashi\": _70 }], \"fukushima\": [1, { \"aizubange\": _70, \"aizumisato\": _70, \"aizuwakamatsu\": _70, \"asakawa\": _70, \"bandai\": _70, \"date\": _70, \"fukushima\": _70, \"furudono\": _70, \"futaba\": _70, \"hanawa\": _70, \"higashi\": _70, \"hirata\": _70, \"hirono\": _70, \"iitate\": _70, \"inawashiro\": _70, \"ishikawa\": _70, \"iwaki\": _70, \"izumizaki\": _70, \"kagamiishi\": _70, \"kaneyama\": _70, \"kawamata\": _70, \"kitakata\": _70, \"kitashiobara\": _70, \"koori\": _70, \"koriyama\": _70, \"kunimi\": _70, \"miharu\": _70, \"mishima\": _70,\n      \"namie\": _70, \"nango\": _70, \"nishiaizu\": _70, \"nishigo\": _70, \"okuma\": _70, \"omotego\": _70, \"ono\": _70, \"otama\": _70, \"samegawa\": _70, \"shimogo\": _70, \"shirakawa\": _70, \"showa\": _70, \"soma\": _70, \"sukagawa\": _70, \"taishin\": _70, \"tamakawa\": _70, \"tanagura\": _70, \"tenei\": _70, \"yabuki\": _70, \"yamato\": _70, \"yamatsuri\": _70, \"yanaizu\": _70, \"yugawa\": _70 }], \"gifu\": [1, { \"anpachi\": _70, \"ena\": _70, \"gifu\": _70, \"ginan\": _70, \"godo\": _70, \"gujo\": _70, \"hashima\": _70, \"hichiso\": _70, \"hida\": _70, \"higashishirakawa\": _70, \"ibigawa\": _70, \"ikeda\": _70, \"kakamigahara\": _70, \"kani\": _70, \"kasahara\": _70, \"kasamatsu\": _70, \"kawaue\": _70, \"kitagata\": _70, \"mino\": _70, \"minokamo\": _70, \"mitake\": _70, \"mizunami\": _70, \"motosu\": _70, \"nakatsugawa\": _70, \"ogaki\": _70, \"sakahogi\": _70, \"seki\": _70, \"sekigahara\": _70, \"shirakawa\": _70, \"tajimi\": _70, \"takayama\": _70, \"tarui\": _70, \"toki\": _70, \"tomika\": _70, \"wanouchi\": _70, \"yamagata\": _70, \"yaotsu\": _70, \"yoro\": _70 }], \"gunma\": [1, { \"annaka\": _70,\n      \"chiyoda\": _70, \"fujioka\": _70, \"higashiagatsuma\": _70, \"isesaki\": _70, \"itakura\": _70, \"kanna\": _70, \"kanra\": _70, \"katashina\": _70, \"kawaba\": _70, \"kiryu\": _70, \"kusatsu\": _70, \"maebashi\": _70, \"meiwa\": _70, \"midori\": _70, \"minakami\": _70, \"naganohara\": _70, \"nakanojo\": _70, \"nanmoku\": _70, \"numata\": _70, \"oizumi\": _70, \"ora\": _70, \"ota\": _70, \"shibukawa\": _70, \"shimonita\": _70, \"shinto\": _70, \"showa\": _70, \"takasaki\": _70, \"takayama\": _70, \"tamamura\": _70, \"tatebayashi\": _70, \"tomioka\": _70, \"tsukiyono\": _70, \"tsumagoi\": _70, \"ueno\": _70, \"yoshioka\": _70 }], \"hiroshima\": [1, { \"asaminami\": _70, \"daiwa\": _70, \"etajima\": _70, \"fuchu\": _70, \"fukuyama\": _70, \"hatsukaichi\": _70, \"higashihiroshima\": _70, \"hongo\": _70, \"jinsekikogen\": _70, \"kaita\": _70, \"kui\": _70, \"kumano\": _70, \"kure\": _70, \"mihara\": _70, \"miyoshi\": _70, \"naka\": _70, \"onomichi\": _70, \"osakikamijima\": _70, \"otake\": _70, \"saka\": _70, \"sera\": _70, \"seranishi\": _70, \"shinichi\": _70, \"shobara\": _70, \"takehara\": _70 }], \"\\\nhokkaido\": [1, { \"abashiri\": _70, \"abira\": _70, \"aibetsu\": _70, \"akabira\": _70, \"akkeshi\": _70, \"asahikawa\": _70, \"ashibetsu\": _70, \"ashoro\": _70, \"assabu\": _70, \"atsuma\": _70, \"bibai\": _70, \"biei\": _70, \"bifuka\": _70, \"bihoro\": _70, \"biratori\": _70, \"chippubetsu\": _70, \"chitose\": _70, \"date\": _70, \"ebetsu\": _70, \"embetsu\": _70, \"eniwa\": _70, \"erimo\": _70, \"esan\": _70, \"esashi\": _70, \"fukagawa\": _70, \"fukushima\": _70, \"furano\": _70, \"furubira\": _70, \"haboro\": _70, \"hakodate\": _70, \"hamatonbetsu\": _70, \"hidaka\": _70, \"higashikagura\": _70, \"higashikawa\": _70, \"hiroo\": _70, \"hokuryu\": _70, \"hokuto\": _70, \"honbetsu\": _70, \"horokanai\": _70, \"horonobe\": _70, \"ikeda\": _70, \"imakane\": _70, \"ishikari\": _70, \"iwamizawa\": _70, \"iwanai\": _70, \"kamifurano\": _70, \"kamikawa\": _70, \"kamishihoro\": _70, \"kamisunagawa\": _70, \"kamoenai\": _70, \"kayabe\": _70, \"kembuchi\": _70, \"kikonai\": _70, \"kimobetsu\": _70, \"kitahiroshima\": _70, \"kitami\": _70, \"kiyosato\": _70, \"koshimizu\": _70, \"kunneppu\": _70, \"kuriyama\": _70,\n      \"kuromatsunai\": _70, \"kushiro\": _70, \"kutchan\": _70, \"kyowa\": _70, \"mashike\": _70, \"matsumae\": _70, \"mikasa\": _70, \"minamifurano\": _70, \"mombetsu\": _70, \"moseushi\": _70, \"mukawa\": _70, \"muroran\": _70, \"naie\": _70, \"nakagawa\": _70, \"nakasatsunai\": _70, \"nakatombetsu\": _70, \"nanae\": _70, \"nanporo\": _70, \"nayoro\": _70, \"nemuro\": _70, \"niikappu\": _70, \"niki\": _70, \"nishiokoppe\": _70, \"noboribetsu\": _70, \"numata\": _70, \"obihiro\": _70, \"obira\": _70, \"oketo\": _70, \"okoppe\": _70, \"otaru\": _70, \"otobe\": _70, \"otofuke\": _70, \"otoineppu\": _70, \"oumu\": _70, \"ozora\": _70, \"pippu\": _70, \"rankoshi\": _70, \"rebun\": _70, \"rikubetsu\": _70, \"rishiri\": _70, \"rishirifuji\": _70, \"saroma\": _70, \"sarufutsu\": _70, \"shakotan\": _70, \"shari\": _70, \"shibecha\": _70, \"shibetsu\": _70, \"shikabe\": _70, \"shikaoi\": _70, \"shimamaki\": _70, \"shimizu\": _70, \"shimokawa\": _70, \"shinshinotsu\": _70, \"shintoku\": _70, \"shiranuka\": _70, \"shiraoi\": _70, \"shiriuchi\": _70, \"sobetsu\": _70, \"sunagawa\": _70, \"taiki\": _70, \"takasu\": _70,\n      \"takikawa\": _70, \"takinoue\": _70, \"teshikaga\": _70, \"tobetsu\": _70, \"tohma\": _70, \"tomakomai\": _70, \"tomari\": _70, \"toya\": _70, \"toyako\": _70, \"toyotomi\": _70, \"toyoura\": _70, \"tsubetsu\": _70, \"tsukigata\": _70, \"urakawa\": _70, \"urausu\": _70, \"uryu\": _70, \"utashinai\": _70, \"wakkanai\": _70, \"wassamu\": _70, \"yakumo\": _70, \"yoichi\": _70 }], \"hyogo\": [1, { \"aioi\": _70, \"akashi\": _70, \"ako\": _70, \"amagasaki\": _70, \"aogaki\": _70, \"asago\": _70, \"ashiya\": _70, \"awaji\": _70, \"fukusaki\": _70, \"goshiki\": _70, \"harima\": _70, \"himeji\": _70, \"ichikawa\": _70, \"inagawa\": _70, \"itami\": _70, \"kakogawa\": _70, \"kamigori\": _70, \"kamikawa\": _70, \"kasai\": _70, \"kasuga\": _70, \"kawanishi\": _70, \"miki\": _70, \"minamiawaji\": _70, \"nishinomiya\": _70, \"nishiwaki\": _70, \"ono\": _70, \"sanda\": _70, \"sannan\": _70, \"sasayama\": _70, \"sayo\": _70, \"shingu\": _70, \"shinonsen\": _70, \"shiso\": _70, \"sumoto\": _70, \"taishi\": _70, \"taka\": _70, \"takarazuka\": _70, \"takasago\": _70, \"takino\": _70, \"tamba\": _70, \"tatsuno\": _70, \"to\\\nyooka\": _70, \"yabu\": _70, \"yashiro\": _70, \"yoka\": _70, \"yokawa\": _70 }], \"ibaraki\": [1, { \"ami\": _70, \"asahi\": _70, \"bando\": _70, \"chikusei\": _70, \"daigo\": _70, \"fujishiro\": _70, \"hitachi\": _70, \"hitachinaka\": _70, \"hitachiomiya\": _70, \"hitachiota\": _70, \"ibaraki\": _70, \"ina\": _70, \"inashiki\": _70, \"itako\": _70, \"iwama\": _70, \"joso\": _70, \"kamisu\": _70, \"kasama\": _70, \"kashima\": _70, \"kasumigaura\": _70, \"koga\": _70, \"miho\": _70, \"mito\": _70, \"moriya\": _70, \"naka\": _70, \"namegata\": _70, \"oarai\": _70, \"ogawa\": _70, \"omitama\": _70, \"ryugasaki\": _70, \"sakai\": _70, \"sakuragawa\": _70, \"shimodate\": _70, \"shimotsuma\": _70, \"shirosato\": _70, \"sowa\": _70, \"suifu\": _70, \"takahagi\": _70, \"tamatsukuri\": _70, \"tokai\": _70, \"tomobe\": _70, \"tone\": _70, \"toride\": _70, \"tsuchiura\": _70, \"tsukuba\": _70, \"uchihara\": _70, \"ushiku\": _70, \"yachiyo\": _70, \"yamagata\": _70, \"yawara\": _70, \"yuki\": _70 }], \"ishikawa\": [1, { \"anamizu\": _70, \"hakui\": _70, \"hakusan\": _70, \"kaga\": _70, \"kahoku\": _70, \"kanazawa\": _70,\n      \"kawakita\": _70, \"komatsu\": _70, \"nakanoto\": _70, \"nanao\": _70, \"nomi\": _70, \"nonoichi\": _70, \"noto\": _70, \"shika\": _70, \"suzu\": _70, \"tsubata\": _70, \"tsurugi\": _70, \"uchinada\": _70, \"wajima\": _70 }], \"iwate\": [1, { \"fudai\": _70, \"fujisawa\": _70, \"hanamaki\": _70, \"hiraizumi\": _70, \"hirono\": _70, \"ichinohe\": _70, \"ichinoseki\": _70, \"iwaizumi\": _70, \"iwate\": _70, \"joboji\": _70, \"kamaishi\": _70, \"kanegasaki\": _70, \"karumai\": _70, \"kawai\": _70, \"kitakami\": _70, \"kuji\": _70, \"kunohe\": _70, \"kuzumaki\": _70, \"miyako\": _70, \"mizusawa\": _70, \"morioka\": _70, \"ninohe\": _70, \"noda\": _70, \"ofunato\": _70, \"oshu\": _70, \"otsuchi\": _70, \"rikuzentakata\": _70, \"shiwa\": _70, \"shizukuishi\": _70, \"sumita\": _70, \"tanohata\": _70, \"tono\": _70, \"yahaba\": _70, \"yamada\": _70 }], \"kagawa\": [1, { \"ayagawa\": _70, \"higashikagawa\": _70, \"kanonji\": _70, \"kotohira\": _70, \"manno\": _70, \"marugame\": _70, \"mitoyo\": _70, \"naoshima\": _70, \"sanuki\": _70, \"tadotsu\": _70, \"takamatsu\": _70, \"tonosho\": _70, \"uchinomi\": _70, \"\\\nutazu\": _70, \"zentsuji\": _70 }], \"kagoshima\": [1, { \"akune\": _70, \"amami\": _70, \"hioki\": _70, \"isa\": _70, \"isen\": _70, \"izumi\": _70, \"kagoshima\": _70, \"kanoya\": _70, \"kawanabe\": _70, \"kinko\": _70, \"kouyama\": _70, \"makurazaki\": _70, \"matsumoto\": _70, \"minamitane\": _70, \"nakatane\": _70, \"nishinoomote\": _70, \"satsumasendai\": _70, \"soo\": _70, \"tarumizu\": _70, \"yusui\": _70 }], \"kanagawa\": [1, { \"aikawa\": _70, \"atsugi\": _70, \"ayase\": _70, \"chigasaki\": _70, \"ebina\": _70, \"fujisawa\": _70, \"hadano\": _70, \"hakone\": _70, \"hiratsuka\": _70, \"isehara\": _70, \"kaisei\": _70, \"kamakura\": _70, \"kiyokawa\": _70, \"matsuda\": _70, \"minamiashigara\": _70, \"miura\": _70, \"nakai\": _70, \"ninomiya\": _70, \"odawara\": _70, \"oi\": _70, \"oiso\": _70, \"sagamihara\": _70, \"samukawa\": _70, \"tsukui\": _70, \"yamakita\": _70, \"yamato\": _70, \"yokosuka\": _70, \"yugawara\": _70, \"zama\": _70, \"zushi\": _70 }], \"kochi\": [1, { \"aki\": _70, \"geisei\": _70, \"hidaka\": _70, \"higashitsuno\": _70, \"ino\": _70, \"kagami\": _70, \"kami\": _70, \"kitagawa\": _70,\n      \"kochi\": _70, \"mihara\": _70, \"motoyama\": _70, \"muroto\": _70, \"nahari\": _70, \"nakamura\": _70, \"nankoku\": _70, \"nishitosa\": _70, \"niyodogawa\": _70, \"ochi\": _70, \"okawa\": _70, \"otoyo\": _70, \"otsuki\": _70, \"sakawa\": _70, \"sukumo\": _70, \"susaki\": _70, \"tosa\": _70, \"tosashimizu\": _70, \"toyo\": _70, \"tsuno\": _70, \"umaji\": _70, \"yasuda\": _70, \"yusuhara\": _70 }], \"kumamoto\": [1, { \"amakusa\": _70, \"arao\": _70, \"aso\": _70, \"choyo\": _70, \"gyokuto\": _70, \"kamiamakusa\": _70, \"kikuchi\": _70, \"kumamoto\": _70, \"mashiki\": _70, \"mifune\": _70, \"minamata\": _70, \"minamioguni\": _70, \"nagasu\": _70, \"nishihara\": _70, \"oguni\": _70, \"ozu\": _70, \"sumoto\": _70, \"takamori\": _70, \"uki\": _70, \"uto\": _70, \"yamaga\": _70, \"yamato\": _70, \"yatsushiro\": _70 }], \"kyoto\": [1, { \"ayabe\": _70, \"fukuchiyama\": _70, \"higashiyama\": _70, \"ide\": _70, \"ine\": _70, \"joyo\": _70, \"kameoka\": _70, \"kamo\": _70, \"kita\": _70, \"kizu\": _70, \"kumiyama\": _70, \"kyotamba\": _70, \"kyotanabe\": _70, \"kyotango\": _70, \"maizuru\": _70, \"minami\": _70, \"\\\nminamiyamashiro\": _70, \"miyazu\": _70, \"muko\": _70, \"nagaokakyo\": _70, \"nakagyo\": _70, \"nantan\": _70, \"oyamazaki\": _70, \"sakyo\": _70, \"seika\": _70, \"tanabe\": _70, \"uji\": _70, \"ujitawara\": _70, \"wazuka\": _70, \"yamashina\": _70, \"yawata\": _70 }], \"mie\": [1, { \"asahi\": _70, \"inabe\": _70, \"ise\": _70, \"kameyama\": _70, \"kawagoe\": _70, \"kiho\": _70, \"kisosaki\": _70, \"kiwa\": _70, \"komono\": _70, \"kumano\": _70, \"kuwana\": _70, \"matsusaka\": _70, \"meiwa\": _70, \"mihama\": _70, \"minamiise\": _70, \"misugi\": _70, \"miyama\": _70, \"nabari\": _70, \"shima\": _70, \"suzuka\": _70, \"tado\": _70, \"taiki\": _70, \"taki\": _70, \"tamaki\": _70, \"toba\": _70, \"tsu\": _70, \"udono\": _70, \"ureshino\": _70, \"watarai\": _70, \"yokkaichi\": _70 }], \"miyagi\": [1, { \"furukawa\": _70, \"higashimatsushima\": _70, \"ishinomaki\": _70, \"iwanuma\": _70, \"kakuda\": _70, \"kami\": _70, \"kawasaki\": _70, \"marumori\": _70, \"matsushima\": _70, \"minamisanriku\": _70, \"misato\": _70, \"murata\": _70, \"natori\": _70, \"ogawara\": _70, \"ohira\": _70, \"onagawa\": _70, \"osaki\": _70,\n      \"rifu\": _70, \"semine\": _70, \"shibata\": _70, \"shichikashuku\": _70, \"shikama\": _70, \"shiogama\": _70, \"shiroishi\": _70, \"tagajo\": _70, \"taiwa\": _70, \"tome\": _70, \"tomiya\": _70, \"wakuya\": _70, \"watari\": _70, \"yamamoto\": _70, \"zao\": _70 }], \"miyazaki\": [1, { \"aya\": _70, \"ebino\": _70, \"gokase\": _70, \"hyuga\": _70, \"kadogawa\": _70, \"kawaminami\": _70, \"kijo\": _70, \"kitagawa\": _70, \"kitakata\": _70, \"kitaura\": _70, \"kobayashi\": _70, \"kunitomi\": _70, \"kushima\": _70, \"mimata\": _70, \"miyakonojo\": _70, \"miyazaki\": _70, \"morotsuka\": _70, \"nichinan\": _70, \"nishimera\": _70, \"nobeoka\": _70, \"saito\": _70, \"shiiba\": _70, \"shintomi\": _70, \"takaharu\": _70, \"takanabe\": _70, \"takazaki\": _70, \"tsuno\": _70 }], \"nagano\": [1, { \"achi\": _70, \"agematsu\": _70, \"anan\": _70, \"aoki\": _70, \"asahi\": _70, \"azumino\": _70, \"chikuhoku\": _70, \"chikuma\": _70, \"chino\": _70, \"fujimi\": _70, \"hakuba\": _70, \"hara\": _70, \"hiraya\": _70, \"iida\": _70, \"iijima\": _70, \"iiyama\": _70, \"iizuna\": _70, \"ikeda\": _70, \"ikusaka\": _70, \"ina\": _70,\n      \"karuizawa\": _70, \"kawakami\": _70, \"kiso\": _70, \"kisofukushima\": _70, \"kitaaiki\": _70, \"komagane\": _70, \"komoro\": _70, \"matsukawa\": _70, \"matsumoto\": _70, \"miasa\": _70, \"minamiaiki\": _70, \"minamimaki\": _70, \"minamiminowa\": _70, \"minowa\": _70, \"miyada\": _70, \"miyota\": _70, \"mochizuki\": _70, \"nagano\": _70, \"nagawa\": _70, \"nagiso\": _70, \"nakagawa\": _70, \"nakano\": _70, \"nozawaonsen\": _70, \"obuse\": _70, \"ogawa\": _70, \"okaya\": _70, \"omachi\": _70, \"omi\": _70, \"ookuwa\": _70, \"ooshika\": _70, \"otaki\": _70, \"otari\": _70, \"sakae\": _70, \"sakaki\": _70, \"saku\": _70, \"sakuho\": _70, \"shimosuwa\": _70, \"shinanomachi\": _70, \"shiojiri\": _70, \"suwa\": _70, \"suzaka\": _70, \"takagi\": _70, \"takamori\": _70, \"takayama\": _70, \"tateshina\": _70, \"tatsuno\": _70, \"togakushi\": _70, \"togura\": _70, \"tomi\": _70, \"ueda\": _70, \"wada\": _70, \"yamagata\": _70, \"yamanouchi\": _70, \"yasaka\": _70, \"yasuoka\": _70 }], \"nagasaki\": [1, { \"chijiwa\": _70, \"futsu\": _70, \"goto\": _70, \"hasami\": _70, \"hirado\": _70, \"iki\": _70, \"isahaya\": _70,\n      \"kawatana\": _70, \"kuchinotsu\": _70, \"matsuura\": _70, \"nagasaki\": _70, \"obama\": _70, \"omura\": _70, \"oseto\": _70, \"saikai\": _70, \"sasebo\": _70, \"seihi\": _70, \"shimabara\": _70, \"shinkamigoto\": _70, \"togitsu\": _70, \"tsushima\": _70, \"unzen\": _70 }], \"nara\": [1, { \"ando\": _70, \"gose\": _70, \"heguri\": _70, \"higashiyoshino\": _70, \"ikaruga\": _70, \"ikoma\": _70, \"kamikitayama\": _70, \"kanmaki\": _70, \"kashiba\": _70, \"kashihara\": _70, \"katsuragi\": _70, \"kawai\": _70, \"kawakami\": _70, \"kawanishi\": _70, \"koryo\": _70, \"kurotaki\": _70, \"mitsue\": _70, \"miyake\": _70, \"nara\": _70, \"nosegawa\": _70, \"oji\": _70, \"ouda\": _70, \"oyodo\": _70, \"sakurai\": _70, \"sango\": _70, \"shimoichi\": _70, \"shimokitayama\": _70, \"shinjo\": _70, \"soni\": _70, \"takatori\": _70, \"tawaramoto\": _70, \"tenkawa\": _70, \"tenri\": _70, \"uda\": _70, \"yamatokoriyama\": _70, \"yamatotakada\": _70, \"yamazoe\": _70, \"yoshino\": _70 }], \"niigata\": [1, { \"aga\": _70, \"agano\": _70, \"gosen\": _70, \"itoigawa\": _70, \"izumozaki\": _70, \"joetsu\": _70, \"kamo\": _70,\n      \"kariwa\": _70, \"kashiwazaki\": _70, \"minamiuonuma\": _70, \"mitsuke\": _70, \"muika\": _70, \"murakami\": _70, \"myoko\": _70, \"nagaoka\": _70, \"niigata\": _70, \"ojiya\": _70, \"omi\": _70, \"sado\": _70, \"sanjo\": _70, \"seiro\": _70, \"seirou\": _70, \"sekikawa\": _70, \"shibata\": _70, \"tagami\": _70, \"tainai\": _70, \"tochio\": _70, \"tokamachi\": _70, \"tsubame\": _70, \"tsunan\": _70, \"uonuma\": _70, \"yahiko\": _70, \"yoita\": _70, \"yuzawa\": _70 }], \"oita\": [1, { \"beppu\": _70, \"bungoono\": _70, \"bungotakada\": _70, \"hasama\": _70, \"hiji\": _70, \"himeshima\": _70, \"hita\": _70, \"kamitsue\": _70, \"kokonoe\": _70, \"kuju\": _70, \"kunisaki\": _70, \"kusu\": _70, \"oita\": _70, \"saiki\": _70, \"taketa\": _70, \"tsukumi\": _70, \"usa\": _70, \"usuki\": _70, \"yufu\": _70 }], \"okayama\": [1, { \"akaiwa\": _70, \"asakuchi\": _70, \"bizen\": _70, \"hayashima\": _70, \"ibara\": _70, \"kagamino\": _70, \"kasaoka\": _70, \"kibichuo\": _70, \"kumenan\": _70, \"kurashiki\": _70, \"maniwa\": _70, \"misaki\": _70, \"nagi\": _70, \"niimi\": _70, \"nishiawakura\": _70, \"okayama\": _70, \"\\\nsatosho\": _70, \"setouchi\": _70, \"shinjo\": _70, \"shoo\": _70, \"soja\": _70, \"takahashi\": _70, \"tamano\": _70, \"tsuyama\": _70, \"wake\": _70, \"yakage\": _70 }], \"okinawa\": [1, { \"aguni\": _70, \"ginowan\": _70, \"ginoza\": _70, \"gushikami\": _70, \"haebaru\": _70, \"higashi\": _70, \"hirara\": _70, \"iheya\": _70, \"ishigaki\": _70, \"ishikawa\": _70, \"itoman\": _70, \"izena\": _70, \"kadena\": _70, \"kin\": _70, \"kitadaito\": _70, \"kitanakagusuku\": _70, \"kumejima\": _70, \"kunigami\": _70, \"minamidaito\": _70, \"motobu\": _70, \"nago\": _70, \"naha\": _70, \"nakagusuku\": _70, \"nakijin\": _70, \"nanjo\": _70, \"nishihara\": _70, \"ogimi\": _70, \"okinawa\": _70, \"onna\": _70, \"shimoji\": _70, \"taketomi\": _70, \"tarama\": _70, \"tokashiki\": _70, \"tomigusuku\": _70, \"tonaki\": _70, \"urasoe\": _70, \"uruma\": _70, \"yaese\": _70, \"yomitan\": _70, \"yonabaru\": _70, \"yonaguni\": _70, \"zamami\": _70 }], \"osaka\": [1, { \"abeno\": _70, \"chihayaakasaka\": _70, \"chuo\": _70, \"daito\": _70, \"fujiidera\": _70, \"habikino\": _70, \"hannan\": _70, \"higashiosaka\": _70, \"higashis\\\numiyoshi\": _70, \"higashiyodogawa\": _70, \"hirakata\": _70, \"ibaraki\": _70, \"ikeda\": _70, \"izumi\": _70, \"izumiotsu\": _70, \"izumisano\": _70, \"kadoma\": _70, \"kaizuka\": _70, \"kanan\": _70, \"kashiwara\": _70, \"katano\": _70, \"kawachinagano\": _70, \"kishiwada\": _70, \"kita\": _70, \"kumatori\": _70, \"matsubara\": _70, \"minato\": _70, \"minoh\": _70, \"misaki\": _70, \"moriguchi\": _70, \"neyagawa\": _70, \"nishi\": _70, \"nose\": _70, \"osakasayama\": _70, \"sakai\": _70, \"sayama\": _70, \"sennan\": _70, \"settsu\": _70, \"shijonawate\": _70, \"shimamoto\": _70, \"suita\": _70, \"tadaoka\": _70, \"taishi\": _70, \"tajiri\": _70, \"takaishi\": _70, \"takatsuki\": _70, \"tondabayashi\": _70, \"toyonaka\": _70, \"toyono\": _70, \"yao\": _70 }], \"saga\": [1, { \"ariake\": _70, \"arita\": _70, \"fukudomi\": _70, \"genkai\": _70, \"hamatama\": _70, \"hizen\": _70, \"imari\": _70, \"kamimine\": _70, \"kanzaki\": _70, \"karatsu\": _70, \"kashima\": _70, \"kitagata\": _70, \"kitahata\": _70, \"kiyama\": _70, \"kouhoku\": _70, \"kyuragi\": _70, \"nishiarita\": _70, \"ogi\": _70, \"omachi\": _70,\n      \"ouchi\": _70, \"saga\": _70, \"shiroishi\": _70, \"taku\": _70, \"tara\": _70, \"tosu\": _70, \"yoshinogari\": _70 }], \"saitama\": [1, { \"arakawa\": _70, \"asaka\": _70, \"chichibu\": _70, \"fujimi\": _70, \"fujimino\": _70, \"fukaya\": _70, \"hanno\": _70, \"hanyu\": _70, \"hasuda\": _70, \"hatogaya\": _70, \"hatoyama\": _70, \"hidaka\": _70, \"higashichichibu\": _70, \"higashimatsuyama\": _70, \"honjo\": _70, \"ina\": _70, \"iruma\": _70, \"iwatsuki\": _70, \"kamiizumi\": _70, \"kamikawa\": _70, \"kamisato\": _70, \"kasukabe\": _70, \"kawagoe\": _70, \"kawaguchi\": _70, \"kawajima\": _70, \"kazo\": _70, \"kitamoto\": _70, \"koshigaya\": _70, \"kounosu\": _70, \"kuki\": _70, \"kumagaya\": _70, \"matsubushi\": _70, \"minano\": _70, \"misato\": _70, \"miyashiro\": _70, \"miyoshi\": _70, \"moroyama\": _70, \"nagatoro\": _70, \"namegawa\": _70, \"niiza\": _70, \"ogano\": _70, \"ogawa\": _70, \"ogose\": _70, \"okegawa\": _70, \"omiya\": _70, \"otaki\": _70, \"ranzan\": _70, \"ryokami\": _70, \"saitama\": _70, \"sakado\": _70, \"satte\": _70, \"sayama\": _70, \"shiki\": _70, \"shiraoka\": _70, \"soka\": _70,\n      \"sugito\": _70, \"toda\": _70, \"tokigawa\": _70, \"tokorozawa\": _70, \"tsurugashima\": _70, \"urawa\": _70, \"warabi\": _70, \"yashio\": _70, \"yokoze\": _70, \"yono\": _70, \"yorii\": _70, \"yoshida\": _70, \"yoshikawa\": _70, \"yoshimi\": _70 }], \"shiga\": [1, { \"aisho\": _70, \"gamo\": _70, \"higashiomi\": _70, \"hikone\": _70, \"koka\": _70, \"konan\": _70, \"kosei\": _70, \"koto\": _70, \"kusatsu\": _70, \"maibara\": _70, \"moriyama\": _70, \"nagahama\": _70, \"nishiazai\": _70, \"notogawa\": _70, \"omihachiman\": _70, \"otsu\": _70, \"ritto\": _70, \"ryuoh\": _70, \"takashima\": _70, \"takatsuki\": _70, \"torahime\": _70, \"toyosato\": _70, \"yasu\": _70 }], \"shimane\": [1, { \"akagi\": _70, \"ama\": _70, \"gotsu\": _70, \"hamada\": _70, \"higashiizumo\": _70, \"hikawa\": _70, \"hikimi\": _70, \"izumo\": _70, \"kakinoki\": _70, \"masuda\": _70, \"matsue\": _70, \"misato\": _70, \"nishinoshima\": _70, \"ohda\": _70, \"okinoshima\": _70, \"okuizumo\": _70, \"shimane\": _70, \"tamayu\": _70, \"tsuwano\": _70, \"unnan\": _70, \"yakumo\": _70, \"yasugi\": _70, \"yatsuka\": _70 }], \"shizuoka\": [\n      1, { \"arai\": _70, \"atami\": _70, \"fuji\": _70, \"fujieda\": _70, \"fujikawa\": _70, \"fujinomiya\": _70, \"fukuroi\": _70, \"gotemba\": _70, \"haibara\": _70, \"hamamatsu\": _70, \"higashiizu\": _70, \"ito\": _70, \"iwata\": _70, \"izu\": _70, \"izunokuni\": _70, \"kakegawa\": _70, \"kannami\": _70, \"kawanehon\": _70, \"kawazu\": _70, \"kikugawa\": _70, \"kosai\": _70, \"makinohara\": _70, \"matsuzaki\": _70, \"minamiizu\": _70, \"mishima\": _70, \"morimachi\": _70, \"nishiizu\": _70, \"numazu\": _70, \"omaezaki\": _70, \"shimada\": _70, \"shimizu\": _70, \"shimoda\": _70, \"shizuoka\": _70, \"susono\": _70, \"yaizu\": _70, \"yoshida\": _70 }], \"tochigi\": [1, { \"ashikaga\": _70, \"bato\": _70, \"haga\": _70, \"ichikai\": _70, \"iwafune\": _70, \"kaminokawa\": _70, \"kanuma\": _70, \"karasuyama\": _70, \"kuroiso\": _70, \"mashiko\": _70, \"mibu\": _70, \"moka\": _70, \"motegi\": _70, \"nasu\": _70, \"nasushiobara\": _70, \"nikko\": _70, \"nishikata\": _70, \"nogi\": _70, \"ohira\": _70, \"ohtawara\": _70, \"oyama\": _70, \"sakura\": _70, \"sano\": _70, \"shimotsuke\": _70, \"shioya\": _70, \"tak\\\nanezawa\": _70, \"tochigi\": _70, \"tsuga\": _70, \"ujiie\": _70, \"utsunomiya\": _70, \"yaita\": _70 }], \"tokushima\": [1, { \"aizumi\": _70, \"anan\": _70, \"ichiba\": _70, \"itano\": _70, \"kainan\": _70, \"komatsushima\": _70, \"matsushige\": _70, \"mima\": _70, \"minami\": _70, \"miyoshi\": _70, \"mugi\": _70, \"nakagawa\": _70, \"naruto\": _70, \"sanagochi\": _70, \"shishikui\": _70, \"tokushima\": _70, \"wajiki\": _70 }], \"tokyo\": [1, { \"adachi\": _70, \"akiruno\": _70, \"akishima\": _70, \"aogashima\": _70, \"arakawa\": _70, \"bunkyo\": _70, \"chiyoda\": _70, \"chofu\": _70, \"chuo\": _70, \"edogawa\": _70, \"fuchu\": _70, \"fussa\": _70, \"hachijo\": _70, \"hachioji\": _70, \"hamura\": _70, \"higashikurume\": _70, \"higashimurayama\": _70, \"higashiyamato\": _70, \"hino\": _70, \"hinode\": _70, \"hinohara\": _70, \"inagi\": _70, \"itabashi\": _70, \"katsushika\": _70, \"kita\": _70, \"kiyose\": _70, \"kodaira\": _70, \"koganei\": _70, \"kokubunji\": _70, \"komae\": _70, \"koto\": _70, \"kouzushima\": _70, \"kunitachi\": _70, \"machida\": _70, \"meguro\": _70, \"minato\": _70, \"mitaka\": _70, \"\\\nmizuho\": _70, \"musashimurayama\": _70, \"musashino\": _70, \"nakano\": _70, \"nerima\": _70, \"ogasawara\": _70, \"okutama\": _70, \"ome\": _70, \"oshima\": _70, \"ota\": _70, \"setagaya\": _70, \"shibuya\": _70, \"shinagawa\": _70, \"shinjuku\": _70, \"suginami\": _70, \"sumida\": _70, \"tachikawa\": _70, \"taito\": _70, \"tama\": _70, \"toshima\": _70 }], \"tottori\": [1, { \"chizu\": _70, \"hino\": _70, \"kawahara\": _70, \"koge\": _70, \"kotoura\": _70, \"misasa\": _70, \"nanbu\": _70, \"nichinan\": _70, \"sakaiminato\": _70, \"tottori\": _70, \"wakasa\": _70, \"yazu\": _70, \"yonago\": _70 }], \"toyama\": [1, { \"asahi\": _70, \"fuchu\": _70, \"fukumitsu\": _70, \"funahashi\": _70, \"himi\": _70, \"imizu\": _70, \"inami\": _70, \"johana\": _70, \"kamiichi\": _70, \"kurobe\": _70, \"nakaniikawa\": _70, \"namerikawa\": _70, \"nanto\": _70, \"nyuzen\": _70, \"oyabe\": _70, \"taira\": _70, \"takaoka\": _70, \"tateyama\": _70, \"toga\": _70, \"tonami\": _70, \"toyama\": _70, \"unazuki\": _70, \"uozu\": _70, \"yamada\": _70 }], \"wakayama\": [1, { \"arida\": _70, \"aridagawa\": _70, \"gobo\": _70, \"hashimot\\\no\": _70, \"hidaka\": _70, \"hirogawa\": _70, \"inami\": _70, \"iwade\": _70, \"kainan\": _70, \"kamitonda\": _70, \"katsuragi\": _70, \"kimino\": _70, \"kinokawa\": _70, \"kitayama\": _70, \"koya\": _70, \"koza\": _70, \"kozagawa\": _70, \"kudoyama\": _70, \"kushimoto\": _70, \"mihama\": _70, \"misato\": _70, \"nachikatsuura\": _70, \"shingu\": _70, \"shirahama\": _70, \"taiji\": _70, \"tanabe\": _70, \"wakayama\": _70, \"yuasa\": _70, \"yura\": _70 }], \"yamagata\": [1, { \"asahi\": _70, \"funagata\": _70, \"higashine\": _70, \"iide\": _70, \"kahoku\": _70, \"kaminoyama\": _70, \"kaneyama\": _70, \"kawanishi\": _70, \"mamurogawa\": _70, \"mikawa\": _70, \"murayama\": _70, \"nagai\": _70, \"nakayama\": _70, \"nanyo\": _70, \"nishikawa\": _70, \"obanazawa\": _70, \"oe\": _70, \"oguni\": _70, \"ohkura\": _70, \"oishida\": _70, \"sagae\": _70, \"sakata\": _70, \"sakegawa\": _70, \"shinjo\": _70, \"shirataka\": _70, \"shonai\": _70, \"takahata\": _70, \"tendo\": _70, \"tozawa\": _70, \"tsuruoka\": _70, \"yamagata\": _70, \"yamanobe\": _70, \"yonezawa\": _70, \"yuza\": _70 }], \"yamaguchi\": [1, { \"abu\": _70, \"\\\nhagi\": _70, \"hikari\": _70, \"hofu\": _70, \"iwakuni\": _70, \"kudamatsu\": _70, \"mitou\": _70, \"nagato\": _70, \"oshima\": _70, \"shimonoseki\": _70, \"shunan\": _70, \"tabuse\": _70, \"tokuyama\": _70, \"toyota\": _70, \"ube\": _70, \"yuu\": _70 }], \"yamanashi\": [1, { \"chuo\": _70, \"doshi\": _70, \"fuefuki\": _70, \"fujikawa\": _70, \"fujikawaguchiko\": _70, \"fujiyoshida\": _70, \"hayakawa\": _70, \"hokuto\": _70, \"ichikawamisato\": _70, \"kai\": _70, \"kofu\": _70, \"koshu\": _70, \"kosuge\": _70, \"minami-alps\": _70, \"minobu\": _70, \"nakamichi\": _70, \"nanbu\": _70, \"narusawa\": _70, \"nirasaki\": _70, \"nishikatsura\": _70, \"oshino\": _70, \"otsuki\": _70, \"showa\": _70, \"tabayama\": _70, \"tsuru\": _70, \"uenohara\": _70, \"yamanakako\": _70, \"yamanashi\": _70 }], \"xn--ehqz56n\": _70, \"三重\": _70, \"xn--1lqs03n\": _70, \"京都\": _70, \"xn--qqqt11m\": _70, \"佐賀\": _70, \"xn--f6qx53a\": _70, \"兵庫\": _70, \"xn--djrs72d6uy\": _70, \"北海道\": _70, \"xn--mkru45i\": _70, \"千葉\": _70, \"xn--0trq7p7nn\": _70, \"和歌山\": _70, \"xn--5js045d\": _70, \"埼玉\": _70,\n      \"xn--kbrq7o\": _70, \"大分\": _70, \"xn--pssu33l\": _70, \"大阪\": _70, \"xn--ntsq17g\": _70, \"奈良\": _70, \"xn--uisz3g\": _70, \"宮城\": _70, \"xn--6btw5a\": _70, \"宮崎\": _70, \"xn--1ctwo\": _70, \"富山\": _70, \"xn--6orx2r\": _70, \"山口\": _70, \"xn--rht61e\": _70, \"山形\": _70, \"xn--rht27z\": _70, \"山梨\": _70, \"xn--nit225k\": _70, \"岐阜\": _70, \"xn--rht3d\": _70, \"岡山\": _70, \"xn--djty4k\": _70, \"岩手\": _70, \"xn--klty5x\": _70, \"島根\": _70, \"xn--kltx9a\": _70, \"広島\": _70, \"xn--kltp7d\": _70, \"徳島\": _70, \"xn--c3s14m\": _70, \"愛媛\": _70, \"xn--vgu402c\": _70, \"愛知\": _70, \"xn--efvn9s\": _70, \"新潟\": _70, \"xn--1lqs71d\": _70, \"東京\": _70, \"xn--4pvxs\": _70, \"栃木\": _70, \"xn--uuwu58a\": _70, \"沖縄\": _70, \"xn--zbx025d\": _70, \"滋賀\": _70, \"xn--8pvr4u\": _70, \"熊本\": _70, \"xn--5rtp49c\": _70, \"石川\": _70, \"xn--ntso0iqx3a\": _70, \"神奈川\": _70, \"xn--elqq16h\": _70, \"福井\": _70, \"xn--4it168d\": _70, \"福岡\": _70, \"xn--klt787d\": _70, \"福島\": _70, \"xn--rny31h\": _70, \"秋田\": _70,\n      \"xn--7t0a264c\": _70, \"群馬\": _70, \"xn--uist22h\": _70, \"茨城\": _70, \"xn--8ltr62k\": _70, \"長崎\": _70, \"xn--2m4a15e\": _70, \"長野\": _70, \"xn--32vp30h\": _70, \"青森\": _70, \"xn--4it797k\": _70, \"静岡\": _70, \"xn--5rtq34k\": _70, \"香川\": _70, \"xn--k7yn95e\": _70, \"高知\": _70, \"xn--tor131o\": _70, \"鳥取\": _70, \"xn--d5qv7z876c\": _70, \"鹿児島\": _70, \"kawasaki\": _74, \"kitakyushu\": _74, \"kobe\": _74, \"nagoya\": _74, \"sapporo\": _74, \"sendai\": _74, \"yokohama\": _74 }], \"ke\": [1, { \"ac\": _70, \"co\": _70, \"go\": _70, \"info\": _70, \"me\": _70, \"mobi\": _70, \"ne\": _70, \"or\": _70, \"sc\": _70 }], \"kg\": _71, \"kh\": _74, \"ki\": _79, \"km\": [1, { \"ass\": _70, \"com\": _70, \"edu\": _70, \"gov\": _70, \"mil\": _70, \"nom\": _70, \"org\": _70, \"prd\": _70, \"tm\": _70, \"asso\": _70, \"coop\": _70, \"gouv\": _70, \"medecin\": _70, \"notaires\": _70, \"pharmaciens\": _70, \"presse\": _70, \"veterinaire\": _70 }], \"kn\": [1, { \"edu\": _70, \"gov\": _70, \"net\": _70, \"org\": _70 }], \"kp\": [1, { \"com\": _70, \"edu\": _70, \"gov\": _70, \"org\": _70,\n      \"rep\": _70, \"tra\": _70 }], \"kr\": [1, { \"ac\": _70, \"ai\": _70, \"co\": _70, \"es\": _70, \"go\": _70, \"hs\": _70, \"io\": _70, \"it\": _70, \"kg\": _70, \"me\": _70, \"mil\": _70, \"ms\": _70, \"ne\": _70, \"or\": _70, \"pe\": _70, \"re\": _70, \"sc\": _70, \"busan\": _70, \"chungbuk\": _70, \"chungnam\": _70, \"daegu\": _70, \"daejeon\": _70, \"gangwon\": _70, \"gwangju\": _70, \"gyeongbuk\": _70, \"gyeonggi\": _70, \"gyeongnam\": _70, \"incheon\": _70, \"jeju\": _70, \"jeonbuk\": _70, \"jeonnam\": _70, \"seoul\": _70, \"ulsan\": _70 }], \"kw\": [1, { \"com\": _70, \"edu\": _70, \"emb\": _70, \"gov\": _70, \"ind\": _70, \"net\": _70, \"org\": _70 }], \"ky\": _76, \"kz\": _71, \"la\": [1, { \"com\": _70, \"edu\": _70, \"gov\": _70, \"info\": _70, \"int\": _70, \"net\": _70, \"org\": _70, \"per\": _70 }], \"lb\": _72, \"lc\": _75, \"li\": _70, \"lk\": [1, { \"ac\": _70, \"assn\": _70, \"com\": _70, \"edu\": _70, \"gov\": _70, \"grp\": _70, \"hotel\": _70, \"int\": _70, \"ltd\": _70, \"net\": _70, \"ngo\": _70, \"org\": _70, \"sch\": _70, \"soc\": _70, \"web\": _70 }], \"lr\": _72, \"ls\": [1, { \"ac\": _70, \"biz\": _70, \"co\": _70,\n      \"edu\": _70, \"gov\": _70, \"info\": _70, \"net\": _70, \"org\": _70, \"sc\": _70 }], \"lt\": _73, \"lu\": _70, \"lv\": [1, { \"asn\": _70, \"com\": _70, \"conf\": _70, \"edu\": _70, \"gov\": _70, \"id\": _70, \"mil\": _70, \"net\": _70, \"org\": _70 }], \"ly\": [1, { \"com\": _70, \"edu\": _70, \"gov\": _70, \"id\": _70, \"med\": _70, \"net\": _70, \"org\": _70, \"plc\": _70, \"sch\": _70 }], \"ma\": [1, { \"ac\": _70, \"co\": _70, \"gov\": _70, \"net\": _70, \"org\": _70, \"press\": _70 }], \"mc\": [1, { \"asso\": _70, \"tm\": _70 }], \"md\": _70, \"me\": [1, { \"ac\": _70, \"co\": _70, \"edu\": _70, \"gov\": _70, \"its\": _70, \"net\": _70, \"org\": _70, \"priv\": _70 }], \"mg\": [1, { \"co\": _70, \"com\": _70, \"edu\": _70, \"gov\": _70, \"mil\": _70, \"nom\": _70, \"org\": _70, \"prd\": _70 }], \"mh\": _70, \"mil\": _70, \"mk\": [1, { \"com\": _70, \"edu\": _70, \"gov\": _70, \"inf\": _70, \"name\": _70, \"net\": _70, \"org\": _70 }], \"ml\": [1, { \"ac\": _70, \"art\": _70, \"asso\": _70, \"com\": _70, \"edu\": _70, \"gouv\": _70, \"gov\": _70, \"info\": _70, \"inst\": _70, \"net\": _70, \"org\": _70, \"pr\": _70, \"presse\": _70 }],\n      \"mm\": _74, \"mn\": [1, { \"edu\": _70, \"gov\": _70, \"org\": _70 }], \"mo\": _72, \"mobi\": _70, \"mp\": _70, \"mq\": _70, \"mr\": _73, \"ms\": _72, \"mt\": _76, \"mu\": [1, { \"ac\": _70, \"co\": _70, \"com\": _70, \"gov\": _70, \"net\": _70, \"or\": _70, \"org\": _70 }], \"museum\": _70, \"mv\": [1, { \"aero\": _70, \"biz\": _70, \"com\": _70, \"coop\": _70, \"edu\": _70, \"gov\": _70, \"info\": _70, \"int\": _70, \"mil\": _70, \"museum\": _70, \"name\": _70, \"net\": _70, \"org\": _70, \"pro\": _70 }], \"mw\": [1, { \"ac\": _70, \"biz\": _70, \"co\": _70, \"com\": _70, \"coop\": _70, \"edu\": _70, \"gov\": _70, \"int\": _70, \"net\": _70, \"org\": _70 }], \"mx\": [1, { \"com\": _70, \"edu\": _70, \"gob\": _70, \"net\": _70, \"org\": _70 }], \"my\": [1, { \"biz\": _70, \"com\": _70, \"edu\": _70, \"gov\": _70, \"mil\": _70, \"name\": _70, \"net\": _70, \"org\": _70 }], \"mz\": [1, { \"ac\": _70, \"adv\": _70, \"co\": _70, \"edu\": _70, \"gov\": _70, \"mil\": _70, \"net\": _70, \"org\": _70 }], \"na\": [1, { \"alt\": _70, \"co\": _70, \"com\": _70, \"gov\": _70, \"net\": _70, \"org\": _70 }], \"name\": _70, \"nc\": [1, { \"asso\": _70,\n      \"nom\": _70 }], \"ne\": _70, \"net\": _70, \"nf\": [1, { \"arts\": _70, \"com\": _70, \"firm\": _70, \"info\": _70, \"net\": _70, \"other\": _70, \"per\": _70, \"rec\": _70, \"store\": _70, \"web\": _70 }], \"ng\": [1, { \"com\": _70, \"edu\": _70, \"gov\": _70, \"i\": _70, \"mil\": _70, \"mobi\": _70, \"name\": _70, \"net\": _70, \"org\": _70, \"sch\": _70 }], \"ni\": [1, { \"ac\": _70, \"biz\": _70, \"co\": _70, \"com\": _70, \"edu\": _70, \"gob\": _70, \"in\": _70, \"info\": _70, \"int\": _70, \"mil\": _70, \"net\": _70, \"nom\": _70, \"org\": _70, \"web\": _70 }], \"nl\": _70, \"no\": [1, { \"fhs\": _70, \"folkebibl\": _70, \"fylkesbibl\": _70, \"idrett\": _70, \"museum\": _70, \"priv\": _70, \"vgs\": _70, \"dep\": _70, \"herad\": _70, \"kommune\": _70, \"mil\": _70, \"stat\": _70, \"aa\": _80, \"ah\": _80, \"bu\": _80, \"fm\": _80, \"hl\": _80, \"hm\": _80, \"jan-mayen\": _80, \"mr\": _80, \"nl\": _80, \"nt\": _80, \"of\": _80, \"ol\": _80, \"oslo\": _80, \"rl\": _80, \"sf\": _80, \"st\": _80, \"svalbard\": _80, \"tm\": _80, \"tr\": _80, \"va\": _80, \"vf\": _80, \"akrehamn\": _70, \"xn--krehamn-dxa\": _70, \"åkrehamn\": _70,\n      \"algard\": _70, \"xn--lgrd-poac\": _70, \"ålgård\": _70, \"arna\": _70, \"bronnoysund\": _70, \"xn--brnnysund-m8ac\": _70, \"brønnøysund\": _70, \"brumunddal\": _70, \"bryne\": _70, \"drobak\": _70, \"xn--drbak-wua\": _70, \"drøbak\": _70, \"egersund\": _70, \"fetsund\": _70, \"floro\": _70, \"xn--flor-jra\": _70, \"florø\": _70, \"fredrikstad\": _70, \"hokksund\": _70, \"honefoss\": _70, \"xn--hnefoss-q1a\": _70, \"hønefoss\": _70, \"jessheim\": _70, \"jorpeland\": _70, \"xn--jrpeland-54a\": _70, \"jørpeland\": _70, \"kirkenes\": _70, \"kopervik\": _70, \"krokstadelva\": _70, \"langevag\": _70, \"xn--langevg-jxa\": _70, \"langevåg\": _70, \"leirvik\": _70, \"mjondalen\": _70, \"xn--mjndalen-64a\": _70, \"mjøndalen\": _70, \"mo-i-rana\": _70, \"mosjoen\": _70, \"xn--mosjen-eya\": _70, \"mosjøen\": _70, \"nesoddtangen\": _70, \"orkanger\": _70, \"osoyro\": _70, \"xn--osyro-wua\": _70, \"osøyro\": _70, \"raholt\": _70, \"xn--rholt-mra\": _70, \"råholt\": _70, \"sandnessjoen\": _70, \"xn--sandnessjen-ogb\": _70, \"sandnessjøen\": _70, \"skedsmokorset\": _70, \"slattum\": _70,\n      \"spjelkavik\": _70, \"stathelle\": _70, \"stavern\": _70, \"stjordalshalsen\": _70, \"xn--stjrdalshalsen-sqb\": _70, \"stjørdalshalsen\": _70, \"tananger\": _70, \"tranby\": _70, \"vossevangen\": _70, \"aarborte\": _70, \"aejrie\": _70, \"afjord\": _70, \"xn--fjord-lra\": _70, \"åfjord\": _70, \"agdenes\": _70, \"akershus\": _81, \"aknoluokta\": _70, \"xn--koluokta-7ya57h\": _70, \"ákŋoluokta\": _70, \"al\": _70, \"xn--l-1fa\": _70, \"ål\": _70, \"alaheadju\": _70, \"xn--laheadju-7ya\": _70, \"álaheadju\": _70, \"alesund\": _70, \"xn--lesund-hua\": _70, \"ålesund\": _70, \"alstahaug\": _70, \"alta\": _70, \"xn--lt-liac\": _70, \"áltá\": _70, \"alvdal\": _70, \"amli\": _70, \"xn--mli-tla\": _70, \"åmli\": _70, \"amot\": _70, \"xn--mot-tla\": _70, \"åmot\": _70, \"andasuolo\": _70, \"andebu\": _70, \"andoy\": _70, \"xn--andy-ira\": _70, \"andøy\": _70, \"ardal\": _70, \"xn--rdal-poa\": _70, \"årdal\": _70, \"aremark\": _70, \"arendal\": _70, \"xn--s-1fa\": _70, \"ås\": _70, \"aseral\": _70, \"xn--seral-lra\": _70, \"åseral\": _70, \"asker\": _70, \"askim\": _70, \"askoy\": _70,\n      \"xn--asky-ira\": _70, \"askøy\": _70, \"askvoll\": _70, \"asnes\": _70, \"xn--snes-poa\": _70, \"åsnes\": _70, \"audnedaln\": _70, \"aukra\": _70, \"aure\": _70, \"aurland\": _70, \"aurskog-holand\": _70, \"xn--aurskog-hland-jnb\": _70, \"aurskog-høland\": _70, \"austevoll\": _70, \"austrheim\": _70, \"averoy\": _70, \"xn--avery-yua\": _70, \"averøy\": _70, \"badaddja\": _70, \"xn--bdddj-mrabd\": _70, \"bådåddjå\": _70, \"xn--brum-voa\": _70, \"bærum\": _70, \"bahcavuotna\": _70, \"xn--bhcavuotna-s4a\": _70, \"báhcavuotna\": _70, \"bahccavuotna\": _70, \"xn--bhccavuotna-k7a\": _70, \"báhccavuotna\": _70, \"baidar\": _70, \"xn--bidr-5nac\": _70, \"báidár\": _70, \"bajddar\": _70, \"xn--bjddar-pta\": _70, \"bájddar\": _70, \"balat\": _70, \"xn--blt-elab\": _70, \"bálát\": _70, \"balestrand\": _70, \"ballangen\": _70, \"balsfjord\": _70, \"bamble\": _70, \"bardu\": _70, \"barum\": _70, \"batsfjord\": _70, \"xn--btsfjord-9za\": _70, \"båtsfjord\": _70, \"bearalvahki\": _70, \"xn--bearalvhki-y4a\": _70, \"bearalváhki\": _70, \"beardu\": _70, \"beiarn\": _70, \"berg\": _70,\n      \"bergen\": _70, \"berlevag\": _70, \"xn--berlevg-jxa\": _70, \"berlevåg\": _70, \"bievat\": _70, \"xn--bievt-0qa\": _70, \"bievát\": _70, \"bindal\": _70, \"birkenes\": _70, \"bjarkoy\": _70, \"xn--bjarky-fya\": _70, \"bjarkøy\": _70, \"bjerkreim\": _70, \"bjugn\": _70, \"bodo\": _70, \"xn--bod-2na\": _70, \"bodø\": _70, \"bokn\": _70, \"bomlo\": _70, \"xn--bmlo-gra\": _70, \"bømlo\": _70, \"bremanger\": _70, \"bronnoy\": _70, \"xn--brnny-wuac\": _70, \"brønnøy\": _70, \"budejju\": _70, \"buskerud\": _81, \"bygland\": _70, \"bykle\": _70, \"cahcesuolo\": _70, \"xn--hcesuolo-7ya35b\": _70, \"čáhcesuolo\": _70, \"davvenjarga\": _70, \"xn--davvenjrga-y4a\": _70, \"davvenjárga\": _70, \"davvesiida\": _70, \"deatnu\": _70, \"dielddanuorri\": _70, \"divtasvuodna\": _70, \"divttasvuotna\": _70, \"donna\": _70, \"xn--dnna-gra\": _70, \"dønna\": _70, \"dovre\": _70, \"drammen\": _70, \"drangedal\": _70, \"dyroy\": _70, \"xn--dyry-ira\": _70, \"dyrøy\": _70, \"eid\": _70, \"eidfjord\": _70, \"eidsberg\": _70, \"eidskog\": _70, \"eidsvoll\": _70, \"eigersund\": _70, \"elverum\": _70, \"en\\\nebakk\": _70, \"engerdal\": _70, \"etne\": _70, \"etnedal\": _70, \"evenassi\": _70, \"xn--eveni-0qa01ga\": _70, \"evenášši\": _70, \"evenes\": _70, \"evje-og-hornnes\": _70, \"farsund\": _70, \"fauske\": _70, \"fedje\": _70, \"fet\": _70, \"finnoy\": _70, \"xn--finny-yua\": _70, \"finnøy\": _70, \"fitjar\": _70, \"fjaler\": _70, \"fjell\": _70, \"fla\": _70, \"xn--fl-zia\": _70, \"flå\": _70, \"flakstad\": _70, \"flatanger\": _70, \"flekkefjord\": _70, \"flesberg\": _70, \"flora\": _70, \"folldal\": _70, \"forde\": _70, \"xn--frde-gra\": _70, \"førde\": _70, \"forsand\": _70, \"fosnes\": _70, \"xn--frna-woa\": _70, \"fræna\": _70, \"frana\": _70, \"frei\": _70, \"frogn\": _70, \"froland\": _70, \"frosta\": _70, \"froya\": _70, \"xn--frya-hra\": _70, \"frøya\": _70, \"fuoisku\": _70, \"fuossko\": _70, \"fusa\": _70, \"fyresdal\": _70, \"gaivuotna\": _70, \"xn--givuotna-8ya\": _70, \"gáivuotna\": _70, \"galsa\": _70, \"xn--gls-elac\": _70, \"gálsá\": _70, \"gamvik\": _70, \"gangaviika\": _70, \"xn--ggaviika-8ya47h\": _70, \"gáŋgaviika\": _70, \"gaular\": _70, \"gausdal\": _70, \"giehtavuoa\\\ntna\": _70, \"gildeskal\": _70, \"xn--gildeskl-g0a\": _70, \"gildeskål\": _70, \"giske\": _70, \"gjemnes\": _70, \"gjerdrum\": _70, \"gjerstad\": _70, \"gjesdal\": _70, \"gjovik\": _70, \"xn--gjvik-wua\": _70, \"gjøvik\": _70, \"gloppen\": _70, \"gol\": _70, \"gran\": _70, \"grane\": _70, \"granvin\": _70, \"gratangen\": _70, \"grimstad\": _70, \"grong\": _70, \"grue\": _70, \"gulen\": _70, \"guovdageaidnu\": _70, \"ha\": _70, \"xn--h-2fa\": _70, \"hå\": _70, \"habmer\": _70, \"xn--hbmer-xqa\": _70, \"hábmer\": _70, \"hadsel\": _70, \"xn--hgebostad-g3a\": _70, \"hægebostad\": _70, \"hagebostad\": _70, \"halden\": _70, \"halsa\": _70, \"hamar\": _70, \"hamaroy\": _70, \"hammarfeasta\": _70, \"xn--hmmrfeasta-s4ac\": _70, \"hámmárfeasta\": _70, \"hammerfest\": _70, \"hapmir\": _70, \"xn--hpmir-xqa\": _70, \"hápmir\": _70, \"haram\": _70, \"hareid\": _70, \"harstad\": _70, \"hasvik\": _70, \"hattfjelldal\": _70, \"haugesund\": _70, \"hedmark\": [0, { \"os\": _70, \"valer\": _70, \"xn--vler-qoa\": _70, \"våler\": _70 }], \"hemne\": _70, \"hemnes\": _70, \"hemsedal\": _70, \"hitra\": _70, \"hjartda\\\nl\": _70, \"hjelmeland\": _70, \"hobol\": _70, \"xn--hobl-ira\": _70, \"hobøl\": _70, \"hof\": _70, \"hol\": _70, \"hole\": _70, \"holmestrand\": _70, \"holtalen\": _70, \"xn--holtlen-hxa\": _70, \"holtålen\": _70, \"hordaland\": [0, { \"os\": _70 }], \"hornindal\": _70, \"horten\": _70, \"hoyanger\": _70, \"xn--hyanger-q1a\": _70, \"høyanger\": _70, \"hoylandet\": _70, \"xn--hylandet-54a\": _70, \"høylandet\": _70, \"hurdal\": _70, \"hurum\": _70, \"hvaler\": _70, \"hyllestad\": _70, \"ibestad\": _70, \"inderoy\": _70, \"xn--indery-fya\": _70, \"inderøy\": _70, \"iveland\": _70, \"ivgu\": _70, \"jevnaker\": _70, \"jolster\": _70, \"xn--jlster-bya\": _70, \"jølster\": _70, \"jondal\": _70, \"kafjord\": _70, \"xn--kfjord-iua\": _70, \"kåfjord\": _70, \"karasjohka\": _70, \"xn--krjohka-hwab49j\": _70, \"kárášjohka\": _70, \"karasjok\": _70, \"karlsoy\": _70, \"karmoy\": _70, \"xn--karmy-yua\": _70, \"karmøy\": _70, \"kautokeino\": _70, \"klabu\": _70, \"xn--klbu-woa\": _70, \"klæbu\": _70, \"klepp\": _70, \"kongsberg\": _70, \"kongsvinger\": _70, \"kraanghke\": _70, \"xn--kranghke-b0a\": _70,\n      \"kråanghke\": _70, \"kragero\": _70, \"xn--krager-gya\": _70, \"kragerø\": _70, \"kristiansand\": _70, \"kristiansund\": _70, \"krodsherad\": _70, \"xn--krdsherad-m8a\": _70, \"krødsherad\": _70, \"xn--kvfjord-nxa\": _70, \"kvæfjord\": _70, \"xn--kvnangen-k0a\": _70, \"kvænangen\": _70, \"kvafjord\": _70, \"kvalsund\": _70, \"kvam\": _70, \"kvanangen\": _70, \"kvinesdal\": _70, \"kvinnherad\": _70, \"kviteseid\": _70, \"kvitsoy\": _70, \"xn--kvitsy-fya\": _70, \"kvitsøy\": _70, \"laakesvuemie\": _70, \"xn--lrdal-sra\": _70, \"lærdal\": _70, \"lahppi\": _70, \"xn--lhppi-xqa\": _70, \"láhppi\": _70, \"lardal\": _70, \"larvik\": _70, \"lavagis\": _70, \"lavangen\": _70, \"leangaviika\": _70, \"xn--leagaviika-52b\": _70, \"leaŋgaviika\": _70, \"lebesby\": _70, \"leikanger\": _70, \"leirfjord\": _70, \"leka\": _70, \"leksvik\": _70, \"lenvik\": _70, \"lerdal\": _70, \"lesja\": _70, \"levanger\": _70, \"lier\": _70, \"lierne\": _70, \"lillehammer\": _70, \"lillesand\": _70, \"lindas\": _70, \"xn--linds-pra\": _70, \"lindås\": _70, \"lindesnes\": _70, \"loabat\": _70, \"xn--loabt-0q\\\na\": _70, \"loabát\": _70, \"lodingen\": _70, \"xn--ldingen-q1a\": _70, \"lødingen\": _70, \"lom\": _70, \"loppa\": _70, \"lorenskog\": _70, \"xn--lrenskog-54a\": _70, \"lørenskog\": _70, \"loten\": _70, \"xn--lten-gra\": _70, \"løten\": _70, \"lund\": _70, \"lunner\": _70, \"luroy\": _70, \"xn--lury-ira\": _70, \"lurøy\": _70, \"luster\": _70, \"lyngdal\": _70, \"lyngen\": _70, \"malatvuopmi\": _70, \"xn--mlatvuopmi-s4a\": _70, \"málatvuopmi\": _70, \"malselv\": _70, \"xn--mlselv-iua\": _70, \"målselv\": _70, \"malvik\": _70, \"mandal\": _70, \"marker\": _70, \"marnardal\": _70, \"masfjorden\": _70, \"masoy\": _70, \"xn--msy-ula0h\": _70, \"måsøy\": _70, \"matta-varjjat\": _70, \"xn--mtta-vrjjat-k7af\": _70, \"mátta-várjjat\": _70, \"meland\": _70, \"meldal\": _70, \"melhus\": _70, \"meloy\": _70, \"xn--mely-ira\": _70, \"meløy\": _70, \"meraker\": _70, \"xn--merker-kua\": _70, \"meråker\": _70, \"midsund\": _70, \"midtre-gauldal\": _70, \"moareke\": _70, \"xn--moreke-jua\": _70, \"moåreke\": _70, \"modalen\": _70, \"modum\": _70, \"molde\": _70, \"more-og-romsdal\": [0, { \"heroy\": _70,\n      \"sande\": _70 }], \"xn--mre-og-romsdal-qqb\": [0, { \"xn--hery-ira\": _70, \"sande\": _70 }], \"møre-og-romsdal\": [0, { \"herøy\": _70, \"sande\": _70 }], \"moskenes\": _70, \"moss\": _70, \"mosvik\": _70, \"muosat\": _70, \"xn--muost-0qa\": _70, \"muosát\": _70, \"naamesjevuemie\": _70, \"xn--nmesjevuemie-tcba\": _70, \"nååmesjevuemie\": _70, \"xn--nry-yla5g\": _70, \"nærøy\": _70, \"namdalseid\": _70, \"namsos\": _70, \"namsskogan\": _70, \"nannestad\": _70, \"naroy\": _70, \"narviika\": _70, \"narvik\": _70, \"naustdal\": _70, \"navuotna\": _70, \"xn--nvuotna-hwa\": _70, \"návuotna\": _70, \"nedre-eiker\": _70, \"nesna\": _70, \"nesodden\": _70, \"nesseby\": _70, \"nesset\": _70, \"nissedal\": _70, \"nittedal\": _70, \"nord-aurdal\": _70, \"nord-fron\": _70, \"nord-odal\": _70, \"norddal\": _70, \"nordkapp\": _70, \"nordland\": [0, { \"bo\": _70, \"xn--b-5ga\": _70, \"bø\": _70, \"heroy\": _70, \"xn--hery-ira\": _70, \"herøy\": _70 }], \"nordre-land\": _70, \"nordreisa\": _70, \"nore-og-uvdal\": _70, \"notodden\": _70, \"notteroy\": _70, \"xn--nttery-byae\": _70, \"nøtter\\\nøy\": _70, \"odda\": _70, \"oksnes\": _70, \"xn--ksnes-uua\": _70, \"øksnes\": _70, \"omasvuotna\": _70, \"oppdal\": _70, \"oppegard\": _70, \"xn--oppegrd-ixa\": _70, \"oppegård\": _70, \"orkdal\": _70, \"orland\": _70, \"xn--rland-uua\": _70, \"ørland\": _70, \"orskog\": _70, \"xn--rskog-uua\": _70, \"ørskog\": _70, \"orsta\": _70, \"xn--rsta-fra\": _70, \"ørsta\": _70, \"osen\": _70, \"osteroy\": _70, \"xn--ostery-fya\": _70, \"osterøy\": _70, \"ostfold\": [0, { \"valer\": _70 }], \"xn--stfold-9xa\": [0, { \"xn--vler-qoa\": _70 }], \"østfold\": [0, { \"våler\": _70 }], \"ostre-toten\": _70, \"xn--stre-toten-zcb\": _70, \"østre-toten\": _70, \"overhalla\": _70, \"ovre-eiker\": _70, \"xn--vre-eiker-k8a\": _70, \"øvre-eiker\": _70, \"oyer\": _70, \"xn--yer-zna\": _70, \"øyer\": _70, \"oygarden\": _70, \"xn--ygarden-p1a\": _70, \"øygarden\": _70, \"oystre-slidre\": _70, \"xn--ystre-slidre-ujb\": _70, \"øystre-slidre\": _70, \"porsanger\": _70, \"porsangu\": _70, \"xn--porsgu-sta26f\": _70, \"porsáŋgu\": _70, \"porsgrunn\": _70, \"rade\": _70, \"xn--rde-ula\": _70, \"råde\": _70,\n      \"radoy\": _70, \"xn--rady-ira\": _70, \"radøy\": _70, \"xn--rlingen-mxa\": _70, \"rælingen\": _70, \"rahkkeravju\": _70, \"xn--rhkkervju-01af\": _70, \"ráhkkerávju\": _70, \"raisa\": _70, \"xn--risa-5na\": _70, \"ráisa\": _70, \"rakkestad\": _70, \"ralingen\": _70, \"rana\": _70, \"randaberg\": _70, \"rauma\": _70, \"rendalen\": _70, \"rennebu\": _70, \"rennesoy\": _70, \"xn--rennesy-v1a\": _70, \"rennesøy\": _70, \"rindal\": _70, \"ringebu\": _70, \"ringerike\": _70, \"ringsaker\": _70, \"risor\": _70, \"xn--risr-ira\": _70, \"risør\": _70, \"rissa\": _70, \"roan\": _70, \"rodoy\": _70, \"xn--rdy-0nab\": _70, \"rødøy\": _70, \"rollag\": _70, \"romsa\": _70, \"romskog\": _70, \"xn--rmskog-bya\": _70, \"rømskog\": _70, \"roros\": _70, \"xn--rros-gra\": _70, \"røros\": _70, \"rost\": _70, \"xn--rst-0na\": _70, \"røst\": _70, \"royken\": _70, \"xn--ryken-vua\": _70, \"røyken\": _70, \"royrvik\": _70, \"xn--ryrvik-bya\": _70, \"røyrvik\": _70, \"ruovat\": _70, \"rygge\": _70, \"salangen\": _70, \"salat\": _70, \"xn--slat-5na\": _70, \"sálat\": _70, \"xn--slt-elab\": _70, \"sálát\": _70,\n      \"saltdal\": _70, \"samnanger\": _70, \"sandefjord\": _70, \"sandnes\": _70, \"sandoy\": _70, \"xn--sandy-yua\": _70, \"sandøy\": _70, \"sarpsborg\": _70, \"sauda\": _70, \"sauherad\": _70, \"sel\": _70, \"selbu\": _70, \"selje\": _70, \"seljord\": _70, \"siellak\": _70, \"sigdal\": _70, \"siljan\": _70, \"sirdal\": _70, \"skanit\": _70, \"xn--sknit-yqa\": _70, \"skánit\": _70, \"skanland\": _70, \"xn--sknland-fxa\": _70, \"skånland\": _70, \"skaun\": _70, \"skedsmo\": _70, \"ski\": _70, \"skien\": _70, \"skierva\": _70, \"xn--skierv-uta\": _70, \"skiervá\": _70, \"skiptvet\": _70, \"skjak\": _70, \"xn--skjk-soa\": _70, \"skjåk\": _70, \"skjervoy\": _70, \"xn--skjervy-v1a\": _70, \"skjervøy\": _70, \"skodje\": _70, \"smola\": _70, \"xn--smla-hra\": _70, \"smøla\": _70, \"snaase\": _70, \"xn--snase-nra\": _70, \"snåase\": _70, \"snasa\": _70, \"xn--snsa-roa\": _70, \"snåsa\": _70, \"snillfjord\": _70, \"snoasa\": _70, \"sogndal\": _70, \"sogne\": _70, \"xn--sgne-gra\": _70, \"søgne\": _70, \"sokndal\": _70, \"sola\": _70, \"solund\": _70, \"somna\": _70, \"xn--smna-gra\": _70, \"sømna\": _70,\n      \"sondre-land\": _70, \"xn--sndre-land-0cb\": _70, \"søndre-land\": _70, \"songdalen\": _70, \"sor-aurdal\": _70, \"xn--sr-aurdal-l8a\": _70, \"sør-aurdal\": _70, \"sor-fron\": _70, \"xn--sr-fron-q1a\": _70, \"sør-fron\": _70, \"sor-odal\": _70, \"xn--sr-odal-q1a\": _70, \"sør-odal\": _70, \"sor-varanger\": _70, \"xn--sr-varanger-ggb\": _70, \"sør-varanger\": _70, \"sorfold\": _70, \"xn--srfold-bya\": _70, \"sørfold\": _70, \"sorreisa\": _70, \"xn--srreisa-q1a\": _70, \"sørreisa\": _70, \"sortland\": _70, \"sorum\": _70, \"xn--srum-gra\": _70, \"sørum\": _70, \"spydeberg\": _70, \"stange\": _70, \"stavanger\": _70, \"steigen\": _70, \"steinkjer\": _70, \"stjordal\": _70, \"xn--stjrdal-s1a\": _70, \"stjørdal\": _70, \"stokke\": _70, \"stor-elvdal\": _70, \"stord\": _70, \"stordal\": _70, \"storfjord\": _70, \"strand\": _70, \"stranda\": _70, \"stryn\": _70, \"sula\": _70, \"suldal\": _70, \"sund\": _70, \"sunndal\": _70, \"surnadal\": _70, \"sveio\": _70, \"svelvik\": _70, \"sykkylven\": _70, \"tana\": _70, \"telemark\": [0, { \"bo\": _70, \"xn--b-5ga\": _70, \"bø\": _70 }], \"ti\\\nme\": _70, \"tingvoll\": _70, \"tinn\": _70, \"tjeldsund\": _70, \"tjome\": _70, \"xn--tjme-hra\": _70, \"tjøme\": _70, \"tokke\": _70, \"tolga\": _70, \"tonsberg\": _70, \"xn--tnsberg-q1a\": _70, \"tønsberg\": _70, \"torsken\": _70, \"xn--trna-woa\": _70, \"træna\": _70, \"trana\": _70, \"tranoy\": _70, \"xn--trany-yua\": _70, \"tranøy\": _70, \"troandin\": _70, \"trogstad\": _70, \"xn--trgstad-r1a\": _70, \"trøgstad\": _70, \"tromsa\": _70, \"tromso\": _70, \"xn--troms-zua\": _70, \"tromsø\": _70, \"trondheim\": _70, \"trysil\": _70, \"tvedestrand\": _70, \"tydal\": _70, \"tynset\": _70, \"tysfjord\": _70, \"tysnes\": _70, \"xn--tysvr-vra\": _70, \"tysvær\": _70, \"tysvar\": _70, \"ullensaker\": _70, \"ullensvang\": _70, \"ulvik\": _70, \"unjarga\": _70, \"xn--unjrga-rta\": _70, \"unjárga\": _70, \"utsira\": _70, \"vaapste\": _70, \"vadso\": _70, \"xn--vads-jra\": _70, \"vadsø\": _70, \"xn--vry-yla5g\": _70, \"værøy\": _70, \"vaga\": _70, \"xn--vg-yiab\": _70, \"vågå\": _70, \"vagan\": _70, \"xn--vgan-qoa\": _70, \"vågan\": _70, \"vagsoy\": _70, \"xn--vgsy-qoa0j\": _70, \"vågsøy\": _70,\n      \"vaksdal\": _70, \"valle\": _70, \"vang\": _70, \"vanylven\": _70, \"vardo\": _70, \"xn--vard-jra\": _70, \"vardø\": _70, \"varggat\": _70, \"xn--vrggt-xqad\": _70, \"várggát\": _70, \"varoy\": _70, \"vefsn\": _70, \"vega\": _70, \"vegarshei\": _70, \"xn--vegrshei-c0a\": _70, \"vegårshei\": _70, \"vennesla\": _70, \"verdal\": _70, \"verran\": _70, \"vestby\": _70, \"vestfold\": [0, { \"sande\": _70 }], \"vestnes\": _70, \"vestre-slidre\": _70, \"vestre-toten\": _70, \"vestvagoy\": _70, \"xn--vestvgy-ixa6o\": _70, \"vestvågøy\": _70, \"vevelstad\": _70, \"vik\": _70, \"vikna\": _70, \"vindafjord\": _70, \"voagat\": _70, \"volda\": _70, \"voss\": _70 }], \"np\": _74, \"nr\": _79, \"nu\": _70, \"nz\": [1, { \"ac\": _70, \"co\": _70, \"cri\": _70, \"geek\": _70, \"gen\": _70, \"govt\": _70, \"health\": _70, \"iwi\": _70, \"kiwi\": _70, \"maori\": _70, \"xn--mori-qsa\": _70, \"māori\": _70, \"mil\": _70, \"net\": _70, \"org\": _70, \"parliament\": _70, \"school\": _70 }], \"om\": [1, { \"co\": _70, \"com\": _70, \"edu\": _70, \"gov\": _70, \"med\": _70, \"museum\": _70, \"net\": _70, \"org\": _70, \"pro\": _70 }],\n      \"onion\": _70, \"org\": _70, \"pa\": [1, { \"abo\": _70, \"ac\": _70, \"com\": _70, \"edu\": _70, \"gob\": _70, \"ing\": _70, \"med\": _70, \"net\": _70, \"nom\": _70, \"org\": _70, \"sld\": _70 }], \"pe\": [1, { \"com\": _70, \"edu\": _70, \"gob\": _70, \"mil\": _70, \"net\": _70, \"nom\": _70, \"org\": _70 }], \"pf\": [1, { \"com\": _70, \"edu\": _70, \"org\": _70 }], \"pg\": _74, \"ph\": [1, { \"com\": _70, \"edu\": _70, \"gov\": _70, \"i\": _70, \"mil\": _70, \"net\": _70, \"ngo\": _70, \"org\": _70 }], \"pk\": [1, { \"ac\": _70, \"biz\": _70, \"com\": _70, \"edu\": _70, \"fam\": _70, \"gkp\": _70, \"gob\": _70, \"gog\": _70, \"gok\": _70, \"gop\": _70, \"gos\": _70, \"gov\": _70, \"net\": _70, \"org\": _70, \"web\": _70 }], \"pl\": [1, { \"com\": _70, \"net\": _70, \"org\": _70, \"agro\": _70, \"aid\": _70, \"atm\": _70, \"auto\": _70, \"biz\": _70, \"edu\": _70, \"gmina\": _70, \"gsm\": _70, \"info\": _70, \"mail\": _70, \"media\": _70, \"miasta\": _70, \"mil\": _70, \"nieruchomosci\": _70, \"nom\": _70, \"pc\": _70, \"powiat\": _70, \"priv\": _70, \"realestate\": _70, \"rel\": _70, \"sex\": _70, \"shop\": _70, \"sklep\": _70, \"\\\nsos\": _70, \"szkola\": _70, \"targi\": _70, \"tm\": _70, \"tourism\": _70, \"travel\": _70, \"turystyka\": _70, \"gov\": [1, { \"ap\": _70, \"griw\": _70, \"ic\": _70, \"is\": _70, \"kmpsp\": _70, \"konsulat\": _70, \"kppsp\": _70, \"kwp\": _70, \"kwpsp\": _70, \"mup\": _70, \"mw\": _70, \"oia\": _70, \"oirm\": _70, \"oke\": _70, \"oow\": _70, \"oschr\": _70, \"oum\": _70, \"pa\": _70, \"pinb\": _70, \"piw\": _70, \"po\": _70, \"pr\": _70, \"psp\": _70, \"psse\": _70, \"pup\": _70, \"rzgw\": _70, \"sa\": _70, \"sdn\": _70, \"sko\": _70, \"so\": _70, \"sr\": _70, \"starostwo\": _70, \"ug\": _70, \"ugim\": _70, \"um\": _70, \"umig\": _70, \"upow\": _70, \"uppo\": _70, \"us\": _70, \"uw\": _70, \"uzs\": _70, \"wif\": _70, \"wiih\": _70, \"winb\": _70, \"wios\": _70, \"witd\": _70, \"wiw\": _70, \"wkz\": _70, \"wsa\": _70, \"wskr\": _70, \"wsse\": _70, \"wuoz\": _70, \"wzmiuw\": _70, \"zp\": _70, \"zpisdn\": _70 }], \"augustow\": _70, \"babia-gora\": _70, \"bedzin\": _70, \"beskidy\": _70, \"bialowieza\": _70, \"bialystok\": _70, \"bielawa\": _70, \"bieszczady\": _70, \"boleslawiec\": _70, \"bydgoszcz\": _70, \"bytom\": _70, \"cieszy\\\nn\": _70, \"czeladz\": _70, \"czest\": _70, \"dlugoleka\": _70, \"elblag\": _70, \"elk\": _70, \"glogow\": _70, \"gniezno\": _70, \"gorlice\": _70, \"grajewo\": _70, \"ilawa\": _70, \"jaworzno\": _70, \"jelenia-gora\": _70, \"jgora\": _70, \"kalisz\": _70, \"karpacz\": _70, \"kartuzy\": _70, \"kaszuby\": _70, \"katowice\": _70, \"kazimierz-dolny\": _70, \"kepno\": _70, \"ketrzyn\": _70, \"klodzko\": _70, \"kobierzyce\": _70, \"kolobrzeg\": _70, \"konin\": _70, \"konskowola\": _70, \"kutno\": _70, \"lapy\": _70, \"lebork\": _70, \"legnica\": _70, \"lezajsk\": _70, \"limanowa\": _70, \"lomza\": _70, \"lowicz\": _70, \"lubin\": _70, \"lukow\": _70, \"malbork\": _70, \"malopolska\": _70, \"mazowsze\": _70, \"mazury\": _70, \"mielec\": _70, \"mielno\": _70, \"mragowo\": _70, \"naklo\": _70, \"nowaruda\": _70, \"nysa\": _70, \"olawa\": _70, \"olecko\": _70, \"olkusz\": _70, \"olsztyn\": _70, \"opoczno\": _70, \"opole\": _70, \"ostroda\": _70, \"ostroleka\": _70, \"ostrowiec\": _70, \"ostrowwlkp\": _70, \"pila\": _70, \"pisz\": _70, \"podhale\": _70, \"podlasie\": _70, \"polkowice\": _70, \"pomorskie\": _70, \"pomor\\\nze\": _70, \"prochowice\": _70, \"pruszkow\": _70, \"przeworsk\": _70, \"pulawy\": _70, \"radom\": _70, \"rawa-maz\": _70, \"rybnik\": _70, \"rzeszow\": _70, \"sanok\": _70, \"sejny\": _70, \"skoczow\": _70, \"slask\": _70, \"slupsk\": _70, \"sosnowiec\": _70, \"stalowa-wola\": _70, \"starachowice\": _70, \"stargard\": _70, \"suwalki\": _70, \"swidnica\": _70, \"swiebodzin\": _70, \"swinoujscie\": _70, \"szczecin\": _70, \"szczytno\": _70, \"tarnobrzeg\": _70, \"tgory\": _70, \"turek\": _70, \"tychy\": _70, \"ustka\": _70, \"walbrzych\": _70, \"warmia\": _70, \"warszawa\": _70, \"waw\": _70, \"wegrow\": _70, \"wielun\": _70, \"wlocl\": _70, \"wloclawek\": _70, \"wodzislaw\": _70, \"wolomin\": _70, \"wroclaw\": _70, \"zachpomor\": _70, \"zagan\": _70, \"zarow\": _70, \"zgora\": _70, \"zgorzelec\": _70 }], \"pm\": _70, \"pn\": [1, { \"co\": _70, \"edu\": _70, \"gov\": _70, \"net\": _70, \"org\": _70 }], \"post\": _70, \"pr\": [1, { \"biz\": _70, \"com\": _70, \"edu\": _70, \"gov\": _70, \"info\": _70, \"isla\": _70, \"name\": _70, \"net\": _70, \"org\": _70, \"pro\": _70, \"ac\": _70, \"est\": _70, \"prof\": _70 }], \"\\\npro\": [1, { \"aaa\": _70, \"aca\": _70, \"acct\": _70, \"avocat\": _70, \"bar\": _70, \"cpa\": _70, \"eng\": _70, \"jur\": _70, \"law\": _70, \"med\": _70, \"recht\": _70 }], \"ps\": [1, { \"com\": _70, \"edu\": _70, \"gov\": _70, \"net\": _70, \"org\": _70, \"plo\": _70, \"sec\": _70 }], \"pt\": [1, { \"com\": _70, \"edu\": _70, \"gov\": _70, \"int\": _70, \"net\": _70, \"nome\": _70, \"org\": _70, \"publ\": _70 }], \"pw\": _73, \"py\": [1, { \"com\": _70, \"coop\": _70, \"edu\": _70, \"gov\": _70, \"mil\": _70, \"net\": _70, \"org\": _70 }], \"qa\": [1, { \"com\": _70, \"edu\": _70, \"gov\": _70, \"mil\": _70, \"name\": _70, \"net\": _70, \"org\": _70, \"sch\": _70 }], \"re\": [1, { \"asso\": _70, \"com\": _70 }], \"ro\": [1, { \"arts\": _70, \"com\": _70, \"firm\": _70, \"info\": _70, \"nom\": _70, \"nt\": _70, \"org\": _70, \"rec\": _70, \"store\": _70, \"tm\": _70, \"www\": _70 }], \"rs\": [1, { \"ac\": _70, \"co\": _70, \"edu\": _70, \"gov\": _70, \"in\": _70, \"org\": _70 }], \"ru\": _70, \"rw\": [1, { \"ac\": _70, \"co\": _70, \"coop\": _70, \"gov\": _70, \"mil\": _70, \"net\": _70, \"org\": _70 }], \"sa\": [1, { \"com\": _70, \"edu\": _70,\n      \"gov\": _70, \"med\": _70, \"net\": _70, \"org\": _70, \"pub\": _70, \"sch\": _70 }], \"sb\": _72, \"sc\": _72, \"sd\": [1, { \"com\": _70, \"edu\": _70, \"gov\": _70, \"info\": _70, \"med\": _70, \"net\": _70, \"org\": _70, \"tv\": _70 }], \"se\": [1, { \"a\": _70, \"ac\": _70, \"b\": _70, \"bd\": _70, \"brand\": _70, \"c\": _70, \"d\": _70, \"e\": _70, \"f\": _70, \"fh\": _70, \"fhsk\": _70, \"fhv\": _70, \"g\": _70, \"h\": _70, \"i\": _70, \"k\": _70, \"komforb\": _70, \"kommunalforbund\": _70, \"komvux\": _70, \"l\": _70, \"lanbib\": _70, \"m\": _70, \"n\": _70, \"naturbruksgymn\": _70, \"o\": _70, \"org\": _70, \"p\": _70, \"parti\": _70, \"pp\": _70, \"press\": _70, \"r\": _70, \"s\": _70, \"t\": _70, \"tm\": _70, \"u\": _70, \"w\": _70, \"x\": _70, \"y\": _70, \"z\": _70 }], \"sg\": _72, \"sh\": [1, { \"com\": _70, \"gov\": _70, \"mil\": _70, \"net\": _70, \"org\": _70 }], \"si\": _70, \"sj\": _70, \"sk\": _70, \"sl\": _72, \"sm\": _70, \"sn\": [1, { \"art\": _70, \"com\": _70, \"edu\": _70, \"gouv\": _70, \"org\": _70, \"perso\": _70, \"univ\": _70 }], \"so\": [1, { \"com\": _70, \"edu\": _70, \"gov\": _70, \"me\": _70, \"net\": _70,\n      \"org\": _70 }], \"sr\": _70, \"ss\": [1, { \"biz\": _70, \"co\": _70, \"com\": _70, \"edu\": _70, \"gov\": _70, \"me\": _70, \"net\": _70, \"org\": _70, \"sch\": _70 }], \"st\": [1, { \"co\": _70, \"com\": _70, \"consulado\": _70, \"edu\": _70, \"embaixada\": _70, \"mil\": _70, \"net\": _70, \"org\": _70, \"principe\": _70, \"saotome\": _70, \"store\": _70 }], \"su\": _70, \"sv\": [1, { \"com\": _70, \"edu\": _70, \"gob\": _70, \"org\": _70, \"red\": _70 }], \"sx\": _73, \"sy\": _71, \"sz\": [1, { \"ac\": _70, \"co\": _70, \"org\": _70 }], \"tc\": _70, \"td\": _70, \"tel\": _70, \"tf\": _70, \"tg\": _70, \"th\": [1, { \"ac\": _70, \"co\": _70, \"go\": _70, \"in\": _70, \"mi\": _70, \"net\": _70, \"or\": _70 }], \"tj\": [1, { \"ac\": _70, \"biz\": _70, \"co\": _70, \"com\": _70, \"edu\": _70, \"go\": _70, \"gov\": _70, \"int\": _70, \"mil\": _70, \"name\": _70, \"net\": _70, \"nic\": _70, \"org\": _70, \"test\": _70, \"web\": _70 }], \"tk\": _70, \"tl\": _73, \"tm\": _78, \"tn\": [1, { \"com\": _70, \"ens\": _70, \"fin\": _70, \"gov\": _70, \"ind\": _70, \"info\": _70, \"intl\": _70, \"mincom\": _70, \"nat\": _70, \"net\": _70, \"org\": _70,\n      \"perso\": _70, \"tourism\": _70 }], \"to\": _71, \"tr\": [1, { \"av\": _70, \"bbs\": _70, \"bel\": _70, \"biz\": _70, \"com\": _70, \"dr\": _70, \"edu\": _70, \"gen\": _70, \"gov\": _70, \"info\": _70, \"k12\": _70, \"kep\": _70, \"mil\": _70, \"name\": _70, \"net\": _70, \"org\": _70, \"pol\": _70, \"tel\": _70, \"tsk\": _70, \"tv\": _70, \"web\": _70, \"nc\": _73 }], \"tt\": [1, { \"biz\": _70, \"co\": _70, \"com\": _70, \"edu\": _70, \"gov\": _70, \"info\": _70, \"mil\": _70, \"name\": _70, \"net\": _70, \"org\": _70, \"pro\": _70 }], \"tv\": _70, \"tw\": [1, { \"club\": _70, \"com\": _70, \"ebiz\": _70, \"edu\": _70, \"game\": _70, \"gov\": _70, \"idv\": _70, \"mil\": _70, \"net\": _70, \"org\": _70 }], \"tz\": [1, { \"ac\": _70, \"co\": _70, \"go\": _70, \"hotel\": _70, \"info\": _70, \"me\": _70, \"mil\": _70, \"mobi\": _70, \"ne\": _70, \"or\": _70, \"sc\": _70, \"tv\": _70 }], \"ua\": [1, { \"com\": _70, \"edu\": _70, \"gov\": _70, \"in\": _70, \"net\": _70, \"org\": _70, \"cherkassy\": _70, \"cherkasy\": _70, \"chernigov\": _70, \"chernihiv\": _70, \"chernivtsi\": _70, \"chernovtsy\": _70, \"ck\": _70, \"cn\": _70, \"cr\": _70,\n      \"crimea\": _70, \"cv\": _70, \"dn\": _70, \"dnepropetrovsk\": _70, \"dnipropetrovsk\": _70, \"donetsk\": _70, \"dp\": _70, \"if\": _70, \"ivano-frankivsk\": _70, \"kh\": _70, \"kharkiv\": _70, \"kharkov\": _70, \"kherson\": _70, \"khmelnitskiy\": _70, \"khmelnytskyi\": _70, \"kiev\": _70, \"kirovograd\": _70, \"km\": _70, \"kr\": _70, \"kropyvnytskyi\": _70, \"krym\": _70, \"ks\": _70, \"kv\": _70, \"kyiv\": _70, \"lg\": _70, \"lt\": _70, \"lugansk\": _70, \"luhansk\": _70, \"lutsk\": _70, \"lv\": _70, \"lviv\": _70, \"mk\": _70, \"mykolaiv\": _70, \"nikolaev\": _70, \"od\": _70, \"odesa\": _70, \"odessa\": _70, \"pl\": _70, \"poltava\": _70, \"rivne\": _70, \"rovno\": _70, \"rv\": _70, \"sb\": _70, \"sebastopol\": _70, \"sevastopol\": _70, \"sm\": _70, \"sumy\": _70, \"te\": _70, \"ternopil\": _70, \"uz\": _70, \"uzhgorod\": _70, \"uzhhorod\": _70, \"vinnica\": _70, \"vinnytsia\": _70, \"vn\": _70, \"volyn\": _70, \"yalta\": _70, \"zakarpattia\": _70, \"zaporizhzhe\": _70, \"zaporizhzhia\": _70, \"zhitomir\": _70, \"zhytomyr\": _70, \"zp\": _70, \"zt\": _70 }], \"ug\": [1, { \"ac\": _70, \"co\": _70, \"com\": _70,\n      \"edu\": _70, \"go\": _70, \"gov\": _70, \"mil\": _70, \"ne\": _70, \"or\": _70, \"org\": _70, \"sc\": _70, \"us\": _70 }], \"uk\": [1, { \"ac\": _70, \"co\": _70, \"gov\": _70, \"ltd\": _70, \"me\": _70, \"net\": _70, \"nhs\": _70, \"org\": _70, \"plc\": _70, \"police\": _70, \"sch\": _74 }], \"us\": [1, { \"dni\": _70, \"isa\": _70, \"nsn\": _70, \"ak\": _82, \"al\": _82, \"ar\": _82, \"as\": _82, \"az\": _82, \"ca\": _82, \"co\": _82, \"ct\": _82, \"dc\": _82, \"de\": _83, \"fl\": _82, \"ga\": _82, \"gu\": _82, \"hi\": _84, \"ia\": _82, \"id\": _82, \"il\": _82, \"in\": _82, \"ks\": _82, \"ky\": _82, \"la\": _82, \"ma\": [1, { \"k12\": [1, { \"chtr\": _70, \"paroch\": _70, \"pvt\": _70 }], \"cc\": _70, \"lib\": _70 }], \"md\": _82, \"me\": _82, \"mi\": [1, { \"k12\": _70, \"cc\": _70, \"lib\": _70, \"ann-arbor\": _70, \"cog\": _70, \"dst\": _70, \"eaton\": _70, \"gen\": _70, \"mus\": _70, \"tec\": _70, \"washtenaw\": _70 }], \"mn\": _82, \"mo\": _82, \"ms\": [1, { \"k12\": _70, \"cc\": _70 }], \"mt\": _82, \"nc\": _82, \"nd\": _84, \"ne\": _82, \"nh\": _82, \"nj\": _82, \"nm\": _82, \"nv\": _82, \"ny\": _82, \"oh\": _82, \"ok\": _82, \"or\": _82,\n      \"pa\": _82, \"pr\": _82, \"ri\": _84, \"sc\": _82, \"sd\": _84, \"tn\": _82, \"tx\": _82, \"ut\": _82, \"va\": _82, \"vi\": _82, \"vt\": _82, \"wa\": _82, \"wi\": _82, \"wv\": _83, \"wy\": _82 }], \"uy\": [1, { \"com\": _70, \"edu\": _70, \"gub\": _70, \"mil\": _70, \"net\": _70, \"org\": _70 }], \"uz\": [1, { \"co\": _70, \"com\": _70, \"net\": _70, \"org\": _70 }], \"va\": _70, \"vc\": _71, \"ve\": [1, { \"arts\": _70, \"bib\": _70, \"co\": _70, \"com\": _70, \"e12\": _70, \"edu\": _70, \"emprende\": _70, \"firm\": _70, \"gob\": _70, \"gov\": _70, \"info\": _70, \"int\": _70, \"mil\": _70, \"net\": _70, \"nom\": _70, \"org\": _70, \"rar\": _70, \"rec\": _70, \"store\": _70, \"tec\": _70, \"web\": _70 }], \"vg\": [1, { \"edu\": _70 }], \"vi\": [1, { \"co\": _70, \"com\": _70, \"k12\": _70, \"net\": _70, \"org\": _70 }], \"vn\": [1, { \"ac\": _70, \"ai\": _70, \"biz\": _70, \"com\": _70, \"edu\": _70, \"gov\": _70, \"health\": _70, \"id\": _70, \"info\": _70, \"int\": _70, \"io\": _70, \"name\": _70, \"net\": _70, \"org\": _70, \"pro\": _70, \"angiang\": _70, \"bacgiang\": _70, \"backan\": _70, \"baclieu\": _70, \"bacninh\": _70, \"bari\\\na-vungtau\": _70, \"bentre\": _70, \"binhdinh\": _70, \"binhduong\": _70, \"binhphuoc\": _70, \"binhthuan\": _70, \"camau\": _70, \"cantho\": _70, \"caobang\": _70, \"daklak\": _70, \"daknong\": _70, \"danang\": _70, \"dienbien\": _70, \"dongnai\": _70, \"dongthap\": _70, \"gialai\": _70, \"hagiang\": _70, \"haiduong\": _70, \"haiphong\": _70, \"hanam\": _70, \"hanoi\": _70, \"hatinh\": _70, \"haugiang\": _70, \"hoabinh\": _70, \"hungyen\": _70, \"khanhhoa\": _70, \"kiengiang\": _70, \"kontum\": _70, \"laichau\": _70, \"lamdong\": _70, \"langson\": _70, \"laocai\": _70, \"longan\": _70, \"namdinh\": _70, \"nghean\": _70, \"ninhbinh\": _70, \"ninhthuan\": _70, \"phutho\": _70, \"phuyen\": _70, \"quangbinh\": _70, \"quangnam\": _70, \"quangngai\": _70, \"quangninh\": _70, \"quangtri\": _70, \"soctrang\": _70, \"sonla\": _70, \"tayninh\": _70, \"thaibinh\": _70, \"thainguyen\": _70, \"thanhhoa\": _70, \"thanhphohochiminh\": _70, \"thuathienhue\": _70, \"tiengiang\": _70, \"travinh\": _70, \"tuyenquang\": _70, \"vinhlong\": _70, \"vinhphuc\": _70, \"yenbai\": _70 }], \"vu\": _76, \"wf\": _70, \"ws\": _72, \"y\\\nt\": _70, \"xn--mgbaam7a8h\": _70, \"امارات\": _70, \"xn--y9a3aq\": _70, \"հայ\": _70, \"xn--54b7fta0cc\": _70, \"বাংলা\": _70, \"xn--90ae\": _70, \"бг\": _70, \"xn--mgbcpq6gpa1a\": _70, \"البحرين\": _70, \"xn--90ais\": _70, \"бел\": _70, \"xn--fiqs8s\": _70, \"中国\": _70, \"xn--fiqz9s\": _70, \"中國\": _70, \"xn--lgbbat1ad8j\": _70, \"الجزائر\": _70, \"xn--wgbh1c\": _70, \"مصر\": _70, \"xn--e1a4c\": _70, \"ею\": _70, \"xn--qxa6a\": _70, \"ευ\": _70, \"xn--mgbah1a3hjkrd\": _70, \"موريتانيا\": _70, \"xn--node\": _70, \"გე\": _70, \"xn--qxam\": _70, \"ελ\": _70, \"xn--j6w193g\": [1, { \"xn--gmqw5a\": _70, \"xn--55qx5d\": _70, \"xn--mxtq1m\": _70, \"xn--wcvs22d\": _70, \"xn--uc0atv\": _70, \"xn--od0alg\": _70 }], \"香港\": [1, { \"個人\": _70, \"公司\": _70, \"政府\": _70, \"教育\": _70, \"組織\": _70, \"網絡\": _70 }], \"xn--2scrj9c\": _70, \"ಭಾರತ\": _70, \"xn--3hcrj9c\": _70, \"ଭାରତ\": _70, \"xn--45br5cyl\": _70, \"ভাৰত\": _70, \"xn--h2breg3eve\": _70, \"भारतम्\": _70, \"xn--h2\\\nbrj9c8c\": _70, \"भारोत\": _70, \"xn--mgbgu82a\": _70, \"ڀارت\": _70, \"xn--rvc1e0am3e\": _70, \"ഭാരതം\": _70, \"xn--h2brj9c\": _70, \"भारत\": _70, \"xn--mgbbh1a\": _70, \"بارت\": _70, \"xn--mgbbh1a71e\": _70, \"بھارت\": _70, \"xn--fpcrj9c3d\": _70, \"భారత్\": _70, \"xn--gecrj9c\": _70, \"ભારત\": _70, \"xn--s9brj9c\": _70, \"ਭਾਰਤ\": _70, \"xn--45brj9c\": _70, \"ভারত\": _70, \"xn--xkc2dl3a5ee0h\": _70, \"இந்தியா\": _70, \"xn--mgba3a4f16a\": _70, \"ایران\": _70, \"xn--mgba3a4fra\": _70, \"ايران\": _70, \"xn--mgbtx2b\": _70, \"عراق\": _70, \"xn--mgbayh7gpa\": _70, \"الاردن\": _70, \"xn--3e0b707e\": _70, \"한국\": _70, \"xn--80ao21a\": _70, \"қаз\": _70, \"xn--q7ce6a\": _70, \"ລາວ\": _70, \"xn--fzc2c9e2c\": _70, \"ලංකා\": _70, \"xn--xkc2al3hye2a\": _70, \"இலங்கை\": _70, \"xn--mgbc0a9azcg\": _70, \"المغرب\": _70, \"xn--d1alf\": _70, \"мкд\": _70, \"xn--l1acc\": _70, \"мон\": _70, \"xn--mix891f\": _70, \"澳門\": _70, \"xn--mix082f\": _70,\n      \"澳门\": _70, \"xn--mgbx4cd0ab\": _70, \"مليسيا\": _70, \"xn--mgb9awbf\": _70, \"عمان\": _70, \"xn--mgbai9azgqp6j\": _70, \"پاکستان\": _70, \"xn--mgbai9a5eva00b\": _70, \"پاكستان\": _70, \"xn--ygbi2ammx\": _70, \"فلسطين\": _70, \"xn--90a3ac\": [1, { \"xn--80au\": _70, \"xn--90azh\": _70, \"xn--d1at\": _70, \"xn--c1avg\": _70, \"xn--o1ac\": _70, \"xn--o1ach\": _70 }], \"срб\": [1, { \"ак\": _70, \"обр\": _70, \"од\": _70, \"орг\": _70, \"пр\": _70, \"упр\": _70 }], \"xn--p1ai\": _70, \"рф\": _70, \"xn--wgbl6a\": _70, \"قطر\": _70, \"xn--mgberp4a5d4ar\": _70, \"السعودية\": _70, \"xn--mgberp4a5d4a87g\": _70, \"السعودیة\": _70, \"xn--mgbqly7c0a67fbc\": _70, \"السعودیۃ\": _70, \"xn--mgbqly7cvafr\": _70, \"السعوديه\": _70, \"xn--mgbpl2fh\": _70, \"سودان\": _70, \"xn--yfro4i67o\": _70, \"新加坡\": _70, \"xn--clchc0ea0b2g2a9gcd\": _70, \"சிங்கப்பூர்\": _70, \"xn--ogbpf8fl\": _70, \"سورية\": _70, \"xn--mgbtf8fl\": _70, \"سوريا\": _70, \"xn--o3cw4h\": [1, { \"\\\nxn--o3cyx2a\": _70, \"xn--12co0c3b4eva\": _70, \"xn--m3ch0j3a\": _70, \"xn--h3cuzk1di\": _70, \"xn--12c1fe0br\": _70, \"xn--12cfi8ixb8l\": _70 }], \"ไทย\": [1, { \"ทหาร\": _70, \"ธุรกิจ\": _70, \"เน็ต\": _70, \"รัฐบาล\": _70, \"ศึกษา\": _70, \"องค์กร\": _70 }], \"xn--pgbs0dh\": _70, \"تونس\": _70, \"xn--kpry57d\": _70, \"台灣\": _70, \"xn--kprw13d\": _70, \"台湾\": _70, \"xn--nnx388a\": _70, \"臺灣\": _70, \"xn--j1amh\": _70, \"укр\": _70, \"xn--mgb2ddes\": _70, \"اليمن\": _70, \"xxx\": _70, \"ye\": _71, \"za\": [0, { \"ac\": _70, \"agric\": _70, \"alt\": _70, \"co\": _70, \"edu\": _70, \"gov\": _70, \"grondar\": _70, \"law\": _70, \"mil\": _70, \"net\": _70, \"ngo\": _70, \"nic\": _70, \"nis\": _70, \"nom\": _70, \"org\": _70, \"school\": _70, \"tm\": _70, \"web\": _70 }], \"zm\": [1, { \"ac\": _70, \"biz\": _70, \"co\": _70, \"com\": _70, \"edu\": _70, \"gov\": _70, \"info\": _70, \"mil\": _70, \"net\": _70, \"org\": _70, \"sch\": _70 }], \"zw\": [1, { \"ac\": _70, \"co\": _70, \"gov\": _70, \"mil\": _70, \"org\": _70 }], \"\\\naaa\": _70, \"aarp\": _70, \"abb\": _70, \"abbott\": _70, \"abbvie\": _70, \"abc\": _70, \"able\": _70, \"abogado\": _70, \"abudhabi\": _70, \"academy\": _70, \"accenture\": _70, \"accountant\": _70, \"accountants\": _70, \"aco\": _70, \"actor\": _70, \"ads\": _70, \"adult\": _70, \"aeg\": _70, \"aetna\": _70, \"afl\": _70, \"africa\": _70, \"agakhan\": _70, \"agency\": _70, \"aig\": _70, \"airbus\": _70, \"airforce\": _70, \"airtel\": _70, \"akdn\": _70, \"alibaba\": _70, \"alipay\": _70, \"allfinanz\": _70, \"allstate\": _70, \"ally\": _70, \"alsace\": _70, \"alstom\": _70, \"amazon\": _70, \"americanexpress\": _70, \"americanfamily\": _70, \"amex\": _70, \"amfam\": _70, \"amica\": _70, \"amsterdam\": _70, \"analytics\": _70, \"android\": _70, \"anquan\": _70, \"anz\": _70, \"aol\": _70, \"apartments\": _70, \"app\": _70, \"apple\": _70, \"aquarelle\": _70, \"arab\": _70, \"aramco\": _70, \"archi\": _70, \"army\": _70, \"art\": _70, \"arte\": _70, \"asda\": _70, \"associates\": _70, \"athleta\": _70, \"attorney\": _70, \"auction\": _70, \"audi\": _70, \"audible\": _70, \"audio\": _70, \"auspost\": _70, \"author\": _70,\n      \"auto\": _70, \"autos\": _70, \"aws\": _70, \"axa\": _70, \"azure\": _70, \"baby\": _70, \"baidu\": _70, \"banamex\": _70, \"band\": _70, \"bank\": _70, \"bar\": _70, \"barcelona\": _70, \"barclaycard\": _70, \"barclays\": _70, \"barefoot\": _70, \"bargains\": _70, \"baseball\": _70, \"basketball\": _70, \"bauhaus\": _70, \"bayern\": _70, \"bbc\": _70, \"bbt\": _70, \"bbva\": _70, \"bcg\": _70, \"bcn\": _70, \"beats\": _70, \"beauty\": _70, \"beer\": _70, \"berlin\": _70, \"best\": _70, \"bestbuy\": _70, \"bet\": _70, \"bharti\": _70, \"bible\": _70, \"bid\": _70, \"bike\": _70, \"bing\": _70, \"bingo\": _70, \"bio\": _70, \"black\": _70, \"blackfriday\": _70, \"blockbuster\": _70, \"blog\": _70, \"bloomberg\": _70, \"blue\": _70, \"bms\": _70, \"bmw\": _70, \"bnpparibas\": _70, \"boats\": _70, \"boehringer\": _70, \"bofa\": _70, \"bom\": _70, \"bond\": _70, \"boo\": _70, \"book\": _70, \"booking\": _70, \"bosch\": _70, \"bostik\": _70, \"boston\": _70, \"bot\": _70, \"boutique\": _70, \"box\": _70, \"bradesco\": _70, \"bridgestone\": _70, \"broadway\": _70, \"broker\": _70, \"brother\": _70, \"brussels\": _70, \"\\\nbuild\": _70, \"builders\": _70, \"business\": _70, \"buy\": _70, \"buzz\": _70, \"bzh\": _70, \"cab\": _70, \"cafe\": _70, \"cal\": _70, \"call\": _70, \"calvinklein\": _70, \"cam\": _70, \"camera\": _70, \"camp\": _70, \"canon\": _70, \"capetown\": _70, \"capital\": _70, \"capitalone\": _70, \"car\": _70, \"caravan\": _70, \"cards\": _70, \"care\": _70, \"career\": _70, \"careers\": _70, \"cars\": _70, \"casa\": _70, \"case\": _70, \"cash\": _70, \"casino\": _70, \"catering\": _70, \"catholic\": _70, \"cba\": _70, \"cbn\": _70, \"cbre\": _70, \"center\": _70, \"ceo\": _70, \"cern\": _70, \"cfa\": _70, \"cfd\": _70, \"chanel\": _70, \"channel\": _70, \"charity\": _70, \"chase\": _70, \"chat\": _70, \"cheap\": _70, \"chintai\": _70, \"christmas\": _70, \"chrome\": _70, \"church\": _70, \"cipriani\": _70, \"circle\": _70, \"cisco\": _70, \"citadel\": _70, \"citi\": _70, \"citic\": _70, \"city\": _70, \"claims\": _70, \"cleaning\": _70, \"click\": _70, \"clinic\": _70, \"clinique\": _70, \"clothing\": _70, \"cloud\": _70, \"club\": _70, \"clubmed\": _70, \"coach\": _70, \"codes\": _70, \"coffee\": _70, \"college\": _70, \"\\\ncologne\": _70, \"commbank\": _70, \"community\": _70, \"company\": _70, \"compare\": _70, \"computer\": _70, \"comsec\": _70, \"condos\": _70, \"construction\": _70, \"consulting\": _70, \"contact\": _70, \"contractors\": _70, \"cooking\": _70, \"cool\": _70, \"corsica\": _70, \"country\": _70, \"coupon\": _70, \"coupons\": _70, \"courses\": _70, \"cpa\": _70, \"credit\": _70, \"creditcard\": _70, \"creditunion\": _70, \"cricket\": _70, \"crown\": _70, \"crs\": _70, \"cruise\": _70, \"cruises\": _70, \"cuisinella\": _70, \"cymru\": _70, \"cyou\": _70, \"dad\": _70, \"dance\": _70, \"data\": _70, \"date\": _70, \"dating\": _70, \"datsun\": _70, \"day\": _70, \"dclk\": _70, \"dds\": _70, \"deal\": _70, \"dealer\": _70, \"deals\": _70, \"degree\": _70, \"delivery\": _70, \"dell\": _70, \"deloitte\": _70, \"delta\": _70, \"democrat\": _70, \"dental\": _70, \"dentist\": _70, \"desi\": _70, \"design\": _70, \"dev\": _70, \"dhl\": _70, \"diamonds\": _70, \"diet\": _70, \"digital\": _70, \"direct\": _70, \"directory\": _70, \"discount\": _70, \"discover\": _70, \"dish\": _70, \"diy\": _70, \"dnp\": _70, \"docs\": _70, \"d\\\noctor\": _70, \"dog\": _70, \"domains\": _70, \"dot\": _70, \"download\": _70, \"drive\": _70, \"dtv\": _70, \"dubai\": _70, \"dunlop\": _70, \"dupont\": _70, \"durban\": _70, \"dvag\": _70, \"dvr\": _70, \"earth\": _70, \"eat\": _70, \"eco\": _70, \"edeka\": _70, \"education\": _70, \"email\": _70, \"emerck\": _70, \"energy\": _70, \"engineer\": _70, \"engineering\": _70, \"enterprises\": _70, \"epson\": _70, \"equipment\": _70, \"ericsson\": _70, \"erni\": _70, \"esq\": _70, \"estate\": _70, \"eurovision\": _70, \"eus\": _70, \"events\": _70, \"exchange\": _70, \"expert\": _70, \"exposed\": _70, \"express\": _70, \"extraspace\": _70, \"fage\": _70, \"fail\": _70, \"fairwinds\": _70, \"faith\": _70, \"family\": _70, \"fan\": _70, \"fans\": _70, \"farm\": _70, \"farmers\": _70, \"fashion\": _70, \"fast\": _70, \"fedex\": _70, \"feedback\": _70, \"ferrari\": _70, \"ferrero\": _70, \"fidelity\": _70, \"fido\": _70, \"film\": _70, \"final\": _70, \"finance\": _70, \"financial\": _70, \"fire\": _70, \"firestone\": _70, \"firmdale\": _70, \"fish\": _70, \"fishing\": _70, \"fit\": _70, \"fitness\": _70, \"flickr\": _70, \"\\\nflights\": _70, \"flir\": _70, \"florist\": _70, \"flowers\": _70, \"fly\": _70, \"foo\": _70, \"food\": _70, \"football\": _70, \"ford\": _70, \"forex\": _70, \"forsale\": _70, \"forum\": _70, \"foundation\": _70, \"fox\": _70, \"free\": _70, \"fresenius\": _70, \"frl\": _70, \"frogans\": _70, \"frontier\": _70, \"ftr\": _70, \"fujitsu\": _70, \"fun\": _70, \"fund\": _70, \"furniture\": _70, \"futbol\": _70, \"fyi\": _70, \"gal\": _70, \"gallery\": _70, \"gallo\": _70, \"gallup\": _70, \"game\": _70, \"games\": _70, \"gap\": _70, \"garden\": _70, \"gay\": _70, \"gbiz\": _70, \"gdn\": _70, \"gea\": _70, \"gent\": _70, \"genting\": _70, \"george\": _70, \"ggee\": _70, \"gift\": _70, \"gifts\": _70, \"gives\": _70, \"giving\": _70, \"glass\": _70, \"gle\": _70, \"global\": _70, \"globo\": _70, \"gmail\": _70, \"gmbh\": _70, \"gmo\": _70, \"gmx\": _70, \"godaddy\": _70, \"gold\": _70, \"goldpoint\": _70, \"golf\": _70, \"goo\": _70, \"goodyear\": _70, \"goog\": _70, \"google\": _70, \"gop\": _70, \"got\": _70, \"grainger\": _70, \"graphics\": _70, \"gratis\": _70, \"green\": _70, \"gripe\": _70, \"grocery\": _70, \"group\": _70,\n      \"gucci\": _70, \"guge\": _70, \"guide\": _70, \"guitars\": _70, \"guru\": _70, \"hair\": _70, \"hamburg\": _70, \"hangout\": _70, \"haus\": _70, \"hbo\": _70, \"hdfc\": _70, \"hdfcbank\": _70, \"health\": _70, \"healthcare\": _70, \"help\": _70, \"helsinki\": _70, \"here\": _70, \"hermes\": _70, \"hiphop\": _70, \"hisamitsu\": _70, \"hitachi\": _70, \"hiv\": _70, \"hkt\": _70, \"hockey\": _70, \"holdings\": _70, \"holiday\": _70, \"homedepot\": _70, \"homegoods\": _70, \"homes\": _70, \"homesense\": _70, \"honda\": _70, \"horse\": _70, \"hospital\": _70, \"host\": _70, \"hosting\": _70, \"hot\": _70, \"hotel\": _70, \"hotels\": _70, \"hotmail\": _70, \"house\": _70, \"how\": _70, \"hsbc\": _70, \"hughes\": _70, \"hyatt\": _70, \"hyundai\": _70, \"ibm\": _70, \"icbc\": _70, \"ice\": _70, \"icu\": _70, \"ieee\": _70, \"ifm\": _70, \"ikano\": _70, \"imamat\": _70, \"imdb\": _70, \"immo\": _70, \"immobilien\": _70, \"inc\": _70, \"industries\": _70, \"infiniti\": _70, \"ing\": _70, \"ink\": _70, \"institute\": _70, \"insurance\": _70, \"insure\": _70, \"international\": _70, \"intuit\": _70, \"investments\": _70, \"\\\nipiranga\": _70, \"irish\": _70, \"ismaili\": _70, \"ist\": _70, \"istanbul\": _70, \"itau\": _70, \"itv\": _70, \"jaguar\": _70, \"java\": _70, \"jcb\": _70, \"jeep\": _70, \"jetzt\": _70, \"jewelry\": _70, \"jio\": _70, \"jll\": _70, \"jmp\": _70, \"jnj\": _70, \"joburg\": _70, \"jot\": _70, \"joy\": _70, \"jpmorgan\": _70, \"jprs\": _70, \"juegos\": _70, \"juniper\": _70, \"kaufen\": _70, \"kddi\": _70, \"kerryhotels\": _70, \"kerryproperties\": _70, \"kfh\": _70, \"kia\": _70, \"kids\": _70, \"kim\": _70, \"kindle\": _70, \"kitchen\": _70, \"kiwi\": _70, \"koeln\": _70, \"komatsu\": _70, \"kosher\": _70, \"kpmg\": _70, \"kpn\": _70, \"krd\": _70, \"kred\": _70, \"kuokgroup\": _70, \"kyoto\": _70, \"lacaixa\": _70, \"lamborghini\": _70, \"lamer\": _70, \"land\": _70, \"landrover\": _70, \"lanxess\": _70, \"lasalle\": _70, \"lat\": _70, \"latino\": _70, \"latrobe\": _70, \"law\": _70, \"lawyer\": _70, \"lds\": _70, \"lease\": _70, \"leclerc\": _70, \"lefrak\": _70, \"legal\": _70, \"lego\": _70, \"lexus\": _70, \"lgbt\": _70, \"lidl\": _70, \"life\": _70, \"lifeinsurance\": _70, \"lifestyle\": _70, \"lighting\": _70, \"\\\nlike\": _70, \"lilly\": _70, \"limited\": _70, \"limo\": _70, \"lincoln\": _70, \"link\": _70, \"live\": _70, \"living\": _70, \"llc\": _70, \"llp\": _70, \"loan\": _70, \"loans\": _70, \"locker\": _70, \"locus\": _70, \"lol\": _70, \"london\": _70, \"lotte\": _70, \"lotto\": _70, \"love\": _70, \"lpl\": _70, \"lplfinancial\": _70, \"ltd\": _70, \"ltda\": _70, \"lundbeck\": _70, \"luxe\": _70, \"luxury\": _70, \"madrid\": _70, \"maif\": _70, \"maison\": _70, \"makeup\": _70, \"man\": _70, \"management\": _70, \"mango\": _70, \"map\": _70, \"market\": _70, \"marketing\": _70, \"markets\": _70, \"marriott\": _70, \"marshalls\": _70, \"mattel\": _70, \"mba\": _70, \"mckinsey\": _70, \"med\": _70, \"media\": _70, \"meet\": _70, \"melbourne\": _70, \"meme\": _70, \"memorial\": _70, \"men\": _70, \"menu\": _70, \"merck\": _70, \"merckmsd\": _70, \"miami\": _70, \"microsoft\": _70, \"mini\": _70, \"mint\": _70, \"mit\": _70, \"mitsubishi\": _70, \"mlb\": _70, \"mls\": _70, \"mma\": _70, \"mobile\": _70, \"moda\": _70, \"moe\": _70, \"moi\": _70, \"mom\": _70, \"monash\": _70, \"money\": _70, \"monster\": _70, \"mormon\": _70, \"m\\\nortgage\": _70, \"moscow\": _70, \"moto\": _70, \"motorcycles\": _70, \"mov\": _70, \"movie\": _70, \"msd\": _70, \"mtn\": _70, \"mtr\": _70, \"music\": _70, \"nab\": _70, \"nagoya\": _70, \"navy\": _70, \"nba\": _70, \"nec\": _70, \"netbank\": _70, \"netflix\": _70, \"network\": _70, \"neustar\": _70, \"new\": _70, \"news\": _70, \"next\": _70, \"nextdirect\": _70, \"nexus\": _70, \"nfl\": _70, \"ngo\": _70, \"nhk\": _70, \"nico\": _70, \"nike\": _70, \"nikon\": _70, \"ninja\": _70, \"nissan\": _70, \"nissay\": _70, \"nokia\": _70, \"norton\": _70, \"now\": _70, \"nowruz\": _70, \"nowtv\": _70, \"nra\": _70, \"nrw\": _70, \"ntt\": _70, \"nyc\": _70, \"obi\": _70, \"observer\": _70, \"office\": _70, \"okinawa\": _70, \"olayan\": _70, \"olayangroup\": _70, \"ollo\": _70, \"omega\": _70, \"one\": _70, \"ong\": _70, \"onl\": _70, \"online\": _70, \"ooo\": _70, \"open\": _70, \"oracle\": _70, \"orange\": _70, \"organic\": _70, \"origins\": _70, \"osaka\": _70, \"otsuka\": _70, \"ott\": _70, \"ovh\": _70, \"page\": _70, \"panasonic\": _70, \"paris\": _70, \"pars\": _70, \"partners\": _70, \"parts\": _70, \"party\": _70, \"pay\": _70,\n      \"pccw\": _70, \"pet\": _70, \"pfizer\": _70, \"pharmacy\": _70, \"phd\": _70, \"philips\": _70, \"phone\": _70, \"photo\": _70, \"photography\": _70, \"photos\": _70, \"physio\": _70, \"pics\": _70, \"pictet\": _70, \"pictures\": _70, \"pid\": _70, \"pin\": _70, \"ping\": _70, \"pink\": _70, \"pioneer\": _70, \"pizza\": _70, \"place\": _70, \"play\": _70, \"playstation\": _70, \"plumbing\": _70, \"plus\": _70, \"pnc\": _70, \"pohl\": _70, \"poker\": _70, \"politie\": _70, \"porn\": _70, \"praxi\": _70, \"press\": _70, \"prime\": _70, \"prod\": _70, \"productions\": _70, \"prof\": _70, \"progressive\": _70, \"promo\": _70, \"properties\": _70, \"property\": _70, \"protection\": _70, \"pru\": _70, \"prudential\": _70, \"pub\": _70, \"pwc\": _70, \"qpon\": _70, \"quebec\": _70, \"quest\": _70, \"racing\": _70, \"radio\": _70, \"read\": _70, \"realestate\": _70, \"realtor\": _70, \"realty\": _70, \"recipes\": _70, \"red\": _70, \"redumbrella\": _70, \"rehab\": _70, \"reise\": _70, \"reisen\": _70, \"reit\": _70, \"reliance\": _70, \"ren\": _70, \"rent\": _70, \"rentals\": _70, \"repair\": _70, \"report\": _70, \"re\\\npublican\": _70, \"rest\": _70, \"restaurant\": _70, \"review\": _70, \"reviews\": _70, \"rexroth\": _70, \"rich\": _70, \"richardli\": _70, \"ricoh\": _70, \"ril\": _70, \"rio\": _70, \"rip\": _70, \"rocks\": _70, \"rodeo\": _70, \"rogers\": _70, \"room\": _70, \"rsvp\": _70, \"rugby\": _70, \"ruhr\": _70, \"run\": _70, \"rwe\": _70, \"ryukyu\": _70, \"saarland\": _70, \"safe\": _70, \"safety\": _70, \"sakura\": _70, \"sale\": _70, \"salon\": _70, \"samsclub\": _70, \"samsung\": _70, \"sandvik\": _70, \"sandvikcoromant\": _70, \"sanofi\": _70, \"sap\": _70, \"sarl\": _70, \"sas\": _70, \"save\": _70, \"saxo\": _70, \"sbi\": _70, \"sbs\": _70, \"scb\": _70, \"schaeffler\": _70, \"schmidt\": _70, \"scholarships\": _70, \"school\": _70, \"schule\": _70, \"schwarz\": _70, \"science\": _70, \"scot\": _70, \"search\": _70, \"seat\": _70, \"secure\": _70, \"security\": _70, \"seek\": _70, \"select\": _70, \"sener\": _70, \"services\": _70, \"seven\": _70, \"sew\": _70, \"sex\": _70, \"sexy\": _70, \"sfr\": _70, \"shangrila\": _70, \"sharp\": _70, \"shell\": _70, \"shia\": _70, \"shiksha\": _70, \"shoes\": _70, \"shop\": _70, \"\\\nshopping\": _70, \"shouji\": _70, \"show\": _70, \"silk\": _70, \"sina\": _70, \"singles\": _70, \"site\": _70, \"ski\": _70, \"skin\": _70, \"sky\": _70, \"skype\": _70, \"sling\": _70, \"smart\": _70, \"smile\": _70, \"sncf\": _70, \"soccer\": _70, \"social\": _70, \"softbank\": _70, \"software\": _70, \"sohu\": _70, \"solar\": _70, \"solutions\": _70, \"song\": _70, \"sony\": _70, \"soy\": _70, \"spa\": _70, \"space\": _70, \"sport\": _70, \"spot\": _70, \"srl\": _70, \"stada\": _70, \"staples\": _70, \"star\": _70, \"statebank\": _70, \"statefarm\": _70, \"stc\": _70, \"stcgroup\": _70, \"stockholm\": _70, \"storage\": _70, \"store\": _70, \"stream\": _70, \"studio\": _70, \"study\": _70, \"style\": _70, \"sucks\": _70, \"supplies\": _70, \"supply\": _70, \"support\": _70, \"surf\": _70, \"surgery\": _70, \"suzuki\": _70, \"swatch\": _70, \"swiss\": _70, \"sydney\": _70, \"systems\": _70, \"tab\": _70, \"taipei\": _70, \"talk\": _70, \"taobao\": _70, \"target\": _70, \"tatamotors\": _70, \"tatar\": _70, \"tattoo\": _70, \"tax\": _70, \"taxi\": _70, \"tci\": _70, \"tdk\": _70, \"team\": _70, \"tech\": _70, \"technolog\\\ny\": _70, \"temasek\": _70, \"tennis\": _70, \"teva\": _70, \"thd\": _70, \"theater\": _70, \"theatre\": _70, \"tiaa\": _70, \"tickets\": _70, \"tienda\": _70, \"tips\": _70, \"tires\": _70, \"tirol\": _70, \"tjmaxx\": _70, \"tjx\": _70, \"tkmaxx\": _70, \"tmall\": _70, \"today\": _70, \"tokyo\": _70, \"tools\": _70, \"top\": _70, \"toray\": _70, \"toshiba\": _70, \"total\": _70, \"tours\": _70, \"town\": _70, \"toyota\": _70, \"toys\": _70, \"trade\": _70, \"trading\": _70, \"training\": _70, \"travel\": _70, \"travelers\": _70, \"travelersinsurance\": _70, \"trust\": _70, \"trv\": _70, \"tube\": _70, \"tui\": _70, \"tunes\": _70, \"tushu\": _70, \"tvs\": _70, \"ubank\": _70, \"ubs\": _70, \"unicom\": _70, \"university\": _70, \"uno\": _70, \"uol\": _70, \"ups\": _70, \"vacations\": _70, \"vana\": _70, \"vanguard\": _70, \"vegas\": _70, \"ventures\": _70, \"verisign\": _70, \"versicherung\": _70, \"vet\": _70, \"viajes\": _70, \"video\": _70, \"vig\": _70, \"viking\": _70, \"villas\": _70, \"vin\": _70, \"vip\": _70, \"virgin\": _70, \"visa\": _70, \"vision\": _70, \"viva\": _70, \"vivo\": _70, \"vlaanderen\": _70, \"vo\\\ndka\": _70, \"volvo\": _70, \"vote\": _70, \"voting\": _70, \"voto\": _70, \"voyage\": _70, \"wales\": _70, \"walmart\": _70, \"walter\": _70, \"wang\": _70, \"wanggou\": _70, \"watch\": _70, \"watches\": _70, \"weather\": _70, \"weatherchannel\": _70, \"webcam\": _70, \"weber\": _70, \"website\": _70, \"wed\": _70, \"wedding\": _70, \"weibo\": _70, \"weir\": _70, \"whoswho\": _70, \"wien\": _70, \"wiki\": _70, \"williamhill\": _70, \"win\": _70, \"windows\": _70, \"wine\": _70, \"winners\": _70, \"wme\": _70, \"wolterskluwer\": _70, \"woodside\": _70, \"work\": _70, \"works\": _70, \"world\": _70, \"wow\": _70, \"wtc\": _70, \"wtf\": _70, \"xbox\": _70, \"xerox\": _70, \"xihuan\": _70, \"xin\": _70, \"xn--11b4c3d\": _70, \"कॉम\": _70, \"xn--1ck2e1b\": _70, \"セール\": _70, \"xn--1qqw23a\": _70, \"佛山\": _70, \"xn--30rr7y\": _70, \"慈善\": _70, \"xn--3bst00m\": _70, \"集团\": _70, \"xn--3ds443g\": _70, \"在线\": _70, \"xn--3pxu8k\": _70, \"点看\": _70, \"xn--42c2d9a\": _70, \"คอม\": _70, \"xn--45q11c\": _70, \"八卦\": _70, \"xn--4gbrim\": _70, \"موقع\": _70, \"xn--55qw42g\": _70,\n      \"公益\": _70, \"xn--55qx5d\": _70, \"公司\": _70, \"xn--5su34j936bgsg\": _70, \"香格里拉\": _70, \"xn--5tzm5g\": _70, \"网站\": _70, \"xn--6frz82g\": _70, \"移动\": _70, \"xn--6qq986b3xl\": _70, \"我爱你\": _70, \"xn--80adxhks\": _70, \"москва\": _70, \"xn--80aqecdr1a\": _70, \"католик\": _70, \"xn--80asehdb\": _70, \"онлайн\": _70, \"xn--80aswg\": _70, \"сайт\": _70, \"xn--8y0a063a\": _70, \"联通\": _70, \"xn--9dbq2a\": _70, \"קום\": _70, \"xn--9et52u\": _70, \"时尚\": _70, \"xn--9krt00a\": _70, \"微博\": _70, \"xn--b4w605ferd\": _70, \"淡马锡\": _70, \"xn--bck1b9a5dre4c\": _70, \"ファッション\": _70, \"xn--c1avg\": _70, \"орг\": _70, \"xn--c2br7g\": _70, \"नेट\": _70, \"xn--cck2b3b\": _70, \"ストア\": _70, \"xn--cckwcxetd\": _70, \"アマゾン\": _70, \"xn--cg4bki\": _70, \"삼성\": _70, \"xn--czr694b\": _70, \"商标\": _70, \"xn--czrs0t\": _70, \"商店\": _70, \"xn--czru2d\": _70, \"商城\": _70, \"xn--d1acj3b\": _70, \"дети\": _70, \"xn--eckvdtc9d\": _70, \"ポイント\": _70, \"xn--efvy88h\": _70, \"\\\n新闻\": _70, \"xn--fct429k\": _70, \"家電\": _70, \"xn--fhbei\": _70, \"كوم\": _70, \"xn--fiq228c5hs\": _70, \"中文网\": _70, \"xn--fiq64b\": _70, \"中信\": _70, \"xn--fjq720a\": _70, \"娱乐\": _70, \"xn--flw351e\": _70, \"谷歌\": _70, \"xn--fzys8d69uvgm\": _70, \"電訊盈科\": _70, \"xn--g2xx48c\": _70, \"购物\": _70, \"xn--gckr3f0f\": _70, \"クラウド\": _70, \"xn--gk3at1e\": _70, \"通販\": _70, \"xn--hxt814e\": _70, \"网店\": _70, \"xn--i1b6b1a6a2e\": _70, \"संगठन\": _70, \"xn--imr513n\": _70, \"餐厅\": _70, \"xn--io0a7i\": _70, \"网络\": _70, \"xn--j1aef\": _70, \"ком\": _70, \"xn--jlq480n2rg\": _70, \"亚马逊\": _70, \"xn--jvr189m\": _70, \"食品\": _70, \"xn--kcrx77d1x4a\": _70, \"飞利浦\": _70, \"xn--kput3i\": _70, \"手机\": _70, \"xn--mgba3a3ejt\": _70, \"ارامكو\": _70, \"xn--mgba7c0bbn0a\": _70, \"العليان\": _70, \"xn--mgbab2bd\": _70, \"بازار\": _70, \"xn--mgbca7dzdo\": _70, \"ابوظبي\": _70, \"xn--mgbi4ecexp\": _70, \"كاثوليك\": _70, \"xn--mgbt3dhd\": _70, \"همراه\": _70, \"xn--mk1bu44c\": _70,\n      \"닷컴\": _70, \"xn--mxtq1m\": _70, \"政府\": _70, \"xn--ngbc5azd\": _70, \"شبكة\": _70, \"xn--ngbe9e0a\": _70, \"بيتك\": _70, \"xn--ngbrx\": _70, \"عرب\": _70, \"xn--nqv7f\": _70, \"机构\": _70, \"xn--nqv7fs00ema\": _70, \"组织机构\": _70, \"xn--nyqy26a\": _70, \"健康\": _70, \"xn--otu796d\": _70, \"招聘\": _70, \"xn--p1acf\": _70, \"рус\": _70, \"xn--pssy2u\": _70, \"大拿\": _70, \"xn--q9jyb4c\": _70, \"みんな\": _70, \"xn--qcka1pmc\": _70, \"グーグル\": _70, \"xn--rhqv96g\": _70, \"世界\": _70, \"xn--rovu88b\": _70, \"書籍\": _70, \"xn--ses554g\": _70, \"网址\": _70, \"xn--t60b56a\": _70, \"닷넷\": _70, \"xn--tckwe\": _70, \"コム\": _70, \"xn--tiq49xqyj\": _70, \"天主教\": _70, \"xn--unup4y\": _70, \"游戏\": _70, \"xn--vermgensberater-ctb\": _70, \"vermögensberater\": _70, \"xn--vermgensberatung-pwb\": _70, \"vermögensberatung\": _70, \"xn--vhquv\": _70, \"企业\": _70, \"xn--vuq861b\": _70, \"信息\": _70, \"xn--w4r85el8fhu5dnra\": _70, \"嘉里大酒店\": _70, \"xn--w4rs40l\": _70, \"嘉里\": _70, \"xn--xhq521b\": _70, \"\\\n广东\": _70, \"xn--zfr164b\": _70, \"政务\": _70, \"xyz\": _70, \"yachts\": _70, \"yahoo\": _70, \"yamaxun\": _70, \"yandex\": _70, \"yodobashi\": _70, \"yoga\": _70, \"yokohama\": _70, \"you\": _70, \"youtube\": _70, \"yun\": _70, \"zappos\": _70, \"zara\": _70, \"zero\": _70, \"zip\": _70, \"zone\": _70, \"zuerich\": _70 }];\n      return rules2;\n    })();\n    function lookupInTrie(parts, trie, index) {\n      let result = null;\n      let node = trie;\n      while (node !== void 0) {\n        if (node[0] === 1) {\n          result = {\n            index: index + 1\n          };\n        }\n        if (index === -1) {\n          break;\n        }\n        const succ = node[1];\n        node = Object.prototype.hasOwnProperty.call(succ, parts[index]) ? succ[parts[index]] : succ[\"*\"];\n        index -= 1;\n      }\n      return result;\n    }\n    __name(lookupInTrie, \"lookupInTrie\");\n    function suffixLookup(hostname, options, out) {\n      var _a3;\n      if (fastPathLookup(hostname, options, out)) {\n        return;\n      }\n      const hostnameParts = hostname.split(\".\");\n      const exceptionMatch = lookupInTrie(hostnameParts, exceptions, hostnameParts.length - 1);\n      if (exceptionMatch !== null) {\n        out.publicSuffix = hostnameParts.slice(exceptionMatch.index + 1).join(\".\");\n        return;\n      }\n      const rulesMatch = lookupInTrie(hostnameParts, rules, hostnameParts.length - 1);\n      if (rulesMatch !== null) {\n        out.publicSuffix = hostnameParts.slice(rulesMatch.index).join(\".\");\n        return;\n      }\n      out.publicSuffix = (_a3 = hostnameParts[hostnameParts.length - 1]) !== null && _a3 !== void 0 ? _a3 : null;\n    }\n    __name(suffixLookup, \"suffixLookup\");\n    var RESULT = getEmptyResult();\n    function parse(url, options = {}) {\n      return parseImpl(url, 5, suffixLookup, options, getEmptyResult());\n    }\n    __name(parse, \"parse\");\n    function getHostname(url, options = {}) {\n      resetResult(RESULT);\n      return parseImpl(url, 0, suffixLookup, options, RESULT).hostname;\n    }\n    __name(getHostname, \"getHostname\");\n    function getPublicSuffix(url, options = {}) {\n      resetResult(RESULT);\n      return parseImpl(url, 2, suffixLookup, options, RESULT).publicSuffix;\n    }\n    __name(getPublicSuffix, \"getPublicSuffix\");\n    function getDomain2(url, options = {}) {\n      resetResult(RESULT);\n      return parseImpl(url, 3, suffixLookup, options, RESULT).domain;\n    }\n    __name(getDomain2, \"getDomain\");\n    function getSubdomain(url, options = {}) {\n      resetResult(RESULT);\n      return parseImpl(url, 4, suffixLookup, options, RESULT).subdomain;\n    }\n    __name(getSubdomain, \"getSubdomain\");\n    function getDomainWithoutSuffix(url, options = {}) {\n      resetResult(RESULT);\n      return parseImpl(url, 5, suffixLookup, options, RESULT).domainWithoutSuffix;\n    }\n    __name(getDomainWithoutSuffix, \"getDomainWithoutSuffix\");\n    exports2.getDomain = getDomain2;\n    exports2.getDomainWithoutSuffix = getDomainWithoutSuffix;\n    exports2.getHostname = getHostname;\n    exports2.getPublicSuffix = getPublicSuffix;\n    exports2.getSubdomain = getSubdomain;\n    exports2.parse = parse;\n  }\n});\n\n// core/lib/lh-error.js\nvar UIStrings20, str_, LHERROR_SENTINEL, ERROR_SENTINEL, LighthouseError, ERRORS;\nvar init_lh_error = __esm({\n  \"core/lib/lh-error.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_i18n();\n    /**\n     * @license\n     * Copyright 2018 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    UIStrings20 = {\n      /**\n       * @description Error message explaining that the Lighthouse run was not able to collect screenshots through Chrome.\n       * @example {NO_SPEEDLINE_FRAMES} errorCode\n       * */\n      didntCollectScreenshots: `Chrome didn't collect any screenshots during the page load. Please make sure there is content visible on the page, and then try re-running Lighthouse. ({errorCode})`,\n      /**\n       * @description Error message explaining that the performance trace was not able to be recorded for the Lighthouse run.\n       * @example {NO_TRACING_STARTED} errorCode\n       * */\n      badTraceRecording: \"Something went wrong with recording the trace over your page load. Please run Lighthouse again. ({errorCode})\",\n      /**\n       * @description Error message explaining that the First Contentful Paint metric was not seen during the page load.\n       * @example {NO_FCP} errorCode\n       * */\n      noFcp: \"The page did not paint any content. Please ensure you keep the browser window in the foreground during the load and try again. ({errorCode})\",\n      /**\n       * @description Error message explaining that the Largest Contentful Paint metric was not seen during the page load.\n       * @example {NO_LCP} errorCode\n       * */\n      noLcp: \"The page did not display content that qualifies as a Largest Contentful Paint (LCP). Ensure the page has a valid LCP element and then try again. ({errorCode})\",\n      /**\n       * @description Error message explaining that the page loaded too slowly to perform a Lighthouse run.\n       * @example {NO_TTI_CPU_IDLE_PERIOD} errorCode\n       * */\n      pageLoadTookTooLong: \"Your page took too long to load. Please follow the opportunities in the report to reduce your page load time, and then try re-running Lighthouse. ({errorCode})\",\n      /** Error message explaining that Lighthouse could not load the requested URL and the steps that might be taken to fix the unreliability. */\n      pageLoadFailed: \"Lighthouse was unable to reliably load the page you requested. Make sure you are testing the correct URL and that the server is properly responding to all requests.\",\n      /**\n       * @description Error message explaining that Lighthouse could not load the requested URL and the steps that might be taken to fix the unreliability.\n       * @example {404} statusCode\n       * */\n      pageLoadFailedWithStatusCode: \"Lighthouse was unable to reliably load the page you requested. Make sure you are testing the correct URL and that the server is properly responding to all requests. (Status code: {statusCode})\",\n      /**\n       * @description Error message explaining that Lighthouse could not load the requested URL and the steps that might be taken to fix the unreliability.\n       * @example {FAILED_DOCUMENT_REQUEST} errorDetails\n       * */\n      pageLoadFailedWithDetails: \"Lighthouse was unable to reliably load the page you requested. Make sure you are testing the correct URL and that the server is properly responding to all requests. (Details: {errorDetails})\",\n      /**\n       * @description Error message explaining that the security certificate of the page Lighthouse observed was invalid, so the URL cannot be accessed. securityMessages will be replaced with one or more strings from the browser explaining what was insecure about the page load.\n       * @example {net::ERR_CERT_DATE_INVALID} securityMessages\n       * */\n      pageLoadFailedInsecure: \"The URL you have provided does not have a valid security certificate. {securityMessages}\",\n      /** Error message explaining that Chrome prevented the page from loading and displayed an interstitial screen instead, so the URL cannot be accessed. */\n      pageLoadFailedInterstitial: \"Chrome prevented page load with an interstitial. Make sure you are testing the correct URL and that the server is properly responding to all requests.\",\n      /** Error message explaining that Chrome has encountered an error during the Lighthouse run, and that Chrome should be restarted. */\n      internalChromeError: \"An internal Chrome error occurred. Please restart Chrome and try re-running Lighthouse.\",\n      /** Error message explaining that fetching the resources of the webpage has taken longer than the maximum time. */\n      requestContentTimeout: \"Fetching resource content has exceeded the allotted time\",\n      /**\n       * @description Error message explaining that the webpage is non-HTML, so audits are ill-defined.\n       * @example {application/xml} mimeType\n       * */\n      notHtml: \"The page provided is not HTML (served as MIME type {mimeType}).\",\n      /** Error message explaining that the provided URL Lighthouse points to is not valid, and cannot be loaded. */\n      urlInvalid: \"The URL you have provided appears to be invalid.\",\n      /**\n       * @description Error message explaining that the Chrome Devtools protocol has exceeded the maximum timeout allowed.\n       * @example {Network.enable} protocolMethod\n       * */\n      protocolTimeout: \"Waiting for DevTools protocol response has exceeded the allotted time. (Method: {protocolMethod})\",\n      /** Error message explaining that the requested page could not be resolved by the DNS server. */\n      dnsFailure: \"DNS servers could not resolve the provided domain.\",\n      /** Error message explaining that Lighthouse couldn't complete because the page has stopped responding to its instructions. */\n      pageLoadFailedHung: \"Lighthouse was unable to reliably load the URL you requested because the page stopped responding.\",\n      /** Error message explaining that Lighthouse timed out while waiting for the initial connection to the Chrome Devtools protocol. */\n      criTimeout: \"Timeout waiting for initial Debugger Protocol connection.\",\n      /**\n       * @description Error message explaining that a resource that was required for testing was never collected. \"artifactName\" will be replaced with the name of the resource that wasn't collected.\n       * @example {MainDocumentContent} artifactName\n       * */\n      missingRequiredArtifact: \"Required {artifactName} gatherer did not run.\",\n      /**\n       * @description Error message explaining that there was an error while trying to collect a resource that was required for testing. \"artifactName\" will be replaced with the name of the resource that wasn't collected; \"errorMessage\" will be replaced with a string description of the error that occurred.\n       * @example {MainDocumentContent} artifactName\n       * @example {Could not find main document} errorMessage\n       * */\n      erroredRequiredArtifact: \"Required {artifactName} gatherer encountered an error: {errorMessage}\",\n      /**\n       * @description Error message explaining that a feature is unavailable due to an old version of Chrome. \"featureName\" will be replaced by the name of the feature which is not supported.\n       * @example {Largest Contentful Paint} featureName\n       * */\n      oldChromeDoesNotSupportFeature: \"This version of Chrome is too old to support '{featureName}'. Use a newer version to see full results.\",\n      /** Error message explaining that the browser tab that Lighthouse is inspecting has crashed. */\n      targetCrashed: \"Browser tab has unexpectedly crashed.\"\n    };\n    str_ = createIcuMessageFn({ url: \"core/lib/lh-error.js\" }.url, UIStrings20);\n    LHERROR_SENTINEL = \"__LighthouseErrorSentinel\";\n    ERROR_SENTINEL = \"__ErrorSentinel\";\n    LighthouseError = class _LighthouseError extends Error {\n      static {\n        __name(this, \"LighthouseError\");\n      }\n      /**\n       * @param {LighthouseErrorDefinition} errorDefinition\n       * @param {Record<string, string|undefined>=} properties\n       * @param {LHErrorOptions=} options\n       */\n      constructor(errorDefinition, properties, options) {\n        super(errorDefinition.code, options);\n        this.name = \"LighthouseError\";\n        this.code = errorDefinition.code;\n        this.friendlyMessage = str_(errorDefinition.message, { errorCode: this.code, ...properties });\n        this.lhrRuntimeError = !!errorDefinition.lhrRuntimeError;\n        if (properties) Object.assign(this, properties);\n        Error.captureStackTrace(this, _LighthouseError);\n      }\n      /**\n       * @param {string} method\n       * @param {{message: string, data?: string|undefined}} protocolError\n       * @return {Error|LighthouseError}\n       */\n      static fromProtocolMessage(method, protocolError) {\n        const matchedErrorDefinition = Object.values(_LighthouseError.errors).filter((e) => e.pattern).find((e) => e.pattern && e.pattern.test(protocolError.message));\n        if (matchedErrorDefinition) {\n          return new _LighthouseError(matchedErrorDefinition);\n        }\n        let errMsg = `(${method}): ${protocolError.message}`;\n        if (protocolError.data) errMsg += ` (${protocolError.data})`;\n        const error = new Error(`Protocol error ${errMsg}`);\n        return Object.assign(error, { protocolMethod: method, protocolError: protocolError.message });\n      }\n      /**\n       * A JSON.stringify replacer to serialize LighthouseErrors and (as a fallback) Errors.\n       * Returns a simplified version of the error object that can be reconstituted\n       * as a copy of the original error at parse time.\n       * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#The_replacer_parameter\n       * @param {Error|LighthouseError} err\n       * @return {SerializedBaseError|SerializedLighthouseError}\n       */\n      static stringifyReplacer(err) {\n        if (err instanceof _LighthouseError) {\n          const { name, code, message, friendlyMessage, lhrRuntimeError, stack, cause, ...properties } = err;\n          return {\n            sentinel: LHERROR_SENTINEL,\n            code,\n            stack,\n            cause,\n            properties: (\n              /** @type {{ [p: string]: string | undefined }} */\n              properties\n            )\n          };\n        }\n        if (err instanceof Error) {\n          const { message, stack, cause } = err;\n          const code = err.code;\n          return {\n            sentinel: ERROR_SENTINEL,\n            message,\n            code,\n            stack,\n            cause\n          };\n        }\n        throw new Error(\"Invalid value for LighthouseError stringification\");\n      }\n      /**\n       * A JSON.parse reviver. If any value passed in is a serialized Error or\n       * LighthouseError, the error is recreated as the original object. Otherwise, the\n       * value is passed through unchanged.\n       * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse#Using_the_reviver_parameter\n       * @param {string} key\n       * @param {any} possibleError\n       * @return {any}\n       */\n      static parseReviver(key, possibleError) {\n        if (typeof possibleError === \"object\" && possibleError !== null) {\n          if (possibleError.sentinel === LHERROR_SENTINEL) {\n            const { code, stack, cause, properties } = (\n              /** @type {SerializedLighthouseError} */\n              possibleError\n            );\n            const errorDefinition = _LighthouseError.errors[\n              /** @type {keyof typeof ERRORS} */\n              code\n            ];\n            const lhError = new _LighthouseError(errorDefinition, properties, { cause });\n            lhError.stack = stack;\n            return lhError;\n          }\n          if (possibleError.sentinel === ERROR_SENTINEL) {\n            const { message, code, stack, cause } = (\n              /** @type {SerializedBaseError} */\n              possibleError\n            );\n            const opts = cause ? { cause } : void 0;\n            const error = new Error(message, opts);\n            Object.assign(error, { code, stack });\n            return error;\n          }\n        }\n        return possibleError;\n      }\n    };\n    ERRORS = {\n      // Screenshot/speedline errors\n      NO_SPEEDLINE_FRAMES: {\n        code: \"NO_SPEEDLINE_FRAMES\",\n        message: UIStrings20.didntCollectScreenshots,\n        lhrRuntimeError: true\n      },\n      SPEEDINDEX_OF_ZERO: {\n        code: \"SPEEDINDEX_OF_ZERO\",\n        message: UIStrings20.didntCollectScreenshots,\n        lhrRuntimeError: true\n      },\n      NO_SCREENSHOTS: {\n        code: \"NO_SCREENSHOTS\",\n        message: UIStrings20.didntCollectScreenshots,\n        lhrRuntimeError: true\n      },\n      INVALID_SPEEDLINE: {\n        code: \"INVALID_SPEEDLINE\",\n        message: UIStrings20.didntCollectScreenshots,\n        lhrRuntimeError: true\n      },\n      // Trace parsing errors\n      NO_TRACING_STARTED: {\n        code: \"NO_TRACING_STARTED\",\n        message: UIStrings20.badTraceRecording,\n        lhrRuntimeError: true\n      },\n      NO_RESOURCE_REQUEST: {\n        code: \"NO_RESOURCE_REQUEST\",\n        message: UIStrings20.badTraceRecording,\n        lhrRuntimeError: true\n      },\n      NO_NAVSTART: {\n        code: \"NO_NAVSTART\",\n        message: UIStrings20.badTraceRecording,\n        lhrRuntimeError: true\n      },\n      NO_FCP: {\n        code: \"NO_FCP\",\n        message: UIStrings20.noFcp,\n        lhrRuntimeError: true\n      },\n      NO_DCL: {\n        code: \"NO_DCL\",\n        message: UIStrings20.badTraceRecording,\n        lhrRuntimeError: true\n      },\n      NO_FMP: {\n        code: \"NO_FMP\",\n        message: UIStrings20.badTraceRecording\n      },\n      NO_LCP: {\n        code: \"NO_LCP\",\n        message: UIStrings20.noLcp\n      },\n      NO_LCP_ALL_FRAMES: {\n        code: \"NO_LCP_ALL_FRAMES\",\n        message: UIStrings20.noLcp\n      },\n      UNSUPPORTED_OLD_CHROME: {\n        code: \"UNSUPPORTED_OLD_CHROME\",\n        message: UIStrings20.oldChromeDoesNotSupportFeature\n      },\n      // TTI calculation failures\n      NO_TTI_CPU_IDLE_PERIOD: { code: \"NO_TTI_CPU_IDLE_PERIOD\", message: UIStrings20.pageLoadTookTooLong },\n      NO_TTI_NETWORK_IDLE_PERIOD: {\n        code: \"NO_TTI_NETWORK_IDLE_PERIOD\",\n        message: UIStrings20.pageLoadTookTooLong\n      },\n      // Page load failures\n      NO_DOCUMENT_REQUEST: {\n        code: \"NO_DOCUMENT_REQUEST\",\n        message: UIStrings20.pageLoadFailed,\n        lhrRuntimeError: true\n      },\n      /* Used when DevTools reports loading failed. Usually an internal (Chrome) issue.\n       * Requries an additional `errorDetails` field for translation.\n       */\n      FAILED_DOCUMENT_REQUEST: {\n        code: \"FAILED_DOCUMENT_REQUEST\",\n        message: UIStrings20.pageLoadFailedWithDetails,\n        lhrRuntimeError: true\n      },\n      /* Used when status code is 4xx or 5xx.\n       * Requires an additional `statusCode` field for translation.\n       */\n      ERRORED_DOCUMENT_REQUEST: {\n        code: \"ERRORED_DOCUMENT_REQUEST\",\n        message: UIStrings20.pageLoadFailedWithStatusCode,\n        lhrRuntimeError: true\n      },\n      /* Used when security error prevents page load.\n       * Requires an additional `securityMessages` field for translation.\n       */\n      INSECURE_DOCUMENT_REQUEST: {\n        code: \"INSECURE_DOCUMENT_REQUEST\",\n        message: UIStrings20.pageLoadFailedInsecure,\n        lhrRuntimeError: true\n      },\n      /* Used when any Chrome interstitial error prevents page load.\n       */\n      CHROME_INTERSTITIAL_ERROR: {\n        code: \"CHROME_INTERSTITIAL_ERROR\",\n        message: UIStrings20.pageLoadFailedInterstitial,\n        lhrRuntimeError: true\n      },\n      /* Used when the page stopped responding and did not finish loading. */\n      PAGE_HUNG: {\n        code: \"PAGE_HUNG\",\n        message: UIStrings20.pageLoadFailedHung,\n        lhrRuntimeError: true\n      },\n      /* Used when the page is non-HTML. */\n      NOT_HTML: {\n        code: \"NOT_HTML\",\n        message: UIStrings20.notHtml,\n        lhrRuntimeError: true\n      },\n      // Protocol internal failures\n      TRACING_ALREADY_STARTED: {\n        code: \"TRACING_ALREADY_STARTED\",\n        message: UIStrings20.internalChromeError,\n        pattern: /Tracing.*started/,\n        lhrRuntimeError: true\n      },\n      PARSING_PROBLEM: {\n        code: \"PARSING_PROBLEM\",\n        message: UIStrings20.internalChromeError,\n        pattern: /Parsing problem/,\n        lhrRuntimeError: true\n      },\n      READ_FAILED: {\n        code: \"READ_FAILED\",\n        message: UIStrings20.internalChromeError,\n        pattern: /Read failed/,\n        lhrRuntimeError: true\n      },\n      // URL parsing failures\n      INVALID_URL: {\n        code: \"INVALID_URL\",\n        message: UIStrings20.urlInvalid\n      },\n      /* Protocol timeout failures\n       * Requires an additional `protocolMethod` field for translation.\n       */\n      PROTOCOL_TIMEOUT: {\n        code: \"PROTOCOL_TIMEOUT\",\n        message: UIStrings20.protocolTimeout,\n        lhrRuntimeError: true\n      },\n      // DNS failure on main document (no resolution, timed out, etc)\n      DNS_FAILURE: {\n        code: \"DNS_FAILURE\",\n        message: UIStrings20.dnsFailure,\n        lhrRuntimeError: true\n      },\n      /** A timeout in the initial connection to the debugger protocol. */\n      CRI_TIMEOUT: {\n        code: \"CRI_TIMEOUT\",\n        message: UIStrings20.criTimeout,\n        lhrRuntimeError: true\n      },\n      /**\n       * Error internal to Runner used when an artifact required for an audit is missing.\n       * Requires an additional `artifactName` field for translation.\n      */\n      MISSING_REQUIRED_ARTIFACT: {\n        code: \"MISSING_REQUIRED_ARTIFACT\",\n        message: UIStrings20.missingRequiredArtifact\n      },\n      /**\n       * Error internal to Runner used when an artifact required for an audit was an error.\n       * Requires additional `artifactName` and `errorMessage` fields for translation.\n      */\n      ERRORED_REQUIRED_ARTIFACT: {\n        code: \"ERRORED_REQUIRED_ARTIFACT\",\n        message: UIStrings20.erroredRequiredArtifact\n      },\n      /** The page has crashed and will no longer respond to 99% of CDP commmands. */\n      TARGET_CRASHED: {\n        code: \"TARGET_CRASHED\",\n        message: UIStrings20.targetCrashed,\n        lhrRuntimeError: true\n      }\n      // Hey! When adding a new error type, update lighthouse-result.proto too.\n      // Only necessary for runtime errors, which come from artifacts or pageLoadErrors.\n    };\n    LighthouseError.errors = ERRORS;\n    LighthouseError.NO_ERROR = \"NO_ERROR\";\n    LighthouseError.UNKNOWN_ERROR = \"UNKNOWN_ERROR\";\n  }\n});\n\n// core/lib/url-utils.js\nfunction rewriteChromeInternalUrl(url) {\n  if (!url || !url.startsWith(\"chrome://\")) return url;\n  if (url.endsWith(\"/\")) url = url.replace(/\\/$/, \"\");\n  return url.replace(/^chrome:\\/\\/chrome\\//, \"chrome://\");\n}\nvar import_tldts_icann, allowedProtocols, SECURE_SCHEMES, SECURE_LOCALHOST_DOMAINS2, NON_NETWORK_SCHEMES3, UrlUtils2, url_utils_default;\nvar init_url_utils = __esm({\n  \"core/lib/url-utils.js\"() {\n    \"use strict\";\n    init_process_global();\n    import_tldts_icann = __toESM(require_cjs(), 1);\n    init_util();\n    init_lh_error();\n    /**\n     * @license\n     * Copyright 2016 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    allowedProtocols = [\n      \"https:\",\n      \"http:\",\n      \"chrome:\",\n      \"chrome-extension:\"\n    ];\n    SECURE_SCHEMES = [\n      \"data\",\n      \"https\",\n      \"wss\",\n      \"blob\",\n      \"chrome\",\n      \"chrome-extension\",\n      \"about\",\n      \"filesystem\"\n    ];\n    SECURE_LOCALHOST_DOMAINS2 = [\"localhost\", \"127.0.0.1\"];\n    NON_NETWORK_SCHEMES3 = [\n      \"blob\",\n      // @see https://developer.mozilla.org/en-US/docs/Web/API/URL/createObjectURL\n      \"data\",\n      // @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs\n      \"intent\",\n      // @see https://developer.chrome.com/docs/multidevice/android/intents/\n      \"file\",\n      // @see https://en.wikipedia.org/wiki/File_URI_scheme\n      \"filesystem\",\n      // @see https://developer.mozilla.org/en-US/docs/Web/API/FileSystem\n      \"chrome-extension\"\n    ];\n    __name(rewriteChromeInternalUrl, \"rewriteChromeInternalUrl\");\n    UrlUtils2 = class _UrlUtils {\n      static {\n        __name(this, \"UrlUtils\");\n      }\n      /**\n       * @param {string} url\n       * @return {boolean}\n       */\n      static isValid(url) {\n        try {\n          new URL(url);\n          return true;\n        } catch (e) {\n          return false;\n        }\n      }\n      /**\n       * @param {string} urlA\n       * @param {string} urlB\n       * @return {boolean}\n       */\n      static hostsMatch(urlA, urlB) {\n        try {\n          return new URL(urlA).host === new URL(urlB).host;\n        } catch (e) {\n          return false;\n        }\n      }\n      /**\n       * @param {string} urlA\n       * @param {string} urlB\n       * @return {boolean}\n       */\n      static originsMatch(urlA, urlB) {\n        try {\n          return new URL(urlA).origin === new URL(urlB).origin;\n        } catch (e) {\n          return false;\n        }\n      }\n      /**\n       * @param {string} url\n       * @return {?string}\n       */\n      static getOrigin(url) {\n        try {\n          const urlInfo = new URL(url);\n          if (urlInfo.protocol === \"chrome-extension:\") {\n            return Util.getChromeExtensionOrigin(url);\n          }\n          return urlInfo.host && urlInfo.origin || null;\n        } catch (e) {\n          return null;\n        }\n      }\n      /**\n       * Returns a primary domain for provided hostname (e.g. www.example.com -> example.com).\n       * @param {string|URL} url hostname or URL object\n       * @return {string}\n       */\n      static getRootDomain(url) {\n        const parsedUrl = Util.createOrReturnURL(url);\n        return (0, import_tldts_icann.getDomain)(parsedUrl.href) || parsedUrl.hostname;\n      }\n      /**\n       * Check if rootDomains matches\n       *\n       * @param {string|URL} urlA\n       * @param {string|URL} urlB\n       */\n      static rootDomainsMatch(urlA, urlB) {\n        let urlAInfo;\n        let urlBInfo;\n        try {\n          urlAInfo = Util.createOrReturnURL(urlA);\n          urlBInfo = Util.createOrReturnURL(urlB);\n        } catch (err) {\n          return false;\n        }\n        if (!urlAInfo.hostname || !urlBInfo.hostname) {\n          return false;\n        }\n        const urlARootDomain = _UrlUtils.getRootDomain(urlAInfo);\n        const urlBRootDomain = _UrlUtils.getRootDomain(urlBInfo);\n        return urlARootDomain === urlBRootDomain;\n      }\n      /**\n       * @param {string} url\n       * @param {{numPathParts: number, preserveQuery: boolean, preserveHost: boolean}=} options\n       * @return {string}\n       */\n      static getURLDisplayName(url, options) {\n        return Util.getURLDisplayName(new URL(url), options);\n      }\n      /**\n       * Limits data URIs to 100 characters, returns all other strings untouched.\n       * @param {string} url\n       * @return {string}\n       */\n      static elideDataURI(url) {\n        try {\n          const parsed = new URL(url);\n          return parsed.protocol === \"data:\" ? Util.truncate(url, 100) : url;\n        } catch (e) {\n          return url;\n        }\n      }\n      /**\n       * Determine if url1 equals url2, ignoring URL fragments.\n       * @param {string} url1\n       * @param {string} url2\n       * @return {boolean}\n       */\n      static equalWithExcludedFragments(url1, url2) {\n        [url1, url2] = [url1, url2].map(rewriteChromeInternalUrl);\n        try {\n          const urla = new URL(url1);\n          urla.hash = \"\";\n          const urlb = new URL(url2);\n          urlb.hash = \"\";\n          return urla.href === urlb.href;\n        } catch (e) {\n          return false;\n        }\n      }\n      /**\n       * Determine if the url has a protocol that we're able to test\n       * @param {string} url\n       * @return {boolean}\n       */\n      static isProtocolAllowed(url) {\n        try {\n          const parsed = new URL(url);\n          return allowedProtocols.includes(parsed.protocol);\n        } catch (e) {\n          return false;\n        }\n      }\n      /**\n       * Is the host localhost-enough to satisfy the \"secure context\" definition\n       * https://github.com/GoogleChrome/lighthouse/pull/11766#discussion_r582340683\n       * @param {string} hostname Either a `new URL(url).hostname` or a `networkRequest.parsedUrl.host`\n       * @return {boolean}\n       */\n      static isLikeLocalhost(hostname) {\n        return SECURE_LOCALHOST_DOMAINS2.includes(hostname) || hostname.endsWith(\".localhost\");\n      }\n      /**\n       * @param {NetworkRequest['parsedURL']['scheme']} scheme\n       * @return {boolean}\n       */\n      static isSecureScheme(scheme) {\n        return SECURE_SCHEMES.includes(scheme);\n      }\n      /**\n       * Use `NetworkRequest.isNonNetworkRequest(req)` if working with a request.\n       * Note: the `protocol` field from CDP can be 'h2', 'http', (not 'https'!) or it'll be url's scheme.\n       *   https://source.chromium.org/chromium/chromium/src/+/main:content/browser/devtools/protocol/network_handler.cc;l=598-611;drc=56d4a9a9deb30be73adcee8737c73bcb2a5ab64f\n       * However, a `new URL(href).protocol` has a colon suffix.\n       *   https://url.spec.whatwg.org/#dom-url-protocol\n       * A URL's `scheme` is specced as the `protocol` sans-colon, but isn't exposed on a URL object.\n       * This method can take all 3 of these string types as a parameter.\n       * @param {NetworkRequest['protocol'] | URL['protocol']} protocol Either a networkRequest's `protocol` per CDP or a `new URL(href).protocol`\n       * @return {boolean}\n       */\n      static isNonNetworkProtocol(protocol) {\n        const urlScheme = protocol.includes(\":\") ? protocol.slice(0, protocol.indexOf(\":\")) : protocol;\n        return NON_NETWORK_SCHEMES3.includes(urlScheme);\n      }\n      /**\n       * @param {string} src\n       * @return {string|undefined}\n       */\n      static guessMimeType(src) {\n        let url;\n        try {\n          url = new URL(src);\n        } catch {\n          return void 0;\n        }\n        if (url.protocol === \"data:\") {\n          const match2 = url.pathname.match(/^(image\\/(png|jpeg|svg\\+xml|webp|gif|avif))[;,]/);\n          if (!match2) return void 0;\n          return match2[1];\n        }\n        const match = url.pathname.toLowerCase().match(/\\.(png|jpeg|jpg|svg|webp|gif|avif)$/);\n        if (!match) return void 0;\n        const ext = match[1];\n        if (ext === \"svg\") return \"image/svg+xml\";\n        if (ext === \"jpg\") return \"image/jpeg\";\n        return `image/${ext}`;\n      }\n      /**\n       * @param {string|undefined} url\n       * @return {string}\n       */\n      static normalizeUrl(url) {\n        if (url && this.isValid(url) && this.isProtocolAllowed(url)) {\n          return new URL(url).href;\n        } else {\n          throw new LighthouseError(LighthouseError.errors.INVALID_URL);\n        }\n      }\n    };\n    UrlUtils2.INVALID_URL_DEBUG_STRING = \"Lighthouse was unable to determine the URL of some script executions. It's possible a Chrome extension or other eval'd code is the source.\";\n    url_utils_default = UrlUtils2;\n  }\n});\n\n// core/lib/network-request.js\nvar HEADER_TCP, HEADER_SSL, HEADER_REQ, HEADER_RES, HEADER_TOTAL, HEADER_FETCHED_SIZE, HEADER_PROTOCOL_IS_H2, RESOURCE_TYPES, NetworkRequest;\nvar init_network_request = __esm({\n  \"core/lib/network-request.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_lh();\n    init_lantern2();\n    init_url_utils();\n    /**\n     * @license\n     * Copyright 2018 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    HEADER_TCP = \"X-TCPMs\";\n    HEADER_SSL = \"X-SSLMs\";\n    HEADER_REQ = \"X-RequestMs\";\n    HEADER_RES = \"X-ResponseMs\";\n    HEADER_TOTAL = \"X-TotalMs\";\n    HEADER_FETCHED_SIZE = \"X-TotalFetchedSize\";\n    HEADER_PROTOCOL_IS_H2 = \"X-ProtocolIsH2\";\n    RESOURCE_TYPES = {\n      XHR: \"XHR\",\n      Fetch: \"Fetch\",\n      EventSource: \"EventSource\",\n      Script: \"Script\",\n      Stylesheet: \"Stylesheet\",\n      Image: \"Image\",\n      Media: \"Media\",\n      Font: \"Font\",\n      Document: \"Document\",\n      TextTrack: \"TextTrack\",\n      WebSocket: \"WebSocket\",\n      Other: \"Other\",\n      Manifest: \"Manifest\",\n      SignedExchange: \"SignedExchange\",\n      Ping: \"Ping\",\n      Preflight: \"Preflight\",\n      CSPViolationReport: \"CSPViolationReport\",\n      Prefetch: \"Prefetch\",\n      FedCM: \"FedCM\"\n    };\n    NetworkRequest = class _NetworkRequest {\n      static {\n        __name(this, \"NetworkRequest\");\n      }\n      constructor() {\n        this.requestId = \"\";\n        this.connectionId = 0;\n        this.connectionReused = false;\n        this.url = \"\";\n        this.protocol = \"\";\n        this.isSecure = false;\n        this.isValid = false;\n        this.parsedURL = /** @type {ParsedURL} */\n        { scheme: \"\" };\n        this.documentURL = \"\";\n        this.rendererStartTime = -1;\n        this.networkRequestTime = -1;\n        this.responseHeadersEndTime = -1;\n        this.networkEndTime = -1;\n        this.transferSize = 0;\n        this.responseHeadersTransferSize = 0;\n        this.resourceSize = 0;\n        this.fromDiskCache = false;\n        this.fromMemoryCache = false;\n        this.fromPrefetchCache = false;\n        this.lrStatistics = void 0;\n        this.finished = false;\n        this.requestMethod = \"\";\n        this.statusCode = -1;\n        this.redirectSource = void 0;\n        this.redirectDestination = void 0;\n        this.redirects = void 0;\n        this.failed = false;\n        this.localizedFailDescription = \"\";\n        this.initiator = { type: \"other\" };\n        this.timing = void 0;\n        this.resourceType = void 0;\n        this.mimeType = \"\";\n        this.priority = \"Low\";\n        this.initiatorRequest = void 0;\n        this.responseHeaders = [];\n        this.responseHeadersText = \"\";\n        this.fetchedViaServiceWorker = false;\n        this.frameId = \"\";\n        this.sessionId = void 0;\n        this.sessionTargetType = void 0;\n        this.fromWorker = false;\n        this.isLinkPreload = false;\n      }\n      /**\n       * @return {boolean}\n       */\n      hasErrorStatusCode() {\n        return this.statusCode >= 400;\n      }\n      /**\n       * @param {NetworkRequest} initiatorRequest\n       */\n      setInitiatorRequest(initiatorRequest) {\n        this.initiatorRequest = initiatorRequest;\n      }\n      /**\n       * @param {LH.Crdp.Network.RequestWillBeSentEvent} data\n       */\n      onRequestWillBeSent(data31) {\n        this.requestId = data31.requestId;\n        let url;\n        try {\n          url = new URL(data31.request.url);\n        } catch (e) {\n          return;\n        }\n        this.url = data31.request.url;\n        this.documentURL = data31.documentURL;\n        this.parsedURL = {\n          scheme: url.protocol.split(\":\")[0],\n          // Intentional, DevTools uses different terminology\n          host: url.hostname,\n          securityOrigin: url.origin\n        };\n        this.isSecure = url_utils_default.isSecureScheme(this.parsedURL.scheme);\n        this.rendererStartTime = data31.timestamp * 1e3;\n        this.networkRequestTime = this.rendererStartTime;\n        this.responseHeadersEndTime = this.rendererStartTime;\n        this.requestMethod = data31.request.method;\n        this.initiator = data31.initiator;\n        this.resourceType = data31.type && RESOURCE_TYPES[data31.type];\n        this.priority = data31.request.initialPriority;\n        this.frameId = data31.frameId;\n        this.isLinkPreload = data31.initiator.type === \"preload\" || !!data31.request.isLinkPreload;\n        this.isValid = true;\n      }\n      onRequestServedFromCache() {\n        this.fromMemoryCache = true;\n      }\n      /**\n       * @param {LH.Crdp.Network.ResponseReceivedEvent} data\n       */\n      onResponseReceived(data31) {\n        this._onResponse(data31.response, data31.timestamp, data31.type);\n        this._updateProtocolForLightrider();\n        this.frameId = data31.frameId;\n      }\n      /**\n       * @param {LH.Crdp.Network.ResponseReceivedExtraInfoEvent} data\n       */\n      onResponseReceivedExtraInfo(data31) {\n        this.responseHeadersText = data31.headersText || \"\";\n      }\n      /**\n       * @param {LH.Crdp.Network.DataReceivedEvent} data\n       */\n      onDataReceived(data31) {\n        this.resourceSize += data31.dataLength;\n        if (data31.encodedDataLength !== -1) {\n          this.transferSize += data31.encodedDataLength;\n        }\n      }\n      /**\n       * @param {LH.Crdp.Network.LoadingFinishedEvent} data\n       */\n      onLoadingFinished(data31) {\n        if (this.finished) return;\n        this.finished = true;\n        this.networkEndTime = data31.timestamp * 1e3;\n        if (data31.encodedDataLength >= 0) {\n          this.transferSize = data31.encodedDataLength;\n        }\n        this._updateResponseHeadersEndTimeIfNecessary();\n        this._updateTransferSizeForLightrider();\n        this._updateTimingsForLightrider();\n      }\n      /**\n       * @param {LH.Crdp.Network.LoadingFailedEvent} data\n       */\n      onLoadingFailed(data31) {\n        if (this.finished) return;\n        this.finished = true;\n        this.networkEndTime = data31.timestamp * 1e3;\n        this.failed = true;\n        this.resourceType = data31.type && RESOURCE_TYPES[data31.type];\n        this.localizedFailDescription = data31.errorText;\n        this._updateResponseHeadersEndTimeIfNecessary();\n        this._updateTransferSizeForLightrider();\n        this._updateTimingsForLightrider();\n      }\n      /**\n       * @param {LH.Crdp.Network.ResourceChangedPriorityEvent} data\n       */\n      onResourceChangedPriority(data31) {\n        this.priority = data31.newPriority;\n      }\n      /**\n       * @param {LH.Crdp.Network.RequestWillBeSentEvent} data\n       */\n      onRedirectResponse(data31) {\n        if (!data31.redirectResponse) throw new Error(\"Missing redirectResponse data\");\n        this._onResponse(data31.redirectResponse, data31.timestamp, data31.type);\n        this.resourceType = void 0;\n        this.finished = true;\n        this.networkEndTime = data31.timestamp * 1e3;\n        this._updateResponseHeadersEndTimeIfNecessary();\n      }\n      /**\n       * @param {string|undefined} sessionId\n       */\n      setSession(sessionId) {\n        this.sessionId = sessionId;\n      }\n      get isOutOfProcessIframe() {\n        return this.sessionTargetType === \"iframe\";\n      }\n      /**\n       * @param {LH.Crdp.Network.Response} response\n       * @param {number} timestamp in seconds\n       * @param {LH.Crdp.Network.ResponseReceivedEvent['type']=} resourceType\n       */\n      _onResponse(response, timestamp, resourceType) {\n        this.url = response.url;\n        this.connectionId = response.connectionId;\n        this.connectionReused = response.connectionReused;\n        if (response.protocol) this.protocol = response.protocol;\n        this.responseTimestamp = timestamp * 1e3;\n        this.transferSize = response.encodedDataLength;\n        this.responseHeadersTransferSize = response.encodedDataLength;\n        if (typeof response.fromDiskCache === \"boolean\") this.fromDiskCache = response.fromDiskCache;\n        if (typeof response.fromPrefetchCache === \"boolean\") {\n          this.fromPrefetchCache = response.fromPrefetchCache;\n        }\n        this.statusCode = response.status;\n        this.timing = response.timing;\n        if (resourceType) this.resourceType = RESOURCE_TYPES[resourceType];\n        this.mimeType = response.mimeType;\n        this.responseHeaders = _NetworkRequest._headersDictToHeadersArray(response.headers);\n        this.fetchedViaServiceWorker = !!response.fromServiceWorker;\n        if (this.fromMemoryCache) this.timing = void 0;\n        if (this.timing) this._recomputeTimesWithResourceTiming(this.timing);\n      }\n      /**\n       * Resolve differences between conflicting timing signals. Based on the property setters in DevTools.\n       * @see https://github.com/ChromeDevTools/devtools-frontend/blob/56a99365197b85c24b732ac92b0ac70feed80179/front_end/sdk/NetworkRequest.js#L485-L502\n       * @param {LH.Crdp.Network.ResourceTiming} timing\n       */\n      _recomputeTimesWithResourceTiming(timing) {\n        if (timing.requestTime === -1 || timing.receiveHeadersEnd === -1) return;\n        this.networkRequestTime = timing.requestTime * 1e3;\n        const headersReceivedTime = this.networkRequestTime + timing.receiveHeadersEnd;\n        this.responseHeadersEndTime = headersReceivedTime;\n        if (this.responseTimestamp !== void 0) {\n          this.responseHeadersEndTime = Math.min(this.responseHeadersEndTime, this.responseTimestamp);\n        }\n        this.responseHeadersEndTime = Math.max(this.responseHeadersEndTime, this.networkRequestTime);\n        this.networkEndTime = Math.max(this.networkEndTime, this.responseHeadersEndTime);\n      }\n      /**\n       * Update responseHeadersEndTime to the networkEndTime if networkEndTime is earlier.\n       * A response can't be received after the entire request finished.\n       */\n      _updateResponseHeadersEndTimeIfNecessary() {\n        this.responseHeadersEndTime = Math.min(this.networkEndTime, this.responseHeadersEndTime);\n      }\n      /**\n       * LR loses transfer size information, but passes it in the 'X-TotalFetchedSize' header.\n       * 'X-TotalFetchedSize' is the canonical transfer size in LR. Nothing should supersede it.\n       *\n       * The total length of the encoded data is spread out among multiple events. The sum of the\n       * values in onResponseReceived and all the onDataReceived events typically equals the value\n       * seen on the onLoadingFinished event. In <1% of cases we see the values differ. As we process\n       * onResponseReceived and onDataReceived we accumulate the total encodedDataLength. When we\n       * process onLoadingFinished, we override the accumulated total. We do this so that if the\n       * request is aborted or fails, we still get a value via the accumulation.\n       *\n       * In Lightrider, due to instrumentation limitations, our values for encodedDataLength are bogus\n       * and not valid. However the resource's true encodedDataLength/transferSize is shared via a\n       * special response header, X-TotalFetchedSize. In this situation, we read this value from\n       * responseReceived, use it for the transferSize and ignore the encodedDataLength values in\n       * both dataReceived and loadingFinished.\n       */\n      _updateTransferSizeForLightrider() {\n        if (!global.isLightrider) return;\n        const totalFetchedSize = this.responseHeaders.find((item) => item.name === HEADER_FETCHED_SIZE);\n        if (!totalFetchedSize) return;\n        const floatValue = parseFloat(totalFetchedSize.value);\n        if (isNaN(floatValue)) return;\n        this.transferSize = floatValue;\n      }\n      /**\n       * LR loses protocol information.\n       */\n      _updateProtocolForLightrider() {\n        if (!global.isLightrider) return;\n        if (this.responseHeaders.some((item) => item.name === HEADER_PROTOCOL_IS_H2)) {\n          this.protocol = \"h2\";\n        }\n      }\n      /**\n       * LR gets additional, accurate timing information from its underlying fetch infrastructure.  This\n       * is passed in via X-Headers similar to 'X-TotalFetchedSize'.\n       */\n      _updateTimingsForLightrider() {\n        if (!global.isLightrider) return;\n        const totalHeader = this.responseHeaders.find((item) => item.name === HEADER_TOTAL);\n        if (!totalHeader) return;\n        let totalMs = parseInt(totalHeader.value);\n        const TCPMsHeader = this.responseHeaders.find((item) => item.name === HEADER_TCP);\n        const SSLMsHeader = this.responseHeaders.find((item) => item.name === HEADER_SSL);\n        const requestMsHeader = this.responseHeaders.find((item) => item.name === HEADER_REQ);\n        const responseMsHeader = this.responseHeaders.find((item) => item.name === HEADER_RES);\n        const TCPMs = TCPMsHeader ? Math.max(0, parseInt(TCPMsHeader.value)) : 0;\n        const SSLMs = SSLMsHeader ? Math.max(0, parseInt(SSLMsHeader.value)) : 0;\n        const requestMs = requestMsHeader ? Math.max(0, parseInt(requestMsHeader.value)) : 0;\n        const responseMs = responseMsHeader ? Math.max(0, parseInt(responseMsHeader.value)) : 0;\n        if (Number.isNaN(TCPMs + requestMs + responseMs + totalMs)) {\n          return;\n        }\n        if (TCPMs + requestMs + responseMs !== totalMs) {\n          const delta = Math.abs(TCPMs + requestMs + responseMs - totalMs);\n          if (delta >= 25) return;\n          totalMs = TCPMs + requestMs + responseMs;\n        }\n        if (SSLMs > TCPMs) {\n          return;\n        }\n        this.lrStatistics = {\n          endTimeDeltaMs: this.networkEndTime - (this.networkRequestTime + totalMs),\n          TCPMs,\n          requestMs,\n          responseMs\n        };\n        this.serverResponseTime = responseMs;\n      }\n      /**\n       * Convert the requestId to backend-version by removing the `:redirect` portion\n       *\n       * @param {string} requestId\n       * @return {string}\n       */\n      static getRequestIdForBackend(requestId) {\n        return requestId.replace(/(:redirect)+$/, \"\");\n      }\n      /**\n       * Based on DevTools NetworkManager.\n       * @see https://github.com/ChromeDevTools/devtools-frontend/blob/3415ee28e86a3f4bcc2e15b652d22069938df3a6/front_end/sdk/NetworkManager.js#L285-L297\n       * @param {LH.Crdp.Network.Headers} headersDict\n       * @return {Array<HeaderEntry>}\n       */\n      static _headersDictToHeadersArray(headersDict) {\n        const result = [];\n        for (const name of Object.keys(headersDict)) {\n          const values = headersDict[name].split(\"\\n\");\n          for (let i = 0; i < values.length; ++i) {\n            result.push({ name, value: values[i] });\n          }\n        }\n        return result;\n      }\n      static get TYPES() {\n        return RESOURCE_TYPES;\n      }\n      /**\n       * @param {NetworkRequest} record\n       * @return {Lantern.Types.NetworkRequest<NetworkRequest>}\n       */\n      static asLanternNetworkRequest(record) {\n        let timing = record.timing;\n        let serverResponseTime;\n        if (global.isLightrider && record.lrStatistics) {\n          if (record.protocol.startsWith(\"h3\")) {\n            timing = {\n              connectStart: 0,\n              connectEnd: record.lrStatistics.TCPMs\n            };\n          } else {\n            timing = {\n              connectStart: 0,\n              sslStart: record.lrStatistics.TCPMs / 2,\n              connectEnd: record.lrStatistics.TCPMs,\n              sslEnd: record.lrStatistics.TCPMs\n            };\n            serverResponseTime = record.lrStatistics.requestMs;\n          }\n        }\n        record.fromWorker = record.sessionTargetType === \"worker\";\n        return {\n          rawRequest: record,\n          ...record,\n          timing,\n          serverResponseTime\n        };\n      }\n      /**\n       * @param {Pick<NetworkRequest, 'protocol'|'parsedURL'>} record\n       * @return {boolean}\n       */\n      static isNonNetworkRequest(record) {\n        return url_utils_default.isNonNetworkProtocol(record.protocol) || // But `protocol` can fail to be populated if the request fails, so fallback to scheme.\n        url_utils_default.isNonNetworkProtocol(record.parsedURL.scheme);\n      }\n      /**\n       * Technically there's not alignment on URLs that create \"secure connections\" vs \"secure contexts\"\n       * https://github.com/GoogleChrome/lighthouse/pull/11766#discussion_r582340683\n       * But for our purposes, we don't need to worry too much.\n       * @param {NetworkRequest} record\n       * @return {boolean}\n       */\n      static isSecureRequest(record) {\n        return url_utils_default.isSecureScheme(record.parsedURL.scheme) || url_utils_default.isSecureScheme(record.protocol) || url_utils_default.isLikeLocalhost(record.parsedURL.host) || _NetworkRequest.isHstsRequest(record);\n      }\n      /**\n       * Returns whether the network request was an HSTS redirect request.\n       * @param {NetworkRequest} record\n       * @return {boolean}\n       */\n      static isHstsRequest(record) {\n        const destination = record.redirectDestination;\n        if (!destination) return false;\n        const reasonHeader = record.responseHeaders.find((header) => header.name === \"Non-Authoritative-Reason\");\n        const reason = reasonHeader?.value;\n        return reason === \"HSTS\" && _NetworkRequest.isSecureRequest(destination);\n      }\n      /**\n       * Returns whether the network request was sent encoded.\n       * @param {NetworkRequest} record\n       * @return {boolean}\n       */\n      static isContentEncoded(record) {\n        const patterns = global.isLightrider ? [\n          /^x-original-content-encoding$/i\n        ] : [\n          /^content-encoding$/i,\n          /^x-content-encoding-over-network$/i\n        ];\n        const compressionTypes = [\"gzip\", \"br\", \"deflate\", \"zstd\"];\n        return record.responseHeaders.some(\n          (header) => patterns.some((p) => header.name.match(p)) && compressionTypes.includes(header.value)\n        );\n      }\n      /**\n       * Resource size is almost always the right one to be using because of the below:\n       *     `transferSize = resourceSize + headers.length`.\n       * HOWEVER, there are some cases where an image is compressed again over the network and transfer size\n       * is smaller (see https://github.com/GoogleChrome/lighthouse/pull/4968).\n       * Use the min of the two numbers to be safe.\n       * `tranferSize` of cached records is 0\n       * @param {NetworkRequest} networkRecord\n       * @return {number}\n       */\n      static getResourceSizeOnNetwork(networkRecord) {\n        return Math.min(networkRecord.resourceSize || 0, networkRecord.transferSize || Infinity);\n      }\n    };\n    NetworkRequest.HEADER_TCP = HEADER_TCP;\n    NetworkRequest.HEADER_SSL = HEADER_SSL;\n    NetworkRequest.HEADER_REQ = HEADER_REQ;\n    NetworkRequest.HEADER_RES = HEADER_RES;\n    NetworkRequest.HEADER_TOTAL = HEADER_TOTAL;\n    NetworkRequest.HEADER_FETCHED_SIZE = HEADER_FETCHED_SIZE;\n    NetworkRequest.HEADER_PROTOCOL_IS_H2 = HEADER_PROTOCOL_IS_H2;\n  }\n});\n\n// core/lib/network-recorder.js\nimport { EventEmitter as EventEmitter2 } from \"events\";\nvar RequestEventEmitter, NetworkRecorder;\nvar init_network_recorder = __esm({\n  \"core/lib/network-recorder.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_lighthouse_logger();\n    init_lh();\n    init_lantern2();\n    init_network_request();\n    /**\n     * @license\n     * Copyright 2016 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    RequestEventEmitter = /** @type {RequestEmitter} */\n    EventEmitter2;\n    NetworkRecorder = class _NetworkRecorder extends RequestEventEmitter {\n      static {\n        __name(this, \"NetworkRecorder\");\n      }\n      /**\n       * Creates an instance of NetworkRecorder.\n       */\n      constructor() {\n        super();\n        this._records = [];\n        this._recordsById = /* @__PURE__ */ new Map();\n      }\n      /**\n       * Returns the array of raw network request data without finalizing the initiator and\n       * redirect chain.\n       * @return {Array<NetworkRequest>}\n       */\n      getRawRecords() {\n        return Array.from(this._records);\n      }\n      /**\n       * Listener for the DevTools SDK NetworkManager's RequestStarted event, which includes both\n       * web socket and normal request creation.\n       * @param {NetworkRequest} request\n       * @private\n       */\n      onRequestStarted(request) {\n        this._records.push(request);\n        this._recordsById.set(request.requestId, request);\n        this.emit(\"requeststarted\", request);\n      }\n      /**\n       * Listener for the DevTools SDK NetworkManager's RequestFinished event, which includes\n       * request finish, failure, and redirect, as well as the closing of web sockets.\n       * @param {NetworkRequest} request\n       * @private\n       */\n      onRequestFinished(request) {\n        this.emit(\"requestfinished\", request);\n      }\n      // The below methods proxy network data into the NetworkRequest object which mimics the\n      // DevTools SDK network layer.\n      /**\n       * @param {{params: LH.Crdp.Network.RequestWillBeSentEvent, targetType: LH.Protocol.TargetType, sessionId?: string}} event\n       */\n      onRequestWillBeSent(event) {\n        const data31 = event.params;\n        const originalRequest = this._findRealRequestAndSetSession(\n          data31.requestId,\n          event.targetType,\n          event.sessionId\n        );\n        if (!originalRequest) {\n          const request = new NetworkRequest();\n          request.onRequestWillBeSent(data31);\n          request.sessionId = event.sessionId;\n          request.sessionTargetType = event.targetType;\n          this.onRequestStarted(request);\n          lighthouse_logger_default.verbose(\"network\", `request will be sent to ${request.url}`);\n          return;\n        }\n        if (!data31.redirectResponse) {\n          return;\n        }\n        const modifiedData = {\n          ...data31,\n          // Copy over the initiator as well to match DevTools behavior\n          initiator: originalRequest.initiator,\n          requestId: `${originalRequest.requestId}:redirect`\n        };\n        const redirectedRequest = new NetworkRequest();\n        redirectedRequest.onRequestWillBeSent(modifiedData);\n        originalRequest.onRedirectResponse(data31);\n        lighthouse_logger_default.verbose(\"network\", `${originalRequest.url} redirected to ${redirectedRequest.url}`);\n        originalRequest.redirectDestination = redirectedRequest;\n        redirectedRequest.redirectSource = originalRequest;\n        this.onRequestStarted(redirectedRequest);\n        this.onRequestFinished(originalRequest);\n      }\n      /**\n       * @param {{params: LH.Crdp.Network.RequestServedFromCacheEvent, targetType: LH.Protocol.TargetType, sessionId?: string}} event\n       */\n      onRequestServedFromCache(event) {\n        const data31 = event.params;\n        const request = this._findRealRequestAndSetSession(\n          data31.requestId,\n          event.targetType,\n          event.sessionId\n        );\n        if (!request) return;\n        lighthouse_logger_default.verbose(\"network\", `${request.url} served from cache`);\n        request.onRequestServedFromCache();\n      }\n      /**\n       * @param {{params: LH.Crdp.Network.ResponseReceivedEvent, targetType: LH.Protocol.TargetType, sessionId?: string}} event\n       */\n      onResponseReceived(event) {\n        const data31 = event.params;\n        const request = this._findRealRequestAndSetSession(\n          data31.requestId,\n          event.targetType,\n          event.sessionId\n        );\n        if (!request) return;\n        lighthouse_logger_default.verbose(\"network\", `${request.url} response received`);\n        request.onResponseReceived(data31);\n      }\n      /**\n       * @param {{params: LH.Crdp.Network.ResponseReceivedExtraInfoEvent, targetType: LH.Protocol.TargetType, sessionId?: string}} event\n       */\n      onResponseReceivedExtraInfo(event) {\n        const data31 = event.params;\n        const request = this._findRealRequestAndSetSession(\n          data31.requestId,\n          event.targetType,\n          event.sessionId\n        );\n        if (!request) return;\n        lighthouse_logger_default.verbose(\"network\", `${request.url} response received extra info`);\n        request.onResponseReceivedExtraInfo(data31);\n      }\n      /**\n       * @param {{params: LH.Crdp.Network.DataReceivedEvent, targetType: LH.Protocol.TargetType, sessionId?: string}} event\n       */\n      onDataReceived(event) {\n        const data31 = event.params;\n        const request = this._findRealRequestAndSetSession(\n          data31.requestId,\n          event.targetType,\n          event.sessionId\n        );\n        if (!request) return;\n        lighthouse_logger_default.verbose(\"network\", `${request.url} data received`);\n        request.onDataReceived(data31);\n      }\n      /**\n       * @param {{params: LH.Crdp.Network.LoadingFinishedEvent, targetType: LH.Protocol.TargetType, sessionId?: string}} event\n       */\n      onLoadingFinished(event) {\n        const data31 = event.params;\n        const request = this._findRealRequestAndSetSession(\n          data31.requestId,\n          event.targetType,\n          event.sessionId\n        );\n        if (!request) return;\n        lighthouse_logger_default.verbose(\"network\", `${request.url} loading finished`);\n        request.onLoadingFinished(data31);\n        this.onRequestFinished(request);\n      }\n      /**\n       * @param {{params: LH.Crdp.Network.LoadingFailedEvent, targetType: LH.Protocol.TargetType, sessionId?: string}} event\n       */\n      onLoadingFailed(event) {\n        const data31 = event.params;\n        const request = this._findRealRequestAndSetSession(\n          data31.requestId,\n          event.targetType,\n          event.sessionId\n        );\n        if (!request) return;\n        lighthouse_logger_default.verbose(\"network\", `${request.url} loading failed`);\n        request.onLoadingFailed(data31);\n        this.onRequestFinished(request);\n      }\n      /**\n       * @param {{params: LH.Crdp.Network.ResourceChangedPriorityEvent, targetType: LH.Protocol.TargetType, sessionId?: string}} event\n       */\n      onResourceChangedPriority(event) {\n        const data31 = event.params;\n        const request = this._findRealRequestAndSetSession(\n          data31.requestId,\n          event.targetType,\n          event.sessionId\n        );\n        if (!request) return;\n        request.onResourceChangedPriority(data31);\n      }\n      /**\n       * Routes network events to their handlers, so we can construct networkRecords\n       * @param {LH.Protocol.RawEventMessage} event\n       */\n      dispatch(event) {\n        switch (event.method) {\n          case \"Network.requestWillBeSent\":\n            return this.onRequestWillBeSent(event);\n          case \"Network.requestServedFromCache\":\n            return this.onRequestServedFromCache(event);\n          case \"Network.responseReceived\":\n            return this.onResponseReceived(event);\n          case \"Network.responseReceivedExtraInfo\":\n            return this.onResponseReceivedExtraInfo(event);\n          case \"Network.dataReceived\":\n            return this.onDataReceived(event);\n          case \"Network.loadingFinished\":\n            return this.onLoadingFinished(event);\n          case \"Network.loadingFailed\":\n            return this.onLoadingFailed(event);\n          case \"Network.resourceChangedPriority\":\n            return this.onResourceChangedPriority(event);\n          default:\n            return;\n        }\n      }\n      /**\n       * Redirected requests all have identical requestIds over the protocol. Once a request has been\n       * redirected all future messages referrencing that requestId are about the new destination, not\n       * the original. This method is a helper for finding the real request object to which the current\n       * message is referring.\n       *\n       * @param {string} requestId\n       * @param {LH.Protocol.TargetType} targetType\n       * @param {string|undefined} sessionId\n       * @return {NetworkRequest|undefined}\n       */\n      _findRealRequestAndSetSession(requestId, targetType, sessionId) {\n        let request = this._recordsById.get(requestId);\n        if (!request || !request.isValid) return void 0;\n        while (request.redirectDestination) {\n          request = request.redirectDestination;\n        }\n        request.setSession(sessionId);\n        request.sessionTargetType = targetType;\n        return request;\n      }\n      /**\n       * @param {NetworkRequest} record The record to find the initiator of\n       * @param {Map<string, NetworkRequest[]>} recordsByURL\n       * @return {NetworkRequest|null}\n       * @private\n       */\n      static _chooseInitiatorRequest(record, recordsByURL) {\n        if (record.redirectSource) {\n          return record.redirectSource;\n        }\n        const initiatorURL = graph_exports.PageDependencyGraph.getNetworkInitiators(record)[0];\n        let candidates = recordsByURL.get(initiatorURL) || [];\n        candidates = candidates.filter((c) => {\n          return c.responseHeadersEndTime <= record.rendererStartTime && c.finished && !c.failed;\n        });\n        if (candidates.length > 1) {\n          const nonPrefetchCandidates = candidates.filter(\n            (cand) => cand.resourceType !== NetworkRequest.TYPES.Other\n          );\n          if (nonPrefetchCandidates.length) {\n            candidates = nonPrefetchCandidates;\n          }\n        }\n        if (candidates.length > 1) {\n          const sameFrameCandidates = candidates.filter((cand) => cand.frameId === record.frameId);\n          if (sameFrameCandidates.length) {\n            candidates = sameFrameCandidates;\n          }\n        }\n        if (candidates.length > 1 && record.initiator.type === \"parser\") {\n          const documentCandidates = candidates.filter((cand) => cand.resourceType === NetworkRequest.TYPES.Document);\n          if (documentCandidates.length) {\n            candidates = documentCandidates;\n          }\n        }\n        if (candidates.length > 1) {\n          const linkPreloadCandidates = candidates.filter((c) => c.isLinkPreload);\n          if (linkPreloadCandidates.length) {\n            const nonPreloadCandidates = candidates.filter((c) => !c.isLinkPreload);\n            const allPreloaded = nonPreloadCandidates.every((c) => c.fromDiskCache || c.fromMemoryCache);\n            if (nonPreloadCandidates.length && allPreloaded) {\n              candidates = linkPreloadCandidates;\n            }\n          }\n        }\n        return candidates.length === 1 ? candidates[0] : null;\n      }\n      /**\n       * Construct network records from a log of devtools protocol messages.\n       * @param {LH.DevtoolsLog} devtoolsLog\n       * @return {Array<LH.Artifacts.NetworkRequest>}\n       */\n      static recordsFromLogs(devtoolsLog) {\n        const networkRecorder = new _NetworkRecorder();\n        devtoolsLog.forEach((message) => networkRecorder.dispatch(message));\n        const records = networkRecorder.getRawRecords().filter((record) => record.isValid);\n        const recordsByURL = /* @__PURE__ */ new Map();\n        for (const record of records) {\n          const records2 = recordsByURL.get(record.url) || [];\n          records2.push(record);\n          recordsByURL.set(record.url, records2);\n        }\n        for (const record of records) {\n          const initiatorRequest = _NetworkRecorder._chooseInitiatorRequest(record, recordsByURL);\n          if (initiatorRequest) {\n            record.setInitiatorRequest(initiatorRequest);\n          }\n          let finalRecord = record;\n          while (finalRecord.redirectDestination) finalRecord = finalRecord.redirectDestination;\n          if (finalRecord === record || finalRecord.redirects) continue;\n          const redirects = [];\n          for (let redirect = finalRecord.redirectSource; redirect; redirect = redirect.redirectSource) {\n            redirects.unshift(redirect);\n          }\n          finalRecord.redirects = redirects;\n        }\n        return records;\n      }\n    };\n  }\n});\n\n// core/computed/network-records.js\nvar NetworkRecords, NetworkRecordsComputed;\nvar init_network_records = __esm({\n  \"core/computed/network-records.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_lh();\n    init_computed_artifact();\n    init_network_recorder();\n    /**\n     * @license\n     * Copyright 2017 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    NetworkRecords = class {\n      static {\n        __name(this, \"NetworkRecords\");\n      }\n      /**\n       * @param {LH.DevtoolsLog} devtoolsLog\n       * @return {Promise<Array<LH.Artifacts.NetworkRequest>>} networkRecords\n       */\n      static async compute_(devtoolsLog) {\n        return NetworkRecorder.recordsFromLogs(devtoolsLog);\n      }\n    };\n    NetworkRecordsComputed = makeComputedArtifact(NetworkRecords, null);\n  }\n});\n\n// core/lib/axe.js\nvar require2, axeSource;\nvar init_axe = __esm({\n  \"core/lib/axe.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_module();\n    /**\n     * @license\n     * Copyright 2020 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    require2 = /* @__PURE__ */ createRequire({ url: \"core/lib/axe.js\" }.url);\n    axeSource = `/*! axe v4.11.0\n * Copyright (c) 2015 - 2025 Deque Systems, Inc.\n *\n * Your use of this Source Code Form is subject to the terms of the Mozilla Public\n * License, v. 2.0. If a copy of the MPL was not distributed with this\n * file, You can obtain one at http://mozilla.org/MPL/2.0/.\n *\n * This entire copyright notice must appear in every copy of this file you\n * distribute or in any file that contains substantial portions of this source\n * code.\n */\n!function e(t){var n=t,r=t.document;function a(e){return(a=\"function\"==typeof Symbol&&\"symbol\"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&\"function\"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?\"symbol\":typeof e})(e)}var o=o||{},i=(o.version=\"4.11.0\",\"function\"==typeof define&&define.amd&&define(\"axe-core\",[],(function(){return o})),\"object\"===(\"undefined\"==typeof module?\"undefined\":a(module))&&module.exports&&\"function\"==typeof e.toString&&(o.source=\"(\"+e.toString()+')(typeof window === \"object\" ? window : this);',module.exports=o),\"function\"==typeof t.getComputedStyle&&(t.axe=o),[\"precision\",\"format\",\"inGamut\"]),l=[\"space\"],u=[\"algorithm\"],s=[\"method\"],c=[\"maxDeltaE\",\"deltaEMethod\",\"steps\",\"maxSteps\"],d=[\"variant\"],p=[\"matches\"],f=[\"chromium\"],m=[\"noImplicit\"],h=[\"noPresentational\"],g=[\"node\"],v=[\"relatedNodes\"],b=[\"node\"],y=[\"node\"],D=[\"environmentData\"],w=[\"environmentData\"],x=[\"environmentData\"],E=[\"environmentData\"],A=[\"environmentD\\\nata\"];function F(e,t,n){return(t=Y(t))in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function C(e,t,n){var r;return N()?Reflect.construct.apply(null,arguments):((r=[null]).push.apply(r,t),t=new(e.bind.apply(e,r)),n&&_(t,n.prototype),t)}function k(e,t){if(null==e)return{};var n,r=((e,t)=>{if(null==e)return{};var n,r={};for(n in e)!{}.hasOwnProperty.call(e,n)||-1!==t.indexOf(n)||(r[n]=e[n]);return r})(e,t);if(Object.getOwnPropertySymbols)for(var a=Object.getOwnPropertySymbols(e),o=0;o<a.length;o++)n=a[o],-1===t.indexOf(n)&&{}.propertyIsEnumerable.call(e,n)&&(r[n]=e[n]);return r}function R(e,t,n){t=T(t);var r=e;if((t=N()?Reflect.construct(t,n||[],T(e).constructor):t.apply(e,n))&&(\"object\"==a(t)||\"function\"==typeof t))return t;if(void 0!==t)throw new TypeError(\"Derived constructors may only return object or undefined\");if(void 0!==(t=r))return t;throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\")}function N(){t\\\nry{var e=!Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],(function(){})))}catch(e){}return(N=function(){return!!e})()}function T(e){return(T=Object.setPrototypeOf?Object.getPrototypeOf.bind():function(e){return e.__proto__||Object.getPrototypeOf(e)})(e)}function S(e,t){if(\"function\"!=typeof t&&null!==t)throw new TypeError(\"Super expression must either be null or a function\");e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,writable:!0,configurable:!0}}),Object.defineProperty(e,\"prototype\",{writable:!1}),t&&_(e,t)}function _(e,t){return(_=Object.setPrototypeOf?Object.setPrototypeOf.bind():function(e,t){return e.__proto__=t,e})(e,t)}function O(){return(O=Object.assign?Object.assign.bind():function(e){for(var t=1;t<arguments.length;t++){var n,r=arguments[t];for(n in r)!{}.hasOwnProperty.call(r,n)||(e[n]=r[n])}return e}).apply(null,arguments)}function M(e){return(e=>{if(Array.isArray(e))return Z(e)})(e)||P(e)||X(e)||(()=>{throw new TypeError(\"Invalid attempt to s\\\npread non-iterable instance.\\\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.\")})()}function P(e){if(\"undefined\"!=typeof Symbol&&null!=e[Symbol.iterator]||null!=e[\"@@iterator\"])return Array.from(e)}function I(e,t,n){j(e,t),t.set(e,n)}function B(e,t){j(e,t),t.add(e)}function j(e,t){if(t.has(e))throw new TypeError(\"Cannot initialize the same private elements twice on an object\")}function L(e,t){return e.get(z(e,t))}function q(e,t,n){e.set(z(e,t),n)}function z(e,t,n){if(\"function\"==typeof e?e===t:e.has(t))return arguments.length<3?t:n;throw new TypeError(\"Private element is not present on this object\")}function V(e,t){return $(e)||((e,t)=>{var n=null==e?null:\"undefined\"!=typeof Symbol&&e[Symbol.iterator]||e[\"@@iterator\"];if(null!=n){var r,a,o,i,l=[],u=!0,s=!1;try{if(o=(n=n.call(e)).next,0===t){if(Object(n)!==n)return;u=!1}else for(;!(u=(r=o.call(n)).done)&&(l.push(r.value),l.length!==t);u=!0);}catch(e){s=!0,a=e}finally{try{if(!u&&null!=n.return&&(i=n.ret\\\nurn(),Object(i)!==i))return}finally{if(s)throw a}}return l}})(e,t)||X(e,t)||G()}function G(){throw new TypeError(\"Invalid attempt to destructure non-iterable instance.\\\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.\")}function $(e){if(Array.isArray(e))return e}function H(e,t){if(!(e instanceof t))throw new TypeError(\"Cannot call a class as a function\")}function U(e,t){for(var n=0;n<t.length;n++){var r=t[n];r.enumerable=r.enumerable||!1,r.configurable=!0,\"value\"in r&&(r.writable=!0),Object.defineProperty(e,Y(r.key),r)}}function W(e,t,n){return t&&U(e.prototype,t),n&&U(e,n),Object.defineProperty(e,\"prototype\",{writable:!1}),e}function Y(e){return e=((e,t)=>{if(\"object\"!=a(e)||!e)return e;var n=e[Symbol.toPrimitive];if(void 0===n)return String(e);if(n=n.call(e,\"string\"),\"object\"==a(n))throw new TypeError(\"@@toPrimitive must return a primitive value.\");return n})(e),\"symbol\"==a(e)?e:e+\"\"}function K(e,t){var n,r,a,o,i=\"undefined\"!=typeof Symbol&&e[Symbol.\\\niterator]||e[\"@@iterator\"];if(i)return a=!(r=!0),{s:function(){i=i.call(e)},n:function(){var e=i.next();return r=e.done,e},e:function(e){a=!0,n=e},f:function(){try{r||null==i.return||i.return()}finally{if(a)throw n}}};if(Array.isArray(e)||(i=X(e))||t&&e&&\"number\"==typeof e.length)return i&&(e=i),o=0,{s:t=function(){},n:function(){return o>=e.length?{done:!0}:{done:!1,value:e[o++]}},e:function(e){throw e},f:t};throw new TypeError(\"Invalid attempt to iterate non-iterable instance.\\\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.\")}function X(e,t){var n;if(e)return\"string\"==typeof e?Z(e,t):\"Map\"===(n=\"Object\"===(n={}.toString.call(e).slice(8,-1))&&e.constructor?e.constructor.name:n)||\"Set\"===n?Array.from(e):\"Arguments\"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?Z(e,t):void 0}function Z(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n<t;n++)r[n]=e[n];return r}function a(e){return(a=\"function\"==typeof Symbol&&\"symbol\"==typeof \\\nSymbol.iterator?function(e){return typeof e}:function(e){return e&&\"function\"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?\"symbol\":typeof e})(e)}var J,Q,ee,te,ne,re,ae,oe,ie,le,ue=void 0;function se(e,t){return function(){return t||e((t={exports:{}}).exports,t),t.exports}}function ce(e,t){for(var n in t)me(e,n,{get:t[n],enumerable:!0})}function de(e){return function(e,t,n){if(t&&\"object\"===a(t)||\"function\"==typeof t){var r,o=K(ve(t));try{for(o.s();!(r=o.n()).done;)(()=>{var a=r.value;ge.call(e,a)||\"default\"===a||me(e,a,{get:function(){return t[a]},enumerable:!(n=be(t,a))||n.enumerable})})()}catch(e){o.e(e)}finally{o.f()}}return e}((t=me(null!=e?fe(he(e)):{},\"default\",e&&e.__esModule&&\"default\"in e?{get:function(){return e.default},enumerable:!0}:{value:e,enumerable:!0}),me(t,\"__esModule\",{value:!0})),e);var t}function pe(e,t,n){(t=\"symbol\"!==a(t)?t+\"\":t)in e?me(e,t,{enumerable:!0,configurable:!0,writable:!0,value:n}):e[t]=n}var fe=Object.create,me=Object.defineProperty\\\n,he=Object.getPrototypeOf,ge=Object.prototype.hasOwnProperty,ve=Object.getOwnPropertyNames,be=Object.getOwnPropertyDescriptor,ye=se((function(e,o){var i;i=function(){function e(e){return\"function\"==typeof e}var o=Array.isArray||function(e){return\"[object Array]\"===Object.prototype.toString.call(e)},i=0,l=void 0,u=void 0,s=function(e,t){h[i]=e,h[i+1]=t,2===(i+=2)&&(u?u(g):D())},c=void 0!==t?t:void 0,d=(d=c||{}).MutationObserver||d.WebKitMutationObserver,p=\"undefined\"==typeof self&&\"undefined\"!=typeof process&&\"[object process]\"==={}.toString.call(process),f=\"undefined\"!=typeof Uint8ClampedArray&&\"undefined\"!=typeof importScripts&&\"undefined\"!=typeof MessageChannel;function m(){var e=setTimeout;return function(){return e(g,1)}}var h=new Array(1e3);function g(){for(var e=0;e<i;e+=2)(0,h[e])(h[e+1]),h[e]=void 0,h[e+1]=void 0;i=0}var v,b,y,D=void 0;function w(e,t){var n,r=this,a=new this.constructor(A),o=(void 0===a[E]&&B(a),r._state);return o?(n=arguments[o-1],s((function(){return P(o,a,n,\\\nr._result)}))):O(r,a,e,t),a}function x(e){var t;return e&&\"object\"===a(e)&&e.constructor===this?e:(N(t=new this(A),e),t)}D=p?function(){return process.nextTick(g)}:d?(b=0,p=new d(g),y=r.createTextNode(\"\"),p.observe(y,{characterData:!0}),function(){y.data=b=++b%2}):f?((v=new MessageChannel).port1.onmessage=g,function(){return v.port2.postMessage(0)}):(void 0===c?function(){try{var e=Function(\"return this\")().require(\"vertx\");return void 0!==(l=e.runOnLoop||e.runOnContext)?function(){l(g)}:m()}catch(e){return m()}}:m)();var E=Math.random().toString(36).substring(2);function A(){}var F=void 0,C=1,k=2;function R(t,n,r){var a,o;n.constructor===t.constructor&&r===w&&n.constructor.resolve===x?(a=t,(o=n)._state===C?S(a,o._result):o._state===k?_(a,o._result):O(o,void 0,(function(e){return N(a,e)}),(function(e){return _(a,e)}))):void 0!==r&&e(r)?function(e,t,n){s((function(e){var r=!1,a=((e,t,n,r)=>{try{e.call(t,n,r)}catch(e){return e}})(n,t,(function(n){r||(r=!0,(t!==n?N:S)(e,n))}),(function(t)\\\n{r||(r=!0,_(e,t))}),e._label);!r&&a&&(r=!0,_(e,a))}),e)}(t,n,r):S(t,n)}function N(e,t){if(e===t)_(e,new TypeError(\"You cannot resolve a promise with itself\"));else if(r=a(n=t),null===n||\"object\"!==r&&\"function\"!==r)S(e,t);else{n=void 0;try{n=t.then}catch(t){return void _(e,t)}R(e,t,n)}var n,r}function T(e){e._onerror&&e._onerror(e._result),M(e)}function S(e,t){e._state===F&&(e._result=t,e._state=C,0!==e._subscribers.length)&&s(M,e)}function _(e,t){e._state===F&&(e._state=k,e._result=t,s(T,e))}function O(e,t,n,r){var a=e._subscribers,o=a.length;e._onerror=null,a[o]=t,a[o+C]=n,a[o+k]=r,0===o&&e._state&&s(M,e)}function M(e){var t=e._subscribers,n=e._state;if(0!==t.length){for(var r,a=void 0,o=e._result,i=0;i<t.length;i+=3)r=t[i],a=t[i+n],r?P(n,r,a,o):a(o);e._subscribers.length=0}}function P(t,n,r,a){var o=e(r),i=void 0,l=void 0,u=!0;if(o){try{i=r(a)}catch(t){u=!1,l=t}if(n===i)return void _(n,new TypeError(\"A promises callback cannot return that same promise.\"))}else i=a;n._state===F&&(o&&\\\nu?N(n,i):!1===u?_(n,l):t===C?S(n,i):t===k&&_(n,i))}var I=0;function B(e){e[E]=I++,e._state=void 0,e._result=void 0,e._subscribers=[]}L.prototype._enumerate=function(e){for(var t=0;this._state===F&&t<e.length;t++)this._eachEntry(e[t],t)},L.prototype._eachEntry=function(e,t){var n=this._instanceConstructor,r=n.resolve;if(r===x){var a,o=void 0,i=void 0,l=!1;try{o=e.then}catch(t){l=!0,i=t}o===w&&e._state!==F?this._settledAt(e._state,t,e._result):\"function\"!=typeof o?(this._remaining--,this._result[t]=e):n===q?(a=new n(A),l?_(a,i):R(a,e,o),this._willSettleAt(a,t)):this._willSettleAt(new n((function(t){return t(e)})),t)}else this._willSettleAt(r(e),t)},L.prototype._settledAt=function(e,t,n){var r=this.promise;r._state===F&&(this._remaining--,e===k?_(r,n):this._result[t]=n),0===this._remaining&&S(r,this._result)},L.prototype._willSettleAt=function(e,t){var n=this;O(e,void 0,(function(e){return n._settledAt(C,t,e)}),(function(e){return n._settledAt(k,t,e)}))};var j=L;function L(e,t){this._inst\\\nanceConstructor=e,this.promise=new e(A),this.promise[E]||B(this.promise),o(t)?(this.length=t.length,this._remaining=t.length,this._result=new Array(this.length),0!==this.length&&(this.length=this.length||0,this._enumerate(t),0!==this._remaining)||S(this.promise,this._result)):_(this.promise,new Error(\"Array Methods must be provided an Array\"))}z.prototype.catch=function(e){return this.then(null,e)},z.prototype.finally=function(t){var n=this.constructor;return e(t)?this.then((function(e){return n.resolve(t()).then((function(){return e}))}),(function(e){return n.resolve(t()).then((function(){throw e}))})):this.then(t,t)};var q=z;function z(e){if(this[E]=I++,this._result=this._state=void 0,this._subscribers=[],A!==e){if(\"function\"!=typeof e)throw new TypeError(\"You must pass a resolver function as the first argument to the promise constructor\");if(!(this instanceof z))throw new TypeError(\"Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be calle\\\nd as a function.\");var t=this;try{e((function(e){N(t,e)}),(function(e){_(t,e)}))}catch(e){_(t,e)}}}return q.prototype.then=w,q.all=function(e){return new j(this,e).promise},q.race=function(e){var t=this;return o(e)?new t((function(n,r){for(var a=e.length,o=0;o<a;o++)t.resolve(e[o]).then(n,r)})):new t((function(e,t){return t(new TypeError(\"You must pass an array to race.\"))}))},q.resolve=x,q.reject=function(e){var t=new this(A);return _(t,e),t},q._setScheduler=function(e){u=e},q._setAsap=function(e){s=e},q._asap=s,q.polyfill=function(){var e=void 0;if(void 0!==n)e=n;else if(\"undefined\"!=typeof self)e=self;else try{e=Function(\"return this\")()}catch(e){throw new Error(\"polyfill failed because global object is unavailable in this environment\")}var t=e.Promise;if(t){var r=null;try{r=Object.prototype.toString.call(t.resolve())}catch(e){}if(\"[object Promise]\"===r&&!t.cast)return}e.Promise=q},q.Promise=q},\"object\"===a(e)&&void 0!==o?o.exports=i():\"function\"==typeof define&&define.amd?define(i)\\\n:e.ES6Promise=i()})),De=se((function(e){var t,n,r=1e5,o=(t=Object.prototype.toString,n=Object.prototype.hasOwnProperty,{Class:function(e){return t.call(e).replace(/^\\\\[object *|\\\\]$/g,\"\")},HasProperty:function(e,t){return t in e},HasOwnProperty:function(e,t){return n.call(e,t)},IsCallable:function(e){return\"function\"==typeof e},ToInt32:function(e){return e>>0},ToUint32:function(e){return e>>>0}}),i=Math.LN2,l=Math.abs,u=Math.floor,s=Math.log,c=Math.min,d=Math.pow,p=Math.round;function f(e,t,n){return e<t?t:n<e?n:e}var m,h,g,v,b,y,D,w,x,E,A,F=Object.getOwnPropertyNames||function(e){if(e!==Object(e))throw new TypeError(\"Object.getOwnPropertyNames called on non-object\");var t,n=[];for(t in e)o.HasOwnProperty(e,t)&&n.push(t);return n};function C(e){if(F&&m)for(var t=F(e),n=0;n<t.length;n+=1)m(e,t[n],{value:e[t[n]],writable:!1,enumerable:!1,configurable:!1})}function k(e){if(m){if(e.length>r)throw new RangeError(\"Array too large for polyfill\");for(var t=0;t<e.length;t+=1)(t=>{m(e,t,{get:funct\\\nion(){return e._getter(t)},set:function(n){e._setter(t,n)},enumerable:!0,configurable:!1})})(t)}}function R(e,t){return e<<(t=32-t)>>t}function N(e,t){return e<<(t=32-t)>>>t}function T(e){return N(e[0],8)}function S(e,t,n){var r,a,o,p,f,m,h,g=(1<<t-1)-1;function v(e){var t=u(e);return(e=e-t)<.5||!(.5<e||t%2)?t:t+1}for(e!=e?(a=(1<<t)-1,o=d(2,n-1),r=0):e===1/0||e===-1/0?(a=(1<<t)-1,r=e<(o=0)?1:0):0===e?r=1/e==-1/(o=a=0)?1:0:(r=e<0,(e=l(e))>=d(2,1-g)?(a=c(u(s(e)/i),1023),2<=(o=v(e/d(2,a)*d(2,n)))/d(2,n)&&(a+=1,o=1),g<a?(a=(1<<t)-1,o=0):(a+=g,o-=d(2,n))):(a=0,o=v(e/d(2,1-g-n)))),f=[],p=n;p;--p)f.push(o%2?1:0),o=u(o/2);for(p=t;p;--p)f.push(a%2?1:0),a=u(a/2);for(f.push(r?1:0),f.reverse(),m=f.join(\"\"),h=[];m.length;)h.push(parseInt(m.substring(0,8),2)),m=m.substring(8);return h}function _(e,t,n){for(var r,a,o,i,l,u,s=[],c=e.length;c;--c)for(a=e[c-1],r=8;r;--r)s.push(a%2?1:0),a>>=1;return s.reverse(),u=s.join(\"\"),o=(1<<t-1)-1,i=parseInt(u.substring(0,1),2)?-1:1,l=parseInt(u.substring(1,1+t),2)\\\n,u=parseInt(u.substring(1+t),2),l===(1<<t)-1?0===u?1/0*i:NaN:0<l?i*d(2,l-o)*(1+u/d(2,n)):0!==u?i*d(2,-(o-1))*(u/d(2,n)):i<0?-0:0}function O(e){if((e=o.ToInt32(e))<0)throw new RangeError(\"ArrayBuffer size is not a small enough positive integer\");var t;for(this.byteLength=e,this._bytes=[],this._bytes.length=e,t=0;t<this.byteLength;t+=1)this._bytes[t]=0;C(this)}function M(){}function P(e,t,n){var r=function(e,t,n){var i,l,u,s;if(arguments.length&&\"number\"!=typeof e)if(\"object\"===a(e)&&e.constructor===r)for(this.length=(i=e).length,this.byteLength=this.length*this.BYTES_PER_ELEMENT,this.buffer=new O(this.byteLength),u=this.byteOffset=0;u<this.length;u+=1)this._setter(u,i._getter(u));else if(\"object\"!==a(e)||e instanceof O||\"ArrayBuffer\"===o.Class(e)){if(\"object\"!==a(e)||!(e instanceof O||\"ArrayBuffer\"===o.Class(e)))throw new TypeError(\"Unexpected argument type(s)\");if(this.buffer=e,this.byteOffset=o.ToUint32(t),this.byteOffset>this.buffer.byteLength)throw new RangeError(\"byteOffset out of \\\nrange\");if(this.byteOffset%this.BYTES_PER_ELEMENT)throw new RangeError(\"ArrayBuffer length minus the byteOffset is not a multiple of the element size.\");if(arguments.length<3){if(this.byteLength=this.buffer.byteLength-this.byteOffset,this.byteLength%this.BYTES_PER_ELEMENT)throw new RangeError(\"length of buffer minus byteOffset not a multiple of the element size\");this.length=this.byteLength/this.BYTES_PER_ELEMENT}else this.length=o.ToUint32(n),this.byteLength=this.length*this.BYTES_PER_ELEMENT;if(this.byteOffset+this.byteLength>this.buffer.byteLength)throw new RangeError(\"byteOffset and length reference an area beyond the end of the buffer\")}else for(this.length=o.ToUint32((l=e).length),this.byteLength=this.length*this.BYTES_PER_ELEMENT,this.buffer=new O(this.byteLength),u=this.byteOffset=0;u<this.length;u+=1)s=l[u],this._setter(u,Number(s));else{if(this.length=o.ToInt32(e),n<0)throw new RangeError(\"ArrayBufferView size is not a small enough positive integer\");this.byteLength=this.leng\\\nth*this.BYTES_PER_ELEMENT,this.buffer=new O(this.byteLength),this.byteOffset=0}this.constructor=r,C(this),k(this)};return(r.prototype=new M).BYTES_PER_ELEMENT=e,r.prototype._pack=t,r.prototype._unpack=n,r.BYTES_PER_ELEMENT=e,r.prototype.get=r.prototype._getter=function(e){if(arguments.length<1)throw new SyntaxError(\"Not enough arguments\");if(!((e=o.ToUint32(e))>=this.length)){for(var t=[],n=0,r=this.byteOffset+e*this.BYTES_PER_ELEMENT;n<this.BYTES_PER_ELEMENT;n+=1,r+=1)t.push(this.buffer._bytes[r]);return this._unpack(t)}},r.prototype._setter=function(e,t){if(arguments.length<2)throw new SyntaxError(\"Not enough arguments\");if((e=o.ToUint32(e))<this.length)for(var n=this._pack(t),r=0,a=this.byteOffset+e*this.BYTES_PER_ELEMENT;r<this.BYTES_PER_ELEMENT;r+=1,a+=1)this.buffer._bytes[a]=n[r]},r.prototype.set=function(e,t){if(arguments.length<1)throw new SyntaxError(\"Not enough arguments\");var n,r,i,l,u,s,c,d,p,f;if(\"object\"===a(e)&&e.constructor===this.constructor){if(n=e,(i=o.ToUint32(t))+n\\\n.length>this.length)throw new RangeError(\"Offset plus length of array is out of range\");if(d=this.byteOffset+i*this.BYTES_PER_ELEMENT,p=n.length*this.BYTES_PER_ELEMENT,n.buffer===this.buffer){for(f=[],u=0,s=n.byteOffset;u<p;u+=1,s+=1)f[u]=n.buffer._bytes[s];for(u=0,c=d;u<p;u+=1,c+=1)this.buffer._bytes[c]=f[u]}else for(u=0,s=n.byteOffset,c=d;u<p;u+=1,s+=1,c+=1)this.buffer._bytes[c]=n.buffer._bytes[s]}else{if(\"object\"!==a(e)||void 0===e.length)throw new TypeError(\"Unexpected argument type(s)\");if(l=o.ToUint32((r=e).length),(i=o.ToUint32(t))+l>this.length)throw new RangeError(\"Offset plus length of array is out of range\");for(u=0;u<l;u+=1)s=r[u],this._setter(i+u,Number(s))}},r.prototype.subarray=function(e,t){return e=o.ToInt32(e),t=o.ToInt32(t),arguments.length<1&&(e=0),arguments.length<2&&(t=this.length),e<0&&(e=this.length+e),t<0&&(t=this.length+t),e=f(e,0,this.length),t=(t=f(t,0,this.length))-e,new this.constructor(this.buffer,this.byteOffset+e*this.BYTES_PER_ELEMENT,t=t<0?0:t)},r}fun\\\nction I(e,t){return o.IsCallable(e.get)?e.get(t):e[t]}function B(t,n,r){if(0===arguments.length)t=new e.ArrayBuffer(0);else if(!(t instanceof e.ArrayBuffer||\"ArrayBuffer\"===o.Class(t)))throw new TypeError(\"TypeError\");if(this.buffer=t||new e.ArrayBuffer(0),this.byteOffset=o.ToUint32(n),this.byteOffset>this.buffer.byteLength)throw new RangeError(\"byteOffset out of range\");if(this.byteLength=arguments.length<3?this.buffer.byteLength-this.byteOffset:o.ToUint32(r),this.byteOffset+this.byteLength>this.buffer.byteLength)throw new RangeError(\"byteOffset and length reference an area beyond the end of the buffer\");C(this)}function j(t){return function(n,r){if((n=o.ToUint32(n))+t.BYTES_PER_ELEMENT>this.byteLength)throw new RangeError(\"Array index out of range\");n+=this.byteOffset;for(var a=new e.Uint8Array(this.buffer,n,t.BYTES_PER_ELEMENT),i=[],l=0;l<t.BYTES_PER_ELEMENT;l+=1)i.push(I(a,l));return Boolean(r)===Boolean(A)&&i.reverse(),I(new t(new e.Uint8Array(i).buffer),0)}}function L(t){return f\\\nunction(n,r,a){if((n=o.ToUint32(n))+t.BYTES_PER_ELEMENT>this.byteLength)throw new RangeError(\"Array index out of range\");r=new t([r]);for(var i=new e.Uint8Array(r.buffer),l=[],u=0;u<t.BYTES_PER_ELEMENT;u+=1)l.push(I(i,u));Boolean(a)===Boolean(A)&&l.reverse(),new e.Uint8Array(this.buffer,n,t.BYTES_PER_ELEMENT).set(l)}}m=Object.defineProperty&&(()=>{try{return Object.defineProperty({},\"x\",{}),1}catch(e){}})()?Object.defineProperty:function(e,t,n){if(!e===Object(e))throw new TypeError(\"Object.defineProperty called on non-object\");return o.HasProperty(n,\"get\")&&Object.prototype.__defineGetter__&&Object.prototype.__defineGetter__.call(e,t,n.get),o.HasProperty(n,\"set\")&&Object.prototype.__defineSetter__&&Object.prototype.__defineSetter__.call(e,t,n.set),o.HasProperty(n,\"value\")&&(e[t]=n.value),e},e.ArrayBuffer=e.ArrayBuffer||O,E=P(1,(function(e){return[255&e]}),(function(e){return R(e[0],8)})),h=P(1,(function(e){return[255&e]}),T),g=P(1,(function(e){return[(e=p(Number(e)))<0?0:255<e?255:255&\\\ne]}),T),v=P(2,(function(e){return[e>>8&255,255&e]}),(function(e){return R(e[0]<<8|e[1],16)})),b=P(2,(function(e){return[e>>8&255,255&e]}),(function(e){return N(e[0]<<8|e[1],16)})),y=P(4,(function(e){return[e>>24&255,e>>16&255,e>>8&255,255&e]}),(function(e){return R(e[0]<<24|e[1]<<16|e[2]<<8|e[3],32)})),D=P(4,(function(e){return[e>>24&255,e>>16&255,e>>8&255,255&e]}),(function(e){return N(e[0]<<24|e[1]<<16|e[2]<<8|e[3],32)})),w=P(4,(function(e){return S(e,8,23)}),(function(e){return _(e,8,23)})),x=P(8,(function(e){return S(e,11,52)}),(function(e){return _(e,11,52)})),e.Int8Array=e.Int8Array||E,e.Uint8Array=e.Uint8Array||h,e.Uint8ClampedArray=e.Uint8ClampedArray||g,e.Int16Array=e.Int16Array||v,e.Uint16Array=e.Uint16Array||b,e.Int32Array=e.Int32Array||y,e.Uint32Array=e.Uint32Array||D,e.Float32Array=e.Float32Array||w,e.Float64Array=e.Float64Array||x,E=new e.Uint16Array([4660]),A=18===I(new e.Uint8Array(E.buffer),0),B.prototype.getUint8=j(e.Uint8Array),B.prototype.getInt8=j(e.Int8Array),B.pr\\\nototype.getUint16=j(e.Uint16Array),B.prototype.getInt16=j(e.Int16Array),B.prototype.getUint32=j(e.Uint32Array),B.prototype.getInt32=j(e.Int32Array),B.prototype.getFloat32=j(e.Float32Array),B.prototype.getFloat64=j(e.Float64Array),B.prototype.setUint8=L(e.Uint8Array),B.prototype.setInt8=L(e.Int8Array),B.prototype.setUint16=L(e.Uint16Array),B.prototype.setInt16=L(e.Int16Array),B.prototype.setUint32=L(e.Uint32Array),B.prototype.setInt32=L(e.Int32Array),B.prototype.setFloat32=L(e.Float32Array),B.prototype.setFloat64=L(e.Float64Array),e.DataView=e.DataView||B})),we=se((function(e){function r(){if(void 0===this)throw new TypeError(\"Constructor WeakMap requires 'new'\");if(c(this,\"_id\",\"_WeakMap_\"+i()+\".\"+i()),0<arguments.length)throw new TypeError(\"WeakMap iterable is not supported\")}function o(e,t){if(!l(e)||!u.call(e,\"_id\"))throw new TypeError(t+\" method called on incompatible receiver \"+a(e))}function i(){return Math.random().toString().substring(2)}function l(e){return Object(e)===e}var u\\\n,s,c;(e=\"undefined\"!=typeof globalThis?globalThis:\"undefined\"!=typeof self?self:void 0!==t?t:void 0!==n?n:e).WeakMap||(u=Object.prototype.hasOwnProperty,s=Object.defineProperty&&(()=>{try{return 1===Object.defineProperty({},\"x\",{value:1}).x}catch(e){}})(),e.WeakMap=((c=function(e,t,n){s?Object.defineProperty(e,t,{configurable:!0,writable:!0,value:n}):e[t]=n})(r.prototype,\"delete\",(function(e){var t;return o(this,\"delete\"),!!l(e)&&!(!(t=e[this._id])||t[0]!==e||(delete e[this._id],0))})),c(r.prototype,\"get\",(function(e){var t;return o(this,\"get\"),l(e)&&(t=e[this._id])&&t[0]===e?t[1]:void 0})),c(r.prototype,\"has\",(function(e){var t;return o(this,\"has\"),!!l(e)&&!(!(t=e[this._id])||t[0]!==e)})),c(r.prototype,\"set\",(function(e,t){var n;if(o(this,\"set\"),l(e))return(n=e[this._id])&&n[0]===e?n[1]=t:c(e,this._id,[e,t]),this;throw new TypeError(\"Invalid value used as weak map key\")})),c(r,\"_polyfill\",!0),r))})),xe=se((function(e,r){function o(e){return e&&e.Math===Math&&e}r.exports=o(\"object\"==(\"\\\nundefined\"==typeof globalThis?\"undefined\":a(globalThis))&&globalThis)||o(\"object\"==(void 0===t?\"undefined\":a(t))&&t)||o(\"object\"==(\"undefined\"==typeof self?\"undefined\":a(self))&&self)||o(\"object\"==(void 0===n?\"undefined\":a(n))&&n)||o(\"object\"==a(e)&&e)||function(){return this}()||Function(\"return this\")()})),Ee=se((function(e,t){t.exports=function(e){try{return!!e()}catch(e){return!0}}})),Ae=se((function(e,t){var n=Ee();t.exports=!n((function(){var e=function(){}.bind();return\"function\"!=typeof e||e.hasOwnProperty(\"prototype\")}))})),Fe=se((function(e,t){var n=Ae(),r=Function.prototype,o=r.apply,i=r.call;t.exports=\"object\"==(\"undefined\"==typeof Reflect?\"undefined\":a(Reflect))&&Reflect.apply||(n?i.bind(o):function(){return i.apply(o,arguments)})})),Ce=se((function(e,t){var n=Ae(),r=(a=Function.prototype).call,a=n&&a.bind.bind(r,r);t.exports=n?a:function(e){return function(){return r.apply(e,arguments)}}})),ke=se((function(e,t){var n=Ce(),r=n({}.toString),a=n(\"\".slice);t.exports=function(\\\ne){return a(r(e),8,-1)}})),Re=se((function(e,t){var n=ke(),r=Ce();t.exports=function(e){if(\"Function\"===n(e))return r(e)}})),Ne=se((function(e,t){var n=\"object\"==(void 0===r?\"undefined\":a(r))&&r.all;t.exports=void 0===n&&void 0!==n?function(e){return\"function\"==typeof e||e===n}:function(e){return\"function\"==typeof e}})),Te=se((function(e,t){var n=Ee();t.exports=!n((function(){return 7!==Object.defineProperty({},1,{get:function(){return 7}})[1]}))})),Se=se((function(e,t){var n=Ae(),r=Function.prototype.call;t.exports=n?r.bind(r):function(){return r.apply(r,arguments)}})),_e=se((function(e){var t={}.propertyIsEnumerable,n=Object.getOwnPropertyDescriptor,r=n&&!t.call({1:2},1);e.f=r?function(e){return!!(e=n(this,e))&&e.enumerable}:t})),Oe=se((function(e,t){t.exports=function(e,t){return{enumerable:!(1&e),configurable:!(2&e),writable:!(4&e),value:t}}})),Me=se((function(e,t){var n=Ce(),r=Ee(),a=ke(),o=Object,i=n(\"\".split);t.exports=r((function(){return!o(\"z\").propertyIsEnumerable(0)}))?funct\\\nion(e){return\"String\"===a(e)?i(e,\"\"):o(e)}:o})),Pe=se((function(e,t){t.exports=function(e){return null==e}})),Ie=se((function(e,t){var n=Pe(),r=TypeError;t.exports=function(e){if(n(e))throw new r(\"Can't call method on \"+e);return e}})),Be=se((function(e,t){var n=Me(),r=Ie();t.exports=function(e){return n(r(e))}})),je=se((function(e,t){var n=Ne();t.exports=function(e){return\"object\"==a(e)?null!==e:n(e)}})),Le=se((function(e,t){t.exports={}})),qe=se((function(e,t){function n(e){return o(e)?e:void 0}var r=Le(),a=xe(),o=Ne();t.exports=function(e,t){return arguments.length<2?n(r[e])||n(a[e]):r[e]&&r[e][t]||a[e]&&a[e][t]}})),ze=se((function(e,t){var n=Ce();t.exports=n({}.isPrototypeOf)})),Ve=se((function(e,t){var n=(n=xe().navigator)&&n.userAgent;t.exports=n?String(n):\"\"})),Ge=se((function(e,t){var n,r,a=xe(),o=Ve(),i=a.process;a=a.Deno;!(r=(a=(i=i&&i.versions||a&&a.version)&&i.v8)?0<(n=a.split(\".\"))[0]&&n[0]<4?1:+(n[0]+n[1]):r)&&o&&(!(n=o.match(/Edge\\\\/(\\\\d+)/))||74<=n[1])&&(n=o.match(/Chrome\\\n\\\\/(\\\\d+)/))&&(r=+n[1]),t.exports=r})),$e=se((function(e,t){var n=Ge(),r=Ee(),a=xe().String;t.exports=!!Object.getOwnPropertySymbols&&!r((function(){var e=Symbol(\"symbol detection\");return!a(e)||!(Object(e)instanceof Symbol)||!Symbol.sham&&n&&n<41}))})),He=se((function(e,t){var n=$e();t.exports=n&&!Symbol.sham&&\"symbol\"==a(Symbol.iterator)})),Ue=se((function(e,t){var n=qe(),r=Ne(),o=ze(),i=He(),l=Object;t.exports=i?function(e){return\"symbol\"==a(e)}:function(e){var t=n(\"Symbol\");return r(t)&&o(t.prototype,l(e))}})),We=se((function(e,t){var n=String;t.exports=function(e){try{return n(e)}catch(e){return\"Object\"}}})),Ye=se((function(e,t){var n=Ne(),r=We(),a=TypeError;t.exports=function(e){if(n(e))return e;throw new a(r(e)+\" is not a function\")}})),Ke=se((function(e,t){var n=Ye(),r=Pe();t.exports=function(e,t){return e=e[t],r(e)?void 0:n(e)}})),Xe=se((function(e,t){var n=Se(),r=Ne(),a=je(),o=TypeError;t.exports=function(e,t){var i,l;if(\"string\"===t&&r(i=e.toString)&&!a(l=n(i,e)))return l;if(r\\\n(i=e.valueOf)&&!a(l=n(i,e)))return l;if(\"string\"!==t&&r(i=e.toString)&&!a(l=n(i,e)))return l;throw new o(\"Can't convert object to primitive value\")}})),Ze=se((function(e,t){t.exports=!0})),Je=se((function(e,t){var n=xe(),r=Object.defineProperty;t.exports=function(e,t){try{r(n,e,{value:t,configurable:!0,writable:!0})}catch(r){n[e]=t}return t}})),Qe=se((function(e,t){var n=Ze(),r=xe(),a=Je(),o=\"__core-js_shared__\";((t=t.exports=r[o]||a(o,{})).versions||(t.versions=[])).push({version:\"3.44.0\",mode:n?\"pure\":\"global\",copyright:\"© 2014-2025 Denis Pushkarev (zloirock.ru)\",license:\"https://github.com/zloirock/core-js/blob/v3.44.0/LICENSE\",source:\"https://github.com/zloirock/core-js\"})})),et=se((function(e,t){var n=Qe();t.exports=function(e,t){return n[e]||(n[e]=t||{})}})),tt=se((function(e,t){var n=Ie(),r=Object;t.exports=function(e){return r(n(e))}})),nt=se((function(e,t){var n=Ce(),r=tt(),a=n({}.hasOwnProperty);t.exports=Object.hasOwn||function(e,t){return a(r(e),t)}})),rt=se((function(e,t){\\\nvar n=Ce(),r=0,a=Math.random(),o=n(1.1.toString);t.exports=function(e){return\"Symbol(\"+(void 0===e?\"\":e)+\")_\"+o(++r+a,36)}})),at=se((function(e,t){var n=xe(),r=et(),a=nt(),o=rt(),i=$e(),l=He(),u=n.Symbol,s=r(\"wks\"),c=l?u.for||u:u&&u.withoutSetter||o;t.exports=function(e){return a(s,e)||(s[e]=i&&a(u,e)?u[e]:c(\"Symbol.\"+e)),s[e]}})),ot=se((function(e,t){var n=Se(),r=je(),a=Ue(),o=Ke(),i=Xe(),l=at(),u=TypeError,s=l(\"toPrimitive\");t.exports=function(e,t){if(!r(e)||a(e))return e;var l=o(e,s);if(l){if(l=n(l,e,t=void 0===t?\"default\":t),!r(l)||a(l))return l;throw new u(\"Can't convert object to primitive value\")}return i(e,t=void 0===t?\"number\":t)}})),it=se((function(e,t){var n=ot(),r=Ue();t.exports=function(e){return e=n(e,\"string\"),r(e)?e:e+\"\"}})),lt=se((function(e,t){var n=xe(),r=je(),a=n.document,o=r(a)&&r(a.createElement);t.exports=function(e){return o?a.createElement(e):{}}})),ut=se((function(e,t){var n=Te(),r=Ee(),a=lt();t.exports=!n&&!r((function(){return 7!==Object.defineProperty(a(\"di\\\nv\"),\"a\",{get:function(){return 7}}).a}))})),st=se((function(e){var t=Te(),n=Se(),r=_e(),a=Oe(),o=Be(),i=it(),l=nt(),u=ut(),s=Object.getOwnPropertyDescriptor;e.f=t?s:function(e,t){if(e=o(e),t=i(t),u)try{return s(e,t)}catch(e){}if(l(e,t))return a(!n(r.f,e,t),e[t])}})),ct=se((function(e,t){function n(e,t){return(e=l[i(e)])===s||e!==u&&(a(t)?r(t):!!t)}var r=Ee(),a=Ne(),o=/#|\\\\.prototype\\\\./,i=n.normalize=function(e){return String(e).replace(o,\".\").toLowerCase()},l=n.data={},u=n.NATIVE=\"N\",s=n.POLYFILL=\"P\";t.exports=n})),dt=se((function(e,t){var n=Re(),r=Ye(),a=Ae(),o=n(n.bind);t.exports=function(e,t){return r(e),void 0===t?e:a?o(e,t):function(){return e.apply(t,arguments)}}})),pt=se((function(e,t){var n=Te(),r=Ee();t.exports=n&&r((function(){return 42!==Object.defineProperty((function(){}),\"prototype\",{value:42,writable:!1}).prototype}))})),ft=se((function(e,t){var n=je(),r=String,a=TypeError;t.exports=function(e){if(n(e))return e;throw new a(r(e)+\" is not an object\")}})),mt=se((function(e){\\\nvar t=Te(),n=ut(),r=pt(),a=ft(),o=it(),i=TypeError,l=Object.defineProperty,u=Object.getOwnPropertyDescriptor,s=\"enumerable\",c=\"configurable\",d=\"writable\";e.f=t?r?function(e,t,n){var r;return a(e),t=o(t),a(n),\"function\"==typeof e&&\"prototype\"===t&&\"value\"in n&&d in n&&!n[d]&&(r=u(e,t))&&r[d]&&(e[t]=n.value,n={configurable:(c in n?n:r)[c],enumerable:(s in n?n:r)[s],writable:!1}),l(e,t,n)}:l:function(e,t,r){if(a(e),t=o(t),a(r),n)try{return l(e,t,r)}catch(e){}if(\"get\"in r||\"set\"in r)throw new i(\"Accessors not supported\");return\"value\"in r&&(e[t]=r.value),e}})),ht=se((function(e,t){var n=Te(),r=mt(),a=Oe();t.exports=n?function(e,t,n){return r.f(e,t,a(1,n))}:function(e,t,n){return e[t]=n,e}})),gt=se((function(e,t){function n(e){function t(n,r,a){if(this instanceof t){switch(arguments.length){case 0:return new e;case 1:return new e(n);case 2:return new e(n,r)}return new e(n,r,a)}return o(e,this,arguments)}return t.prototype=e.prototype,t}var r=xe(),o=Fe(),i=Re(),l=Ne(),u=st().f,s=ct(),c=Le(),\\\nd=dt(),p=ht(),f=nt();Qe(),t.exports=function(e,t){var o,m,h,g,v,b,y=e.target,D=e.global,w=e.stat,x=e.proto,E=D?r:w?r[y]:r[y]&&r[y].prototype,A=D?c:c[y]||p(c,y,{})[y],F=A.prototype;for(m in t)v=!(o=s(D?m:y+(w?\".\":\"#\")+m,e.forced))&&E&&f(E,m),g=A[m],v&&(b=e.dontCallGetSet?(b=u(E,m))&&b.value:E[m]),h=v&&b?b:t[m],(o||x||a(g)!=a(h))&&(v=e.bind&&v?d(h,r):e.wrap&&v?n(h):x&&l(h)?i(h):h,(e.sham||h&&h.sham||g&&g.sham)&&p(v,\"sham\",!0),p(A,m,v),x)&&(f(c,g=y+\"Prototype\")||p(c,g,{}),p(c[g],m,h),e.real)&&F&&(o||!F[m])&&p(F,m,h)}})),vt=se((function(){gt()({target:\"Object\",stat:!0},{hasOwn:nt()})})),bt=se((function(e,t){vt();var n=Le();t.exports=n.Object.hasOwn})),yt=se((function(e,t){var n=bt();t.exports=n})),Dt=se((function(e,t){var n=yt();t.exports=n})),wt=se((function(e,t){var n=et(),r=rt(),a=n(\"keys\");t.exports=function(e){return a[e]||(a[e]=r(e))}})),xt=se((function(e,t){var n=Ee();t.exports=!n((function(){function e(){}return e.prototype.constructor=null,Object.getPrototypeOf(new e)!==e.prototyp\\\ne}))})),Et=se((function(e,t){var n=nt(),r=Ne(),a=tt(),o=wt(),i=xt(),l=o(\"IE_PROTO\"),u=Object,s=u.prototype;t.exports=i?u.getPrototypeOf:function(e){var t;e=a(e);return n(e,l)?e[l]:(t=e.constructor,r(t)&&e instanceof t?t.prototype:e instanceof u?s:null)}})),At=se((function(e,t){var n=Math.ceil,r=Math.floor;t.exports=Math.trunc||function(e){return(0<(e=+e)?r:n)(e)}})),Ft=se((function(e,t){var n=At();t.exports=function(e){return(e=+e)!=e||0==e?0:n(e)}})),Ct=se((function(e,t){var n=Ft(),r=Math.max,a=Math.min;t.exports=function(e,t){return(e=n(e))<0?r(e+t,0):a(e,t)}})),kt=se((function(e,t){var n=Ft(),r=Math.min;t.exports=function(e){return 0<(e=n(e))?r(e,9007199254740991):0}})),Rt=se((function(e,t){var n=kt();t.exports=function(e){return n(e.length)}})),Nt=se((function(e,t){function n(e){return function(t,n,i){var l=r(t),u=o(l);if(0!==u){var s,c=a(i,u);if(e&&n!=n){for(;c<u;)if((s=l[c++])!=s)return!0}else for(;c<u;c++)if((e||c in l)&&l[c]===n)return e||c||0}return!e&&-1}}var r=Be(),a=Ct(),o=\\\nRt();t.exports={includes:n(!0),indexOf:n(!1)}})),Tt=se((function(e,t){t.exports={}})),St=se((function(e,t){var n=Ce(),r=nt(),a=Be(),o=Nt().indexOf,i=Tt(),l=n([].push);t.exports=function(e,t){var n,u=a(e),s=0,c=[];for(n in u)!r(i,n)&&r(u,n)&&l(c,n);for(;t.length>s;)!r(u,n=t[s++])||~o(c,n)||l(c,n);return c}})),_t=se((function(e,t){t.exports=[\"constructor\",\"hasOwnProperty\",\"isPrototypeOf\",\"propertyIsEnumerable\",\"toLocaleString\",\"toString\",\"valueOf\"]})),Ot=se((function(e,t){var n=St(),r=_t();t.exports=Object.keys||function(e){return n(e,r)}})),Mt=se((function(e,t){function n(e){return function(t){for(var n,a=u(t),o=l(a),p=d&&null===i(a),f=o.length,m=0,h=[];m<f;)n=o[m++],r&&!(p?n in a:s(a,n))||c(h,e?[n,a[n]]:a[n]);return h}}var r=Te(),a=Ee(),o=Ce(),i=Et(),l=Ot(),u=Be(),s=o(_e().f),c=o([].push),d=r&&a((function(){var e=Object.create(null);return e[2]=2,!s(e,2)}));t.exports={entries:n(!0),values:n(!1)}})),Pt=se((function(){var e=gt(),t=Mt().values;e({target:\"Object\",stat:!0},{values:function(\\\ne){return t(e)}})})),It=se((function(e,t){Pt();var n=Le();t.exports=n.Object.values})),Bt=se((function(e,t){var n=It();t.exports=n})),jt=se((function(e,t){var n=Bt();t.exports=n})),Lt=se((function(e,t){var n={};n[at()(\"toStringTag\")]=\"z\",t.exports=\"[object z]\"===String(n)})),qt=se((function(e,t){var n=Lt(),r=Ne(),a=ke(),o=at()(\"toStringTag\"),i=Object,l=\"Arguments\"===a(function(){return arguments}());t.exports=n?a:function(e){var t;return void 0===e?\"Undefined\":null===e?\"Null\":\"string\"==typeof(t=((e,t)=>{try{return e[t]}catch(e){}})(e=i(e),o))?t:l?a(e):\"Object\"===(t=a(e))&&r(e.callee)?\"Arguments\":t}})),zt=se((function(e,t){var n=qt(),r=String;t.exports=function(e){if(\"Symbol\"===n(e))throw new TypeError(\"Cannot convert a Symbol value to a string\");return r(e)}})),Vt=se((function(e,t){function n(e){return function(t,n){t=o(i(t)),n=a(n);var r,c=t.length;return n<0||c<=n?e?\"\":void 0:(r=u(t,n))<55296||56319<r||n+1===c||(c=u(t,n+1))<56320||57343<c?e?l(t,n):r:e?s(t,n,n+2):c-56320+(r-55296<<10)\\\n+65536}}var r=Ce(),a=Ft(),o=zt(),i=Ie(),l=r(\"\".charAt),u=r(\"\".charCodeAt),s=r(\"\".slice);t.exports={codeAt:n(!1),charAt:n(!0)}})),Gt=se((function(e,t){var n=xe(),r=Ne();n=n.WeakMap;t.exports=r(n)&&/native code/.test(String(n))})),$t=se((function(e,t){var n,r,a,o,i=Gt(),l=xe(),u=je(),s=ht(),c=nt(),d=Qe(),p=wt(),f=Tt(),m=\"Object already initialized\",h=l.TypeError,g=(l=l.WeakMap,i||d.state?((a=d.state||(d.state=new l)).get=a.get,a.has=a.has,a.set=a.set,n=function(e,t){if(a.has(e))throw new h(m);return t.facade=e,a.set(e,t),t},r=function(e){return a.get(e)||{}},function(e){return a.has(e)}):(f[o=p(\"state\")]=!0,n=function(e,t){if(c(e,o))throw new h(m);return t.facade=e,s(e,o,t),t},r=function(e){return c(e,o)?e[o]:{}},function(e){return c(e,o)}));t.exports={set:n,get:r,has:g,enforce:function(e){return g(e)?r(e):n(e,{})},getterFor:function(e){return function(t){if(u(t)&&(t=r(t)).type===e)return t;throw new h(\"Incompatible receiver, \"+e+\" required\")}}}})),Ht=se((function(e,t){var n=Te(),r=nt(),\\\na=Function.prototype,o=n&&Object.getOwnPropertyDescriptor,i=(r=r(a,\"name\"))&&\"something\"===function(){}.name;n=r&&(!n||o(a,\"name\").configurable);t.exports={EXISTS:r,PROPER:i,CONFIGURABLE:n}})),Ut=se((function(e){var t=Te(),n=pt(),r=mt(),a=ft(),o=Be(),i=Ot();e.f=t&&!n?Object.defineProperties:function(e,t){a(e);for(var n,l=o(t),u=i(t),s=u.length,c=0;c<s;)r.f(e,n=u[c++],l[n]);return e}})),Wt=se((function(e,t){var n=qe();t.exports=n(\"document\",\"documentElement\")})),Yt=se((function(e,t){function n(){}var a,o=ft(),i=Ut(),l=_t(),u=Tt(),s=Wt(),c=lt(),d=wt(),p=\"prototype\",f=\"script\",m=d(\"IE_PROTO\"),h=function(e){return\"<\"+f+\">\"+e+\"</\"+f+\">\"},g=function(){try{a=new ActiveXObject(\"htmlfile\")}catch(e){}g=void 0===r||r.domain&&a?function(e){e.write(h(\"\")),e.close();var t=e.parentWindow.Object;return e=null,t}(a):(e=c(\"iframe\"),t=\"java\"+f+\":\",e.style.display=\"none\",s.appendChild(e),e.src=String(t),(t=e.contentWindow.document).open(),t.write(h(\"document.F=Object\")),t.close(),t.F);for(var e,t,n=l.leng\\\nth;n--;)delete g[p][l[n]];return g()};u[m]=!0,t.exports=Object.create||function(e,t){var r;return null!==e?(n[p]=o(e),r=new n,n[p]=null,r[m]=e):r=g(),void 0===t?r:i.f(r,t)}})),Kt=se((function(e,t){var n=ht();t.exports=function(e,t,r,a){return a&&a.enumerable?e[t]=r:n(e,t,r),e}})),Xt=se((function(e,t){var n,r,a=Ee(),o=Ne(),i=je(),l=Yt(),u=Et(),s=Kt(),c=at(),d=Ze(),p=c(\"iterator\");c=!1;[].keys&&(\"next\"in(r=[].keys())?(u=u(u(r)))!==Object.prototype&&(n=u):c=!0),!i(n)||a((function(){var e={};return n[p].call(e)!==e}))?n={}:d&&(n=l(n)),o(n[p])||s(n,p,(function(){return this})),t.exports={IteratorPrototype:n,BUGGY_SAFARI_ITERATORS:c}})),Zt=se((function(e,t){var n=Lt(),r=qt();t.exports=n?{}.toString:function(){return\"[object \"+r(this)+\"]\"}})),Jt=se((function(e,t){var n=Lt(),r=mt().f,a=ht(),o=nt(),i=Zt(),l=at()(\"toStringTag\");t.exports=function(e,t,u,s){(u=u?e:e&&e.prototype)&&(o(u,l)||r(u,l,{configurable:!0,value:t}),s)&&!n&&a(u,\"toString\",i)}})),Qt=se((function(e,t){t.exports={}})),en=se((fu\\\nnction(e,t){function n(){return this}var r=Xt().IteratorPrototype,a=Yt(),o=Oe(),i=Jt(),l=Qt();t.exports=function(e,t,u,s){return t+=\" Iterator\",e.prototype=a(r,{next:o(+!s,u)}),i(e,t,!1,!0),l[t]=n,e}})),tn=se((function(e,t){var n=Ce(),r=Ye();t.exports=function(e,t,a){try{return n(r(Object.getOwnPropertyDescriptor(e,t)[a]))}catch(e){}}})),nn=se((function(e,t){var n=je();t.exports=function(e){return n(e)||null===e}})),rn=se((function(e,t){var n=nn(),r=String,a=TypeError;t.exports=function(e){if(n(e))return e;throw new a(\"Can't set \"+r(e)+\" as a prototype\")}})),an=se((function(e,t){var n=tn(),r=je(),a=Ie(),o=rn();t.exports=Object.setPrototypeOf||(\"__proto__\"in{}?(()=>{var e,t=!1,i={};try{(e=n(Object.prototype,\"__proto__\",\"set\"))(i,[]),t=i instanceof Array}catch(i){}return function(n,i){return a(n),o(i),r(n)&&(t?e(n,i):n.__proto__=i),n}})():void 0)})),on=se((function(e,t){function n(){return this}var r=gt(),a=Se(),o=Ze(),i=Ht(),l=Ne(),u=en(),s=Et(),c=an(),d=Jt(),p=ht(),f=Kt(),m=at(),h=Qt()\\\n,g=Xt(),v=i.PROPER,b=i.CONFIGURABLE,y=g.IteratorPrototype,D=g.BUGGY_SAFARI_ITERATORS,w=m(\"iterator\"),x=\"values\",E=\"entries\";t.exports=function(e,t,i,m,g,A,F){function C(e){if(e===g&&_)return _;if(!D&&e&&e in T)return T[e];switch(e){case\"keys\":case x:case E:return function(){return new i(this,e)}}return function(){return new i(this)}}u(i,t,m);m=t+\" Iterator\";var k,R,N=!1,T=e.prototype,S=T[w]||T[\"@@iterator\"]||g&&T[g],_=!D&&S||C(g),O=\"Array\"===t&&T.entries||S;if(O&&(O=s(O.call(new e)))!==Object.prototype&&O.next&&(o||s(O)===y||(c?c(O,y):l(O[w])||f(O,w,n)),d(O,m,!0,!0),o)&&(h[m]=n),v&&g===x&&S&&S.name!==x&&(!o&&b?p(T,\"name\",x):(N=!0,_=function(){return a(S,this)})),g)if(k={values:C(x),keys:A?_:C(\"keys\"),entries:C(E)},F)for(R in k)!D&&!N&&R in T||f(T,R,k[R]);else r({target:t,proto:!0,forced:D||N},k);return o&&!F||T[w]===_||f(T,w,_,{name:g}),h[t]=_,k}})),ln=se((function(e,t){t.exports=function(e,t){return{value:e,done:t}}})),un=se((function(){var e=Vt().charAt,t=zt(),n=$t(),r=on(),a=ln(),o=\\\n\"String Iterator\",i=n.set,l=n.getterFor(o);r(String,\"String\",(function(e){i(this,{type:o,string:t(e),index:0})}),(function(){var t=l(this),n=t.string,r=t.index;return r>=n.length?a(void 0,!0):(n=e(n,r),t.index+=n.length,a(n,!1))}))})),sn=se((function(e,t){var n=Se(),r=ft(),a=Ke();t.exports=function(e,t,o){var i,l;r(e);try{if(!(i=a(e,\"return\"))){if(\"throw\"===t)throw o;return o}i=n(i,e)}catch(e){l=!0,i=e}if(\"throw\"===t)throw o;if(l)throw i;return r(i),o}})),cn=se((function(e,t){var n=ft(),r=sn();t.exports=function(e,t,a,o){try{return o?t(n(a)[0],a[1]):t(a)}catch(t){r(e,\"throw\",t)}}})),dn=se((function(e,t){var n=at(),r=Qt(),a=n(\"iterator\"),o=Array.prototype;t.exports=function(e){return void 0!==e&&(r.Array===e||o[a]===e)}})),pn=se((function(e,t){var n=Ce(),r=Ne(),a=Qe(),o=n(Function.toString);r(a.inspectSource)||(a.inspectSource=function(e){return o(e)}),t.exports=a.inspectSource})),fn=se((function(e,t){function n(){}function r(e){if(!l(e))return!1;try{return d(n,[],e),!0}catch(e){return!\\\n1}}function a(e){if(!l(e))return!1;switch(u(e)){case\"AsyncFunction\":case\"GeneratorFunction\":case\"AsyncGeneratorFunction\":return!1}try{return m||!!f(p,c(e))}catch(e){return!0}}var o=Ce(),i=Ee(),l=Ne(),u=qt(),s=qe(),c=pn(),d=s(\"Reflect\",\"construct\"),p=/^\\\\s*(?:class|function)\\\\b/,f=o(p.exec),m=!p.test(n);a.sham=!0,t.exports=!d||i((function(){var e;return r(r.call)||!r(Object)||!r((function(){e=!0}))||e}))?a:r})),mn=se((function(e,t){var n=Te(),r=mt(),a=Oe();t.exports=function(e,t,o){n?r.f(e,t,a(0,o)):e[t]=o}})),hn=se((function(e,t){var n=qt(),r=Ke(),a=Pe(),o=Qt(),i=at()(\"iterator\");t.exports=function(e){if(!a(e))return r(e,i)||r(e,\"@@iterator\")||o[n(e)]}})),gn=se((function(e,t){var n=Se(),r=Ye(),a=ft(),o=We(),i=hn(),l=TypeError;t.exports=function(e,t){if(t=arguments.length<2?i(e):t,r(t))return a(n(t,e));throw new l(o(e)+\" is not iterable\")}})),vn=se((function(e,t){var n=dt(),r=Se(),a=tt(),o=cn(),i=dn(),l=fn(),u=Rt(),s=mn(),c=gn(),d=hn(),p=Array;t.exports=function(e){var t,f,m,h,g,v,b,y=a(e\\\n),D=(e=l(this),1<(b=arguments.length)?arguments[1]:void 0),w=void 0!==D,x=0;if(!(b=(w&&(D=n(D,2<b?arguments[2]:void 0)),d(y)))||this===p&&i(b))for(t=u(y),f=e?new this(t):p(t);x<t;x++)v=w?D(y[x],x):y[x],s(f,x,v);else for(f=e?new this:[],g=(h=c(y,b)).next;!(m=r(g,h)).done;x++)v=w?o(h,D,[m.value,x],!0):m.value,s(f,x,v);return f.length=x,f}})),bn=se((function(e,t){var n,r,a=at()(\"iterator\"),o=!1;try{n=0,(r={next:function(){return{done:!!n++}},return:function(){o=!0}})[a]=function(){return this},Array.from(r,(function(){throw 2}))}catch(e){}t.exports=function(e,t){try{if(!t&&!o)return!1}catch(e){return!1}var n=!1;try{var r={};r[a]=function(){return{next:function(){return{done:n=!0}}}},e(r)}catch(e){}return n}})),yn=se((function(){var e=gt(),t=vn();e({target:\"Array\",stat:!0,forced:!bn()((function(e){Array.from(e)}))},{from:t})})),Dn=se((function(e,t){un(),yn();var n=Le();t.exports=n.Array.from})),wn=se((function(e,t){var n=Dn();t.exports=n})),xn=se((function(e,t){var n=wn();t.exports=n})),En\\\n=se((function(e){Object.defineProperty(e,\"__esModule\",{value:!0}),e.isIdentStart=function(e){return\"a\"<=e&&e<=\"z\"||\"A\"<=e&&e<=\"Z\"||\"-\"===e||\"_\"===e},e.isIdent=function(e){return\"a\"<=e&&e<=\"z\"||\"A\"<=e&&e<=\"Z\"||\"0\"<=e&&e<=\"9\"||\"-\"===e||\"_\"===e},e.isHex=function(e){return\"a\"<=e&&e<=\"f\"||\"A\"<=e&&e<=\"F\"||\"0\"<=e&&e<=\"9\"},e.escapeIdentifier=function(t){for(var n=t.length,r=\"\",a=0;a<n;){var o=t.charAt(a);if(e.identSpecialChars[o])r+=\"\\\\\\\\\"+o;else if(\"_\"===o||\"-\"===o||\"A\"<=o&&o<=\"Z\"||\"a\"<=o&&o<=\"z\"||0!==a&&\"0\"<=o&&o<=\"9\")r+=o;else{if(55296==(63488&(o=o.charCodeAt(0)))){var i=t.charCodeAt(a++);if(55296!=(64512&o)||56320!=(64512&i))throw Error(\"UCS-2(decode): illegal sequence\");o=((1023&o)<<10)+(1023&i)+65536}r+=\"\\\\\\\\\"+o.toString(16)+\" \"}a++}return r},e.escapeStr=function(t){for(var n,r=t.length,a=\"\",o=0;o<r;){var i=t.charAt(o);'\"'===i?i='\\\\\\\\\"':\"\\\\\\\\\"===i?i=\"\\\\\\\\\\\\\\\\\":void 0!==(n=e.strReplacementsRev[i])&&(i=n),a+=i,o++}return'\"'+a+'\"'},e.identSpecialChars={\"!\":!0,'\"':!0,\"#\":!0,$:!0,\"%\":!0,\"&\":!0,\"'\":!0,\"(\"\\\n:!0,\")\":!0,\"*\":!0,\"+\":!0,\",\":!0,\".\":!0,\"/\":!0,\";\":!0,\"<\":!0,\"=\":!0,\">\":!0,\"?\":!0,\"@\":!0,\"[\":!0,\"\\\\\\\\\":!0,\"]\":!0,\"^\":!0,\"\\`\":!0,\"{\":!0,\"|\":!0,\"}\":!0,\"~\":!0},e.strReplacementsRev={\"\\\\n\":\"\\\\\\\\n\",\"\\\\r\":\"\\\\\\\\r\",\"\\\\t\":\"\\\\\\\\t\",\"\\\\f\":\"\\\\\\\\f\",\"\\\\v\":\"\\\\\\\\v\"},e.singleQuoteEscapeChars={n:\"\\\\n\",r:\"\\\\r\",t:\"\\\\t\",f:\"\\\\f\",\"\\\\\\\\\":\"\\\\\\\\\",\"'\":\"'\"},e.doubleQuotesEscapeChars={n:\"\\\\n\",r:\"\\\\r\",t:\"\\\\t\",f:\"\\\\f\",\"\\\\\\\\\":\"\\\\\\\\\",'\"':'\"'}})),An=se((function(e){Object.defineProperty(e,\"__esModule\",{value:!0});var t=En();e.parseCssSelector=function(e,n,r,a,o,i){var l=e.length,u=\"\";function s(r,a){var o=\"\";for(n++,u=e.charAt(n);n<l;){if(u===r)return n++,o;var i;if(\"\\\\\\\\\"===u)if(n++,(u=e.charAt(n))===r)o+=r;else if(void 0!==(i=a[u]))o+=i;else{if(t.isHex(u)){var s=u;for(n++,u=e.charAt(n);t.isHex(u);)s+=u,n++,u=e.charAt(n);\" \"===u&&(n++,u=e.charAt(n)),o+=String.fromCharCode(parseInt(s,16));continue}o+=u}else o+=u;n++,u=e.charAt(n)}return o}function c(){var r=\"\";for(u=e.charAt(n);n<l;){if(!t.isIdent(u)){if(\"\\\\\\\\\"!==u)return r;if(l<=++n)throw Error(\"Expected sy\\\nmbol but end of file reached.\");if(u=e.charAt(n),!t.identSpecialChars[u]&&t.isHex(u)){var a=u;for(n++,u=e.charAt(n);t.isHex(u);)a+=u,n++,u=e.charAt(n);\" \"===u&&(n++,u=e.charAt(n)),r+=String.fromCharCode(parseInt(a,16));continue}}r+=u,n++,u=e.charAt(n)}return r}function d(){for(u=e.charAt(n);\" \"===u||\"\\\\t\"===u||\"\\\\n\"===u||\"\\\\r\"===u||\"\\\\f\"===u;)n++,u=e.charAt(n)}function p(){var t=f();if(!t)return null;var r=t;for(u=e.charAt(n);\",\"===u;){if(n++,d(),\"selectors\"!==r.type&&(r={type:\"selectors\",selectors:[t]}),!(t=f()))throw Error('Rule expected after \",\".');r.selectors.push(t)}return r}function f(){d();var t={type:\"ruleSet\"},r=m();if(!r)return null;for(var a=t;r&&(r.type=\"rule\",a.rule=r,a=r,d(),u=e.charAt(n),!(l<=n||\",\"===u||\")\"===u));)if(o[u]){var i=u;if(n++,d(),!(r=m()))throw Error('Rule expected after \"'+i+'\".');r.nestingOperator=i}else(r=m())&&(r.nestingOperator=null);return t}function m(){for(var o=null;n<l;)if(\"*\"===(u=e.charAt(n)))n++,(o=o||{}).tagName=\"*\";else if(t.isIdentStart(u)||\"\\\\\\\\\"\\\n===u)(o=o||{}).tagName=c();else if(\".\"===u)n++,((o=o||{}).classNames=o.classNames||[]).push(c());else if(\"#\"===u)n++,(o=o||{}).id=c();else if(\"[\"===u){n++,d();var f={name:c()};if(d(),\"]\"===u)n++;else{var m=\"\";if(a[u]&&(m=u,n++,u=e.charAt(n)),l<=n)throw Error('Expected \"=\" but end of file reached.');if(\"=\"!==u)throw Error('Expected \"=\" but \"'+u+'\" found.');f.operator=m+\"=\",n++,d();var h=\"\";if(f.valueType=\"string\",'\"'===u)h=s('\"',t.doubleQuotesEscapeChars);else if(\"'\"===u)h=s(\"'\",t.singleQuoteEscapeChars);else if(i&&\"$\"===u)n++,h=c(),f.valueType=\"substitute\";else{for(;n<l&&\"]\"!==u;)h+=u,n++,u=e.charAt(n);h=h.trim()}if(d(),l<=n)throw Error('Expected \"]\" but end of file reached.');if(\"]\"!==u)throw Error('Expected \"]\" but \"'+u+'\" found.');n++,f.value=h}((o=o||{}).attrs=o.attrs||[]).push(f)}else{if(\":\"!==u)break;if(n++,f={name:m=c()},\"(\"===u){n++;var g=\"\";if(d(),\"selector\"===r[m])f.valueType=\"selector\",g=p();else{if(f.valueType=r[m]||\"string\",'\"'===u)g=s('\"',t.doubleQuotesEscapeChars);else i\\\nf(\"'\"===u)g=s(\"'\",t.singleQuoteEscapeChars);else if(i&&\"$\"===u)n++,g=c(),f.valueType=\"substitute\";else{for(;n<l&&\")\"!==u;)g+=u,n++,u=e.charAt(n);g=g.trim()}d()}if(l<=n)throw Error('Expected \")\" but end of file reached.');if(\")\"!==u)throw Error('Expected \")\" but \"'+u+'\" found.');n++,f.value=g}((o=o||{}).pseudos=o.pseudos||[]).push(f)}return o}var h=p();if(n<l)throw Error('Rule expected but \"'+e.charAt(n)+'\" found.');return h}})),Fn=se((function(e){Object.defineProperty(e,\"__esModule\",{value:!0});var t=En();e.renderEntity=function e(n){var r=\"\";switch(n.type){case\"ruleSet\":for(var a=n.rule,o=[];a;)a.nestingOperator&&o.push(a.nestingOperator),o.push(e(a)),a=a.rule;r=o.join(\" \");break;case\"selectors\":r=n.selectors.map(e).join(\", \");break;case\"rule\":n.tagName&&(r=\"*\"===n.tagName?\"*\":t.escapeIdentifier(n.tagName)),n.id&&(r+=\"#\"+t.escapeIdentifier(n.id)),n.classNames&&(r+=n.classNames.map((function(e){return\".\"+t.escapeIdentifier(e)})).join(\"\")),n.attrs&&(r+=n.attrs.map((function(e){return\"op\\\nerator\"in e?\"substitute\"===e.valueType?\"[\"+t.escapeIdentifier(e.name)+e.operator+\"$\"+e.value+\"]\":\"[\"+t.escapeIdentifier(e.name)+e.operator+t.escapeStr(e.value)+\"]\":\"[\"+t.escapeIdentifier(e.name)+\"]\"})).join(\"\")),n.pseudos&&(r+=n.pseudos.map((function(n){return n.valueType?\"selector\"===n.valueType?\":\"+t.escapeIdentifier(n.name)+\"(\"+e(n.value)+\")\":\"substitute\"===n.valueType?\":\"+t.escapeIdentifier(n.name)+\"($\"+n.value+\")\":\"numeric\"===n.valueType?\":\"+t.escapeIdentifier(n.name)+\"(\"+n.value+\")\":\":\"+t.escapeIdentifier(n.name)+\"(\"+t.escapeIdentifier(n.value)+\")\":\":\"+t.escapeIdentifier(n.name)})).join(\"\"));break;default:throw Error('Unknown entity type: \"'+n.type+'\".')}return r}})),Cn=se((function(e){Object.defineProperty(e,\"__esModule\",{value:!0});var t=An(),n=Fn();function r(){this.pseudos={},this.attrEqualityMods={},this.ruleNestingOperators={},this.substitutesEnabled=!1}r.prototype.registerSelectorPseudos=function(){for(var e=[],t=0;t<arguments.length;t++)e[t]=arguments[t];for(var n=0,r=e;n\\\n<r.length;n++)this.pseudos[r[n]]=\"selector\";return this},r.prototype.unregisterSelectorPseudos=function(){for(var e=[],t=0;t<arguments.length;t++)e[t]=arguments[t];for(var n=0,r=e;n<r.length;n++)delete this.pseudos[r[n]];return this},r.prototype.registerNumericPseudos=function(){for(var e=[],t=0;t<arguments.length;t++)e[t]=arguments[t];for(var n=0,r=e;n<r.length;n++)this.pseudos[r[n]]=\"numeric\";return this},r.prototype.unregisterNumericPseudos=function(){for(var e=[],t=0;t<arguments.length;t++)e[t]=arguments[t];for(var n=0,r=e;n<r.length;n++)delete this.pseudos[r[n]];return this},r.prototype.registerNestingOperators=function(){for(var e=[],t=0;t<arguments.length;t++)e[t]=arguments[t];for(var n=0,r=e;n<r.length;n++)this.ruleNestingOperators[r[n]]=!0;return this},r.prototype.unregisterNestingOperators=function(){for(var e=[],t=0;t<arguments.length;t++)e[t]=arguments[t];for(var n=0,r=e;n<r.length;n++)delete this.ruleNestingOperators[r[n]];return this},r.prototype.registerAttrEqualityMods=\\\nfunction(){for(var e=[],t=0;t<arguments.length;t++)e[t]=arguments[t];for(var n=0,r=e;n<r.length;n++)this.attrEqualityMods[r[n]]=!0;return this},r.prototype.unregisterAttrEqualityMods=function(){for(var e=[],t=0;t<arguments.length;t++)e[t]=arguments[t];for(var n=0,r=e;n<r.length;n++)delete this.attrEqualityMods[r[n]];return this},r.prototype.enableSubstitutes=function(){return this.substitutesEnabled=!0,this},r.prototype.disableSubstitutes=function(){return this.substitutesEnabled=!1,this},r.prototype.parse=function(e){return t.parseCssSelector(e,0,this.pseudos,this.attrEqualityMods,this.ruleNestingOperators,this.substitutesEnabled)},r.prototype.render=function(e){return n.renderEntity(e).trim()},e.CssSelectorParser=r})),kn=se((function(e,r){var o={name:\"doT\",version:\"1.1.1\",templateSettings:{evaluate:/\\\\{\\\\{([\\\\s\\\\S]+?(\\\\}?)+)\\\\}\\\\}/g,interpolate:/\\\\{\\\\{=([\\\\s\\\\S]+?)\\\\}\\\\}/g,encode:/\\\\{\\\\{!([\\\\s\\\\S]+?)\\\\}\\\\}/g,use:/\\\\{\\\\{#([\\\\s\\\\S]+?)\\\\}\\\\}/g,useParams:/(^|[^\\\\w$])def(?:\\\\.|\\\\[[\\\\'\\\\\"])([\\\\w$\\\\.]+)(?:[\\\\'\\\\\"]\\\\])?\\\\s*\\\\:\\\\\\\ns*([\\\\w$\\\\.]+|\\\\\"[^\\\\\"]+\\\\\"|\\\\'[^\\\\']+\\\\'|\\\\{[^\\\\}]+\\\\})/g,define:/\\\\{\\\\{##\\\\s*([\\\\w\\\\.$]+)\\\\s*(\\\\:|=)([\\\\s\\\\S]+?)#\\\\}\\\\}/g,defineParams:/^\\\\s*([\\\\w$]+):([\\\\s\\\\S]+)/,conditional:/\\\\{\\\\{\\\\?(\\\\?)?\\\\s*([\\\\s\\\\S]*?)\\\\s*\\\\}\\\\}/g,iterate:/\\\\{\\\\{~\\\\s*(?:\\\\}\\\\}|([\\\\s\\\\S]+?)\\\\s*\\\\:\\\\s*([\\\\w$]+)\\\\s*(?:\\\\:\\\\s*([\\\\w$]+))?\\\\s*\\\\}\\\\})/g,varname:\"it\",strip:!0,append:!0,selfcontained:!1,doNotSkipEncoded:!1},template:void 0,compile:void 0,log:!0};if(\"object\"!==(\"undefined\"==typeof globalThis?\"undefined\":a(globalThis)))try{Object.defineProperty(Object.prototype,\"__magic__\",{get:function(){return this},configurable:!0}),__magic__.globalThis=__magic__,delete Object.prototype.__magic__}catch(e){t.globalThis=function(){if(\"undefined\"!=typeof self)return self;if(void 0!==t)return t;if(void 0!==n)return n;if(void 0!==this)return this;throw new Error(\"Unable to locate global \\`this\\`\")}()}o.encodeHTMLSource=function(e){var t={\"&\":\"&#38;\",\"<\":\"&#60;\",\">\":\"&#62;\",'\"':\"&#34;\",\"'\":\"&#39;\",\"/\":\"&#47;\"},n=e?/[&<>\"'\\\\/]/g:/&(?!#?\\\\w+;)|<|>|\"|'|\\\\//g;return function(e){return \\\ne?e.toString().replace(n,(function(e){return t[e]||e})):\"\"}},void 0!==r&&r.exports?r.exports=o:\"function\"==typeof define&&define.amd?define((function(){return o})):globalThis.doT=o;var i={append:{start:\"'+(\",end:\")+'\",startencode:\"'+encodeHTML(\"},split:{start:\"';out+=(\",end:\");out+='\",startencode:\"';out+=encodeHTML(\"}},l=/$^/;function u(e){return e.replace(/\\\\\\\\('|\\\\\\\\)/g,\"$1\").replace(/[\\\\r\\\\t\\\\n]/g,\" \")}o.template=function(e,t,n){var r,a,s=(t=t||o.templateSettings).append?i.append:i.split,c=0;n=t.use||t.define?function e(t,n,r){return(\"string\"==typeof n?n:n.toString()).replace(t.define||l,(function(e,n,a,o){return(n=0===n.indexOf(\"def.\")?n.substring(4):n)in r||(\":\"===a?(t.defineParams&&o.replace(t.defineParams,(function(e,t,a){r[n]={arg:t,text:a}})),n in r||(r[n]=o)):new Function(\"def\",\"def['\"+n+\"']=\"+o)(r)),\"\"})).replace(t.use||l,(function(n,a){return t.useParams&&(a=a.replace(t.useParams,(function(e,t,n,a){var o;if(r[n]&&r[n].arg&&a)return o=(n+\":\"+a).replace(/'|\\\\\\\\/g,\"_\"),r.__exp=r.__exp|\\\n|{},r.__exp[o]=r[n].text.replace(new RegExp(\"(^|[^\\\\\\\\w$])\"+r[n].arg+\"([^\\\\\\\\w$])\",\"g\"),\"$1\"+a+\"$2\"),t+\"def.__exp['\"+o+\"']\"}))),(a=new Function(\"def\",\"return \"+a)(r))&&e(t,a,r)}))}(t,e,n||{}):e,n=(\"var out='\"+(t.strip?n.replace(/(^|\\\\r|\\\\n)\\\\t* +| +\\\\t*(\\\\r|\\\\n|$)/g,\" \").replace(/\\\\r|\\\\n|\\\\t|\\\\/\\\\*[\\\\s\\\\S]*?\\\\*\\\\//g,\"\"):n).replace(/'|\\\\\\\\/g,\"\\\\\\\\$&\").replace(t.interpolate||l,(function(e,t){return s.start+u(t)+s.end})).replace(t.encode||l,(function(e,t){return r=!0,s.startencode+u(t)+s.end})).replace(t.conditional||l,(function(e,t,n){return t?n?\"';}else if(\"+u(n)+\"){out+='\":\"';}else{out+='\":n?\"';if(\"+u(n)+\"){out+='\":\"';}out+='\"})).replace(t.iterate||l,(function(e,t,n,r){return t?(c+=1,a=r||\"i\"+c,t=u(t),\"';var arr\"+c+\"=\"+t+\";if(arr\"+c+\"){var \"+n+\",\"+a+\"=-1,l\"+c+\"=arr\"+c+\".length-1;while(\"+a+\"<l\"+c+\"){\"+n+\"=arr\"+c+\"[\"+a+\"+=1];out+='\"):\"';} } out+='\"})).replace(t.evaluate||l,(function(e,t){return\"';\"+u(t)+\"out+='\"}))+\"';return out;\").replace(/\\\\n/g,\"\\\\\\\\n\").replace(/\\\\t/g,\"\\\\\\\\t\").replace(/\\\\r/g,\"\\\\\\\\r\").replace(/(\\\\s|;|\\\\\\\n}|^|\\\\{)out\\\\+='';/g,\"$1\").replace(/\\\\+''/g,\"\");r&&(t.selfcontained||!globalThis||globalThis._encodeHTML||(globalThis._encodeHTML=o.encodeHTMLSource(t.doNotSkipEncoded)),n=\"var encodeHTML = typeof _encodeHTML !== 'undefined' ? _encodeHTML : (\"+o.encodeHTMLSource.toString()+\"(\"+(t.doNotSkipEncoded||\"\")+\"));\"+n);try{return new Function(t.varname,n)}catch(e){throw\"undefined\"!=typeof console&&console.log(\"Could not create a template function: \"+n),e}},o.compile=function(e,t){return o.template(e,null,t)}})),Rn=se((function(e,t){t.exports=function(){}})),Nn=se((function(e,t){var n=Rn()();t.exports=function(e){return e!==n&&null!==e}})),Tn=se((function(e,t){var n=Nn(),r=Array.prototype.forEach,a=Object.create;t.exports=function(e){var t=a(null);return r.call(arguments,(function(e){if(n(e)){var r,a=Object(e),o=t;for(r in a)o[r]=a[r]}})),t}})),Sn=se((function(e,t){t.exports=function(){var e=Math.sign;return\"function\"==typeof e&&1===e(10)&&-1===e(-20)}})),_n=se((function(e,t){t.exports=function(e){\\\nreturn e=Number(e),isNaN(e)||0===e?e:0<e?1:-1}})),On=se((function(e,t){t.exports=Sn()()?Math.sign:_n()})),Mn=se((function(e,t){var n=On(),r=Math.abs,a=Math.floor;t.exports=function(e){return isNaN(e)?0:0!==(e=Number(e))&&isFinite(e)?n(e)*a(r(e)):e}})),Pn=se((function(e,t){var n=Mn(),r=Math.max;t.exports=function(e){return r(0,n(e))}})),In=se((function(e,t){var n=Pn();t.exports=function(e,t,r){return isNaN(e)?0<=t?r&&t?t-1:t:1:!1!==e&&n(e)}})),Bn=se((function(e,t){t.exports=function(e){if(\"function\"!=typeof e)throw new TypeError(e+\" is not a function\");return e}})),jn=se((function(e,t){var n=Nn();t.exports=function(e){if(n(e))return e;throw new TypeError(\"Cannot use null or undefined\")}})),Ln=se((function(e,t){var n=Bn(),r=jn(),a=Function.prototype.bind,o=Function.prototype.call,i=Object.keys,l=Object.prototype.propertyIsEnumerable;t.exports=function(e,t){return function(u,s){var c,d=arguments[2],p=arguments[3];return u=Object(r(u)),n(s),c=i(u),p&&c.sort(\"function\"==typeof p?a.call(p,u)\\\n:void 0),\"function\"!=typeof e&&(e=c[e]),o.call(e,c,(function(e,n){return l.call(u,e)?o.call(s,d,u[e],e,u,n):t}))}}})),qn=se((function(e,t){t.exports=Ln()(\"forEach\")})),zn=se((function(){})),Vn=se((function(e,t){t.exports=function(){var e=Object.assign;return\"function\"==typeof e&&(e(e={foo:\"raz\"},{bar:\"dwa\"},{trzy:\"trzy\"}),e.foo+e.bar+e.trzy===\"razdwatrzy\")}})),Gn=se((function(e,t){t.exports=function(){try{return Object.keys(\"primitive\"),!0}catch(e){return!1}}})),$n=se((function(e,t){var n=Nn(),r=Object.keys;t.exports=function(e){return r(n(e)?Object(e):e)}})),Hn=se((function(e,t){t.exports=Gn()()?Object.keys:$n()})),Un=se((function(e,t){var n=Hn(),r=jn(),a=Math.max;t.exports=function(e,t){var o,i,l,u=a(arguments.length,2);for(e=Object(r(e)),l=function(n){try{e[n]=t[n]}catch(n){o=o||n}},i=1;i<u;++i)n(t=arguments[i]).forEach(l);if(void 0!==o)throw o;return e}})),Wn=se((function(e,t){t.exports=Vn()()?Object.assign:Un()})),Yn=se((function(e,t){var n=Nn(),r={function:!0,object:!0};t.exports\\\n=function(e){return n(e)&&r[a(e)]||!1}})),Kn=se((function(e,t){var n=Wn(),r=Yn(),a=Nn(),o=Error.captureStackTrace;t.exports=function(e){e=new Error(e);var i=arguments[1],l=arguments[2];return a(l)||r(i)&&(l=i,i=null),a(l)&&n(e,l),a(i)&&(e.code=i),o&&o(e,t.exports),e}})),Xn=se((function(e,t){var n=jn(),r=Object.defineProperty,a=Object.getOwnPropertyDescriptor,o=Object.getOwnPropertyNames,i=Object.getOwnPropertySymbols;t.exports=function(e,t){var l,u=Object(n(t));if(e=Object(n(e)),o(u).forEach((function(n){try{r(e,n,a(t,n))}catch(n){l=n}})),\"function\"==typeof i&&i(u).forEach((function(n){try{r(e,n,a(t,n))}catch(n){l=n}})),void 0!==l)throw l;return e}})),Zn=se((function(e,t){function n(e,t){return t}var r,a,o,i,l,u=Pn();try{Object.defineProperty(n,\"length\",{configurable:!0,writable:!1,enumerable:!1,value:1})}catch(e){}1===n.length?(r={configurable:!0,writable:!1,enumerable:!1},a=Object.defineProperty,t.exports=function(e,t){return t=u(t),e.length===t?e:(r.value=t,a(e,\"length\",r))}):(i=Xn(\\\n),l=[],o=function(e){var t,n=0;if(l[e])return l[e];for(t=[];e--;)t.push(\"a\"+(++n).toString(36));return new Function(\"fn\",\"return function (\"+t.join(\", \")+\") { return fn.apply(this, arguments); };\")},t.exports=function(e,t){if(t=u(t),e.length===t)return e;t=o(t)(e);try{i(t,e)}catch(e){}return t})})),Jn=se((function(e,t){t.exports=function(e){return null!=e}})),Qn=se((function(e,t){var n=Jn(),r={object:!0,function:!0,undefined:!0};t.exports=function(e){return!!n(e)&&hasOwnProperty.call(r,a(e))}})),er=se((function(e,t){var n=Qn();t.exports=function(e){if(!n(e))return!1;try{return!!e.constructor&&e.constructor.prototype===e}catch(e){return!1}}})),tr=se((function(e,t){var n=er();t.exports=function(e){if(\"function\"!=typeof e)return!1;if(!hasOwnProperty.call(e,\"length\"))return!1;try{if(\"number\"!=typeof e.length)return!1;if(\"function\"!=typeof e.call)return!1;if(\"function\"!=typeof e.apply)return!1}catch(e){return!1}return!n(e)}})),nr=se((function(e,t){var n=tr(),r=/^\\\\s*class[\\\\s{/}]/,a=Function.\\\nprototype.toString;t.exports=function(e){return!!n(e)&&!r.test(a.call(e))}})),rr=se((function(e,t){var n=\"razdwatrzy\";t.exports=function(){return\"function\"==typeof n.contains&&!0===n.contains(\"dwa\")&&!1===n.contains(\"foo\")}})),ar=se((function(e,t){var n=String.prototype.indexOf;t.exports=function(e){return-1<n.call(this,e,arguments[1])}})),or=se((function(e,t){t.exports=rr()()?String.prototype.contains:ar()})),ir=se((function(e,t){var n=Jn(),r=nr(),a=Wn(),o=Tn(),i=or();(t.exports=function(e,t){var r,l,u,s;return arguments.length<2||\"string\"!=typeof e?(s=t,t=e,e=null):s=arguments[2],n(e)?(r=i.call(e,\"c\"),l=i.call(e,\"e\"),u=i.call(e,\"w\")):l=!(r=u=!0),e={value:t,configurable:r,enumerable:l,writable:u},s?a(o(s),e):e}).gs=function(e,t,l){var u,s;return\"string\"!=typeof e?(s=l,l=t,t=e,e=null):s=arguments[3],n(t)?r(t)?n(l)?r(l)||(s=l,l=void 0):l=void 0:(s=t,t=l=void 0):t=void 0,e=n(e)?(u=i.call(e,\"c\"),i.call(e,\"e\")):!(u=!0),t={get:t,set:l,configurable:u,enumerable:e},s?a(o(s),t):t}})),lr=se((fu\\\nnction(e,t){var n=ir(),r=Bn(),o=Function.prototype.apply,i=Function.prototype.call,l=Object.create,u=Object.defineProperty,s=Object.defineProperties,c=Object.prototype.hasOwnProperty,d={configurable:!0,enumerable:!1,writable:!0},p=function(e,t){var n;return r(t),c.call(this,\"__ee__\")?n=this.__ee__:(n=d.value=l(null),u(this,\"__ee__\",d),d.value=null),n[e]?\"object\"===a(n[e])?n[e].push(t):n[e]=[n[e],t]:n[e]=t,this},f=function(e,t){var n,a;return r(t),a=this,p.call(this,e,n=function(){m.call(a,e,n),o.call(t,this,arguments)}),n.__eeOnceListener__=t,this},m=function(e,t){var n,o,i,l;if(r(t),c.call(this,\"__ee__\")&&(n=this.__ee__)[e])if(\"object\"===a(o=n[e]))for(l=0;i=o[l];++l)i!==t&&i.__eeOnceListener__!==t||(2===o.length?n[e]=o[l?0:1]:o.splice(l,1));else o!==t&&o.__eeOnceListener__!==t||delete n[e];return this},h=function(e){var t,n,r,l,u;if(c.call(this,\"__ee__\")&&(l=this.__ee__[e]))if(\"object\"===a(l)){for(n=arguments.length,u=new Array(n-1),t=1;t<n;++t)u[t-1]=arguments[t];for(l=l.slice(),t=0;\\\nr=l[t];++t)o.call(r,this,u)}else switch(arguments.length){case 1:i.call(l,this);break;case 2:i.call(l,this,arguments[1]);break;case 3:i.call(l,this,arguments[1],arguments[2]);break;default:for(n=arguments.length,u=new Array(n-1),t=1;t<n;++t)u[t-1]=arguments[t];o.call(l,this,u)}},g={on:p,once:f,off:m,emit:h},v={on:n(p),once:n(f),off:n(m),emit:n(h)},b=s({},v);t.exports=e=function(e){return null==e?l(b):s(Object(e),v)},e.methods=g})),ur=se((function(e,t){t.exports=function(){var e,t=Array.from;return\"function\"==typeof t&&(e=t(t=[\"raz\",\"dwa\"]),Boolean(e&&e!==t&&\"dwa\"===e[1]))}})),sr=se((function(e,t){t.exports=function(){return\"object\"===(\"undefined\"==typeof globalThis?\"undefined\":a(globalThis))&&!!globalThis&&globalThis.Array===Array}})),cr=se((function(e,n){function r(){if(\"object\"===(\"undefined\"==typeof self?\"undefined\":a(self))&&self)return self;if(\"object\"===(void 0===t?\"undefined\":a(t))&&t)return t;throw new Error(\"Unable to resolve global \\`this\\`\")}n.exports=function(){if(this)return\\\n this;try{Object.defineProperty(Object.prototype,\"__global__\",{get:function(){return this},configurable:!0})}catch(e){return r()}try{return __global__||r()}finally{delete Object.prototype.__global__}}()})),dr=se((function(e,t){t.exports=sr()()?globalThis:cr()})),pr=se((function(e,t){var n=dr(),r={object:!0,symbol:!0};t.exports=function(){var e,t=n.Symbol;if(\"function\"!=typeof t)return!1;e=t(\"test symbol\");try{String(e)}catch(e){return!1}return!!r[a(t.iterator)]&&!!r[a(t.toPrimitive)]&&!!r[a(t.toStringTag)]}})),fr=se((function(e,t){t.exports=function(e){return!!e&&(\"symbol\"===a(e)||!!e.constructor&&\"Symbol\"===e.constructor.name&&\"Symbol\"===e[e.constructor.toStringTag])}})),mr=se((function(e,t){var n=fr();t.exports=function(e){if(n(e))return e;throw new TypeError(e+\" is not a symbol\")}})),hr=se((function(e,t){var n=ir(),r=Object.create,a=Object.defineProperty,o=Object.prototype,i=r(null);t.exports=function(e){for(var t,r,l=0;i[e+(l||\"\")];)++l;return i[e+=l||\"\"]=!0,a(o,t=\"@@\"+e,n.gs(null,\\\n(function(e){r||(r=!0,a(this,t,n(e)),r=!1)}))),t}})),gr=se((function(e,t){var n=ir(),r=dr().Symbol;t.exports=function(e){return Object.defineProperties(e,{hasInstance:n(\"\",r&&r.hasInstance||e(\"hasInstance\")),isConcatSpreadable:n(\"\",r&&r.isConcatSpreadable||e(\"isConcatSpreadable\")),iterator:n(\"\",r&&r.iterator||e(\"iterator\")),match:n(\"\",r&&r.match||e(\"match\")),replace:n(\"\",r&&r.replace||e(\"replace\")),search:n(\"\",r&&r.search||e(\"search\")),species:n(\"\",r&&r.species||e(\"species\")),split:n(\"\",r&&r.split||e(\"split\")),toPrimitive:n(\"\",r&&r.toPrimitive||e(\"toPrimitive\")),toStringTag:n(\"\",r&&r.toStringTag||e(\"toStringTag\")),unscopables:n(\"\",r&&r.unscopables||e(\"unscopables\"))})}})),vr=se((function(e,t){var n=ir(),r=mr(),a=Object.create(null);t.exports=function(e){return Object.defineProperties(e,{for:n((function(t){return a[t]||(a[t]=e(String(t)))})),keyFor:n((function(e){for(var t in r(e),a)if(a[t]===e)return t}))})}})),br=se((function(e,t){var n,r,o,i=ir(),l=mr(),u=dr().Symbol,s=hr(),c=gr(),d=\\\nvr(),p=Object.create,f=Object.defineProperties,m=Object.defineProperty;if(\"function\"==typeof u)try{String(u()),o=!0}catch(e){}else u=null;r=function(e){if(this instanceof r)throw new TypeError(\"Symbol is not a constructor\");return n(e)},t.exports=n=function e(t){var n;if(this instanceof e)throw new TypeError(\"Symbol is not a constructor\");return o?u(t):(n=p(r.prototype),t=void 0===t?\"\":String(t),f(n,{__description__:i(\"\",t),__name__:i(\"\",s(t))}))},c(n),d(n),f(r.prototype,{constructor:i(n),toString:i(\"\",(function(){return this.__name__}))}),f(n.prototype,{toString:i((function(){return\"Symbol (\"+l(this).__description__+\")\"})),valueOf:i((function(){return l(this)}))}),m(n.prototype,n.toPrimitive,i(\"\",(function(){var e=l(this);return\"symbol\"===a(e)?e:e.toString()}))),m(n.prototype,n.toStringTag,i(\"c\",\"Symbol\")),m(r.prototype,n.toStringTag,i(\"c\",n.prototype[n.toStringTag])),m(r.prototype,n.toPrimitive,i(\"c\",n.prototype[n.toPrimitive]))})),yr=se((function(e,t){t.exports=pr()()?dr().Symbol:br\\\n()})),Dr=se((function(e,t){var n=Object.prototype.toString,r=n.call(function(){return arguments}());t.exports=function(e){return n.call(e)===r}})),wr=se((function(e,t){var n=Object.prototype.toString,r=RegExp.prototype.test.bind(/^[object [A-Za-z0-9]*Function]$/);t.exports=function(e){return\"function\"==typeof e&&r(n.call(e))}})),xr=se((function(e,t){var n=Object.prototype.toString,r=n.call(\"\");t.exports=function(e){return\"string\"==typeof e||e&&\"object\"===a(e)&&(e instanceof String||n.call(e)===r)||!1}})),Er=se((function(e,t){var n=yr().iterator,r=Dr(),a=wr(),o=Pn(),i=Bn(),l=jn(),u=Nn(),s=xr(),c=Array.isArray,d=Function.prototype.call,p={configurable:!0,enumerable:!0,writable:!0,value:null},f=Object.defineProperty;t.exports=function(e){var t,m,h,g,v,b,y,D,w,x,E=arguments[1],A=arguments[2];if(e=Object(l(e)),u(E)&&i(E),this&&this!==Array&&a(this))t=this;else{if(!E){if(r(e))return 1!==(v=e.length)?Array.apply(null,e):((g=new Array(1))[0]=e[0],g);if(c(e)){for(g=new Array(v=e.length),m=0;m<v\\\n;++m)g[m]=e[m];return g}}g=[]}if(!c(e))if(void 0!==(w=e[n])){for(y=i(w).call(e),t&&(g=new t),D=y.next(),m=0;!D.done;)x=E?d.call(E,A,D.value,m):D.value,t?(p.value=x,f(g,m,p)):g[m]=x,D=y.next(),++m;v=m}else if(s(e)){for(v=e.length,t&&(g=new t),h=m=0;m<v;++m)x=e[m],m+1<v&&55296<=(b=x.charCodeAt(0))&&b<=56319&&(x+=e[++m]),x=E?d.call(E,A,x,h):x,t?(p.value=x,f(g,h,p)):g[h]=x,++h;v=h}if(void 0===v)for(v=o(e.length),t&&(g=new t(v)),m=0;m<v;++m)x=E?d.call(E,A,e[m],m):e[m],t?(p.value=x,f(g,m,p)):g[m]=x;return t&&(p.value=null,g.length=v),g}})),Ar=se((function(e,t){t.exports=ur()()?Array.from:Er()})),Fr=se((function(e,t){var n=Ar(),r=Array.isArray;t.exports=function(e){return r(e)?e:n(e)}})),Cr=se((function(e,t){var n=Fr(),r=Nn(),a=Bn(),o=Array.prototype.slice,i=function(e){return this.map((function(t,n){return t?t(e[n]):e[n]})).concat(o.call(e,this.length))};t.exports=function(e){return(e=n(e)).forEach((function(e){r(e)&&a(e)})),i.bind(e)}})),kr=se((function(e,t){var n=Bn();t.exports=function(e)\\\n{var t;return\"function\"==typeof e?{set:e,get:e}:(t={get:n(e.get)},void 0!==e.set?(t.set=n(e.set),e.delete&&(t.delete=n(e.delete)),e.clear&&(t.clear=n(e.clear))):t.set=t.get,t)}})),Rr=se((function(e,t){var n=Kn(),r=Zn(),a=ir(),o=lr().methods,i=Cr(),l=kr(),u=Function.prototype.apply,s=Function.prototype.call,c=Object.create,d=Object.defineProperties,p=o.on,f=o.emit;t.exports=function(e,t,o){var m,h,g,v,b,y,D,w,x,E,A,F=c(null),C=!1!==t?t:isNaN(e.length)?1:e.length;return o.normalizer&&(E=l(o.normalizer),h=E.get,g=E.set,v=E.delete,b=E.clear),null!=o.resolvers&&(A=i(o.resolvers)),E=h?r((function(t){var r,a,o=arguments;if(A&&(o=A(o)),null!==(r=h(o))&&hasOwnProperty.call(F,r))return D&&m.emit(\"get\",r,o,this),F[r];if(a=1===o.length?s.call(e,this,o[0]):u.call(e,this,o),null===r){if(null!==(r=h(o)))throw n(\"Circular invocation\",\"CIRCULAR_INVOCATION\");r=g(o)}else if(hasOwnProperty.call(F,r))throw n(\"Circular invocation\",\"CIRCULAR_INVOCATION\");return F[r]=a,w&&m.emit(\"set\",r,null,a),a}),C):0===t?f\\\nunction(){var t;if(hasOwnProperty.call(F,\"data\"))return D&&m.emit(\"get\",\"data\",arguments,this),F.data;if(t=arguments.length?u.call(e,this,arguments):s.call(e,this),hasOwnProperty.call(F,\"data\"))throw n(\"Circular invocation\",\"CIRCULAR_INVOCATION\");return F.data=t,w&&m.emit(\"set\",\"data\",null,t),t}:function(t){var r,a=arguments;if(A&&(a=A(arguments)),r=String(a[0]),hasOwnProperty.call(F,r))return D&&m.emit(\"get\",r,a,this),F[r];if(a=1===a.length?s.call(e,this,a[0]):u.call(e,this,a),hasOwnProperty.call(F,r))throw n(\"Circular invocation\",\"CIRCULAR_INVOCATION\");return F[r]=a,w&&m.emit(\"set\",r,null,a),a},m={original:e,memoized:E,profileName:o.profileName,get:function(e){return A&&(e=A(e)),h?h(e):String(e[0])},has:function(e){return hasOwnProperty.call(F,e)},delete:function(e){var t;hasOwnProperty.call(F,e)&&(v&&v(e),t=F[e],delete F[e],x)&&m.emit(\"delete\",e,t)},clear:function(){var e=F;b&&b(),F=c(null),m.emit(\"clear\",e)},on:function(e,t){return\"get\"===e?D=!0:\"set\"===e?w=!0:\"delete\"===e&&(x=!0),\\\np.call(this,e,t)},emit:f,updateEnv:function(){e=m.original}},o=h?r((function(e){var t=arguments;A&&(t=A(t)),null!==(t=h(t))&&m.delete(t)}),C):0===t?function(){return m.delete(\"data\")}:function(e){return A&&(e=A(arguments)[0]),m.delete(e)},C=r((function(){var e=arguments;return 0===t?F.data:(A&&(e=A(e)),e=h?h(e):String(e[0]),F[e])})),y=r((function(){var e=arguments;return 0===t?m.has(\"data\"):(A&&(e=A(e)),null!==(e=h?h(e):String(e[0]))&&m.has(e))})),d(E,{__memoized__:a(!0),delete:a(o),clear:a(m.clear),_get:a(C),_has:a(y)}),m}})),Nr=se((function(e,t){var n=Bn(),r=qn(),a=zn(),o=Rr(),i=In();t.exports=function e(t){var l,u,s;if(n(t),(l=Object(arguments[1])).async&&l.promise)throw new Error(\"Options 'async' and 'promise' cannot be used together\");return hasOwnProperty.call(t,\"__memoized__\")&&!l.force?t:(u=i(l.length,t.length,l.async&&a.async),s=o(t,u,l),r(a,(function(e,t){l[t]&&e(l[t],s,l)})),e.__profiler__&&e.__profiler__(s),s.updateEnv(),s.memoized)}})),Tr=se((function(e,t){t.exports=functi\\\non(e){var t,n,r=e.length;if(!r)return\"\u0002\";for(t=String(e[n=0]);--r;)t+=\"\u0001\"+e[++n];return t}})),Sr=se((function(e,t){t.exports=function(e){return e?function(t){for(var n=String(t[0]),r=0,a=e;--a;)n+=\"\u0001\"+t[++r];return n}:function(){return\"\"}}})),_r=se((function(e,t){t.exports=function(){var e=Number.isNaN;return\"function\"==typeof e&&!e({})&&e(NaN)&&!e(34)}})),Or=se((function(e,t){t.exports=function(e){return e!=e}})),Mr=se((function(e,t){t.exports=_r()()?Number.isNaN:Or()})),Pr=se((function(e,t){var n=Mr(),r=Pn(),a=jn(),o=Array.prototype.indexOf,i=Object.prototype.hasOwnProperty,l=Math.abs,u=Math.floor;t.exports=function(e){var t,s,c;if(!n(e))return o.apply(this,arguments);for(s=r(a(this).length),e=arguments[1],t=e=isNaN(e)?0:0<=e?u(e):r(this.length)-u(l(e));t<s;++t)if(i.call(this,t)&&(c=this[t],n(c)))return t;return-1}})),Ir=se((function(e,t){var n=Pr(),r=Object.create;t.exports=function(){var e=0,t=[],a=r(null);return{get:function(e){var r,a=0,o=t,i=e.length;if(0===i)return o[i]||null;i\\\nf(o=o[i]){for(;a<i-1;){if(-1===(r=n.call(o[0],e[a])))return null;o=o[1][r],++a}return-1===(r=n.call(o[0],e[a]))?null:o[1][r]||null}return null},set:function(r){var o,i=0,l=t,u=r.length;if(0===u)l[u]=++e;else{for(l[u]||(l[u]=[[],[]]),l=l[u];i<u-1;)-1===(o=n.call(l[0],r[i]))&&(o=l[0].push(r[i])-1,l[1].push([[],[]])),l=l[1][o],++i;-1===(o=n.call(l[0],r[i]))&&(o=l[0].push(r[i])-1),l[1][o]=++e}return a[e]=r,e},delete:function(e){var r,o=0,i=t,l=a[e],u=l.length,s=[];if(0===u)delete i[u];else if(i=i[u]){for(;o<u-1;){if(-1===(r=n.call(i[0],l[o])))return;s.push(i,r),i=i[1][r],++o}if(-1===(r=n.call(i[0],l[o])))return;for(e=i[1][r],i[0].splice(r,1),i[1].splice(r,1);!i[0].length&&s.length;)r=s.pop(),(i=s.pop())[0].splice(r,1),i[1].splice(r,1)}delete a[e]},clear:function(){t=[],a=r(null)}}}})),Br=se((function(e,t){var n=Pr();t.exports=function(){var e=0,t=[],r=[];return{get:function(e){return-1===(e=n.call(t,e[0]))?null:r[e]},set:function(n){return t.push(n[0]),r.push(++e),e},delete:function(e){-1!\\\n==(e=n.call(r,e))&&(t.splice(e,1),r.splice(e,1))},clear:function(){t=[],r=[]}}}})),jr=se((function(e,t){var n=Pr(),r=Object.create;t.exports=function(e){var t=0,a=[[],[]],o=r(null);return{get:function(t){for(var r,o=0,i=a;o<e-1;){if(-1===(r=n.call(i[0],t[o])))return null;i=i[1][r],++o}return-1!==(r=n.call(i[0],t[o]))&&i[1][r]||null},set:function(r){for(var i,l=0,u=a;l<e-1;)-1===(i=n.call(u[0],r[l]))&&(i=u[0].push(r[l])-1,u[1].push([[],[]])),u=u[1][i],++l;return-1===(i=n.call(u[0],r[l]))&&(i=u[0].push(r[l])-1),u[1][i]=++t,o[t]=r,t},delete:function(t){for(var r,i=0,l=a,u=[],s=o[t];i<e-1;){if(-1===(r=n.call(l[0],s[i])))return;u.push(l,r),l=l[1][r],++i}if(-1!==(r=n.call(l[0],s[i]))){for(t=l[1][r],l[0].splice(r,1),l[1].splice(r,1);!l[0].length&&u.length;)r=u.pop(),(l=u.pop())[0].splice(r,1),l[1].splice(r,1);delete o[t]}},clear:function(){a=[[],[]],o=r(null)}}}})),Lr=se((function(e,t){var n=Bn(),r=qn(),a=Function.prototype.call;t.exports=function(e,t){var o={},i=arguments[2];return n(t),r(e,\\\n(function(e,n,r,l){o[n]=a.call(t,i,e,n,r,l)})),o}})),qr=se((function(e,t){function n(e){if(\"function\"!=typeof e)throw new TypeError(e+\" is not a function\");return e}function o(e){var t,a,o=r.createTextNode(\"\"),i=0;return new e((function(){var e;if(t)a&&(t=a.concat(t));else{if(!a)return;t=a}if(a=t,t=null,\"function\"==typeof a)e=a,a=null,e();else for(o.data=i=++i%2;a;)e=a.shift(),a.length||(a=null),e()})).observe(o,{characterData:!0}),function(e){n(e),t?\"function\"==typeof t?t=[t,e]:t.push(e):(t=e,o.data=i=++i%2)}}t.exports=(()=>{if(\"object\"===(\"undefined\"==typeof process?\"undefined\":a(process))&&process&&\"function\"==typeof process.nextTick)return process.nextTick;if(\"function\"==typeof queueMicrotask)return function(e){queueMicrotask(n(e))};if(\"object\"===(void 0===r?\"undefined\":a(r))&&r){if(\"function\"==typeof MutationObserver)return o(MutationObserver);if(\"function\"==typeof WebKitMutationObserver)return o(WebKitMutationObserver)}return\"function\"==typeof setImmediate?function(e){setImmediat\\\ne(n(e))}:\"function\"==typeof setTimeout||\"object\"===(\"undefined\"==typeof setTimeout?\"undefined\":a(setTimeout))?function(e){setTimeout(n(e),0)}:null})()})),zr=se((function(){var e=Ar(),t=Lr(),n=Xn(),r=Zn(),a=qr(),o=Array.prototype.slice,i=Function.prototype.apply,l=Object.create;zn().async=function(u,s){var c,d,p,f=l(null),m=l(null),h=s.memoized,g=s.original;s.memoized=r((function(e){var t=arguments,n=t[t.length-1];return\"function\"==typeof n&&(c=n,t=o.call(t,0,-1)),h.apply(d=this,p=t)}),h);try{n(s.memoized,h)}catch(u){}s.on(\"get\",(function(e){var t,n,r;c&&(f[e]?(\"function\"==typeof f[e]?f[e]=[f[e],c]:f[e].push(c),c=null):(t=c,n=d,r=p,c=d=p=null,a((function(){var a;hasOwnProperty.call(m,e)?(a=m[e],s.emit(\"getasync\",e,r,n),i.call(t,a.context,a.args)):(c=t,d=n,p=r,h.apply(n,r))}))))})),s.original=function(){var t,n,r,o;return c?(t=e(arguments),r=c,c=d=p=null,t.push(n=function t(n){var r,l,u=t.id;if(null==u)a(i.bind(t,this,arguments));else if(delete t.id,r=f[u],delete f[u],r)return l=e(argume\\\nnts),s.has(u)&&(n?s.delete(u):(m[u]={context:this,args:l},s.emit(\"setasync\",u,\"function\"==typeof r?1:r.length))),\"function\"==typeof r?o=i.call(r,this,l):r.forEach((function(e){o=i.call(e,this,l)}),this),o}),o=i.call(g,this,t),n.cb=r,c=n,o):i.call(g,this,arguments)},s.on(\"set\",(function(e){c?(f[e]?\"function\"==typeof f[e]?f[e]=[f[e],c.cb]:f[e].push(c.cb):f[e]=c.cb,delete c.cb,c.id=e,c=null):s.delete(e)})),s.on(\"delete\",(function(e){var t;hasOwnProperty.call(f,e)||m[e]&&(t=m[e],delete m[e],s.emit(\"deleteasync\",e,o.call(t.args,1)))})),s.on(\"clear\",(function(){var e=m;m=l(null),s.emit(\"clearasync\",t(e,(function(e){return o.call(e.args,1)})))}))}})),Vr=se((function(e,t){var n=Array.prototype.forEach,r=Object.create;t.exports=function(e){var t=r(null);return n.call(arguments,(function(e){t[e]=!0})),t}})),Gr=se((function(e,t){t.exports=function(e){return\"function\"==typeof e}})),$r=se((function(e,t){var n=Gr();t.exports=function(e){try{return e&&n(e.toString)?e.toString():String(e)}catch(e){thr\\\now new TypeError(\"Passed argument cannot be stringifed\")}}})),Hr=se((function(e,t){var n=jn(),r=$r();t.exports=function(e){return r(n(e))}})),Ur=se((function(e,t){var n=Gr();t.exports=function(e){try{return e&&n(e.toString)?e.toString():String(e)}catch(e){return\"<Non-coercible to string value>\"}}})),Wr=se((function(e,t){var n=Ur(),r=/[\\\\n\\\\r\\\\u2028\\\\u2029]/g;t.exports=function(e){return(e=100<(e=n(e)).length?e.slice(0,99)+\"…\":e).replace(r,(function(e){return JSON.stringify(e).slice(1,-1)}))}})),Yr=se((function(e,t){function n(e){return!!e&&(\"object\"===a(e)||\"function\"==typeof e)&&\"function\"==typeof e.then}t.exports=n,t.exports.default=n})),Kr=se((function(){var e=Lr(),t=Vr(),n=Hr(),r=Wr(),a=Yr(),o=qr(),i=Object.create,l=t(\"then\",\"then:finally\",\"done\",\"done:finally\");zn().promise=function(t,u){var s=i(null),c=i(null),d=i(null);if(!0===t)t=null;else if(t=n(t),!l[t])throw new TypeError(\"'\"+r(t)+\"' is not valid promise mode\");u.on(\"set\",(function(e,n,r){var i=!1;if(a(r)){s[e]=1,d[e]=r;var l=fu\\\nnction(t){var n=s[e];if(i)throw new Error(\"Memoizee error: Detected unordered then|done & finally resolution, which in turn makes proper detection of success/failure impossible (when in 'done:finally' mode)\\\\nConsider to rely on 'then' or 'done' mode instead.\");n&&(delete s[e],c[e]=t,u.emit(\"setasync\",e,n))},p=function(){i=!0,s[e]&&(delete s[e],delete d[e],u.delete(e))},f=t;if(\"then\"===(f=f||\"then\")){var m=function(){o(p)};\"function\"==typeof(r=r.then((function(e){o(l.bind(this,e))}),m)).finally&&r.finally(m)}else if(\"done\"===f){if(\"function\"!=typeof r.done)throw new Error(\"Memoizee error: Retrieved promise does not implement 'done' in 'done' mode\");r.done(l,p)}else if(\"done:finally\"===f){if(\"function\"!=typeof r.done)throw new Error(\"Memoizee error: Retrieved promise does not implement 'done' in 'done:finally' mode\");if(\"function\"!=typeof r.finally)throw new Error(\"Memoizee error: Retrieved promise does not implement 'finally' in 'done:finally' mode\");r.done(l),r.finally(p)}}else c[e]=r,\\\nu.emit(\"setasync\",e,1)})),u.on(\"get\",(function(e,t,n){var r,i;s[e]?++s[e]:(r=d[e],i=function(){u.emit(\"getasync\",e,t,n)},a(r)?\"function\"==typeof r.done?r.done(i):r.then((function(){o(i)})):i())})),u.on(\"delete\",(function(e){var t;delete d[e],s[e]?delete s[e]:hasOwnProperty.call(c,e)&&(t=c[e],delete c[e],u.emit(\"deleteasync\",e,[t]))})),u.on(\"clear\",(function(){var t=c;c=i(null),s=i(null),d=i(null),u.emit(\"clearasync\",e(t,(function(e){return[e]})))}))}})),Xr=se((function(){var e=Bn(),t=qn(),n=zn(),r=Function.prototype.apply;n.dispose=function(a,o,i){var l;e(a),i.async&&n.async||i.promise&&n.promise?(o.on(\"deleteasync\",l=function(e,t){r.call(a,null,t)}),o.on(\"clearasync\",(function(e){t(e,(function(e,t){l(t,e)}))}))):(o.on(\"delete\",l=function(e,t){a(t)}),o.on(\"clear\",(function(e){t(e,(function(e,t){l(t,e)}))})))}})),Zr=se((function(e,t){t.exports=2147483647})),Jr=se((function(e,t){var n=Pn(),r=Zr();t.exports=function(e){if(e=n(e),r<e)throw new TypeError(e+\" exceeds maximum possible timeout\\\n\");return e}})),Qr=se((function(){var e=Ar(),t=qn(),n=qr(),r=Yr(),a=Jr(),o=zn(),i=Function.prototype,l=Math.max,u=Math.min,s=Object.create;o.maxAge=function(c,d,p){var f,m,h,g;(c=a(c))&&(f=s(null),m=p.async&&o.async||p.promise&&o.promise?\"async\":\"\",d.on(\"set\"+m,(function(e){f[e]=setTimeout((function(){d.delete(e)}),c),\"function\"==typeof f[e].unref&&f[e].unref(),g&&(g[e]&&\"nextTick\"!==g[e]&&clearTimeout(g[e]),g[e]=setTimeout((function(){delete g[e]}),h),\"function\"==typeof g[e].unref)&&g[e].unref()})),d.on(\"delete\"+m,(function(e){clearTimeout(f[e]),delete f[e],g&&(\"nextTick\"!==g[e]&&clearTimeout(g[e]),delete g[e])})),p.preFetch&&(h=!0===p.preFetch||isNaN(p.preFetch)?.333:l(u(Number(p.preFetch),1),0))&&(g={},h=(1-h)*c,d.on(\"get\"+m,(function(t,a,o){g[t]||(g[t]=\"nextTick\",n((function(){var n;\"nextTick\"===g[t]&&(delete g[t],d.delete(t),p.async&&(a=e(a)).push(i),n=d.memoized.apply(o,a),p.promise)&&r(n)&&(\"function\"==typeof n.done?n.done(i,i):n.then(i,i))})))}))),d.on(\"clear\"+m,(function(){t(f\\\n,(function(e){clearTimeout(e)})),f={},g&&(t(g,(function(e){\"nextTick\"!==e&&clearTimeout(e)})),g={})})))}})),ea=se((function(e,t){var n=Pn(),r=Object.create,a=Object.prototype.hasOwnProperty;t.exports=function(e){var t,o=0,i=1,l=r(null),u=r(null),s=0;return e=n(e),{hit:function(n){var r=u[n],c=++s;if(l[c]=n,u[n]=c,!r)return++o<=e?void 0:(n=l[i],t(n),n);if(delete l[r],i===r)for(;!a.call(l,++i););},delete:t=function(e){var t=u[e];if(t&&(delete l[t],delete u[e],--o,i===t))if(o)for(;!a.call(l,++i););else s=0,i=1},clear:function(){o=0,i=1,l=r(null),u=r(null),s=0}}}})),ta=se((function(){var e=Pn(),t=ea(),n=zn();n.max=function(r,a,o){var i;(r=e(r))&&(i=t(r),r=o.async&&n.async||o.promise&&n.promise?\"async\":\"\",a.on(\"set\"+r,o=function(e){void 0!==(e=i.hit(e))&&a.delete(e)}),a.on(\"get\"+r,o),a.on(\"delete\"+r,i.delete),a.on(\"clear\"+r,i.clear))}})),na=se((function(){var e=ir(),t=zn(),n=Object.create,r=Object.defineProperties;t.refCounter=function(a,o,i){var l=n(null);i=i.async&&t.async||i.promise&&t.p\\\nromise?\"async\":\"\";o.on(\"set\"+i,(function(e,t){l[e]=t||1})),o.on(\"get\"+i,(function(e){++l[e]})),o.on(\"delete\"+i,(function(e){delete l[e]})),o.on(\"clear\"+i,(function(){l={}})),r(o.memoized,{deleteRef:e((function(){var e=o.get(arguments);return null!==e&&l[e]?!--l[e]&&(o.delete(e),!0):null})),getRefCount:e((function(){var e=o.get(arguments);return null!==e&&l[e]||0}))})}})),ra=se((function(e,t){var n=Tn(),r=In(),a=Nr();t.exports=function(e){var t,o=n(arguments[1]);return o.normalizer||0!==(t=o.length=r(o.length,e.length,o.async))&&(o.primitive?!1===t?o.normalizer=Tr():1<t&&(o.normalizer=Sr()(t)):o.normalizer=!1===t?Ir()():1===t?Br()():jr()(t)),o.async&&zr(),o.promise&&Kr(),o.dispose&&Xr(),o.maxAge&&Qr(),o.max&&ta(),o.refCounter&&na(),a(e,o)}})),aa={helpUrlBase:\"https://dequeuniversity.com/rules/\",gridSize:200,selectorSimilarFilterLimit:700,results:[],resultGroups:[],resultGroupMap:{},impact:Object.freeze([\"minor\",\"moderate\",\"serious\",\"critical\"]),preload:Object.freeze({assets:[\"cssom\",\"me\\\ndia\"],timeout:1e4}),allOrigins:\"<unsafe_all_origins>\",sameOrigin:\"<same_origin>\",serializableErrorProps:Object.freeze([\"message\",\"stack\",\"name\",\"code\",\"ruleId\",\"method\"])},oa=([{name:\"NA\",value:\"inapplicable\",priority:0,group:\"inapplicable\"},{name:\"PASS\",value:\"passed\",priority:1,group:\"passes\"},{name:\"CANTTELL\",value:\"cantTell\",priority:2,group:\"incomplete\"},{name:\"FAIL\",value:\"failed\",priority:3,group:\"violations\"}].forEach((function(e){var t=e.name,n=e.value,r=e.priority;e=e.group;aa[t]=n,aa[t+\"_PRIO\"]=r,aa[t+\"_GROUP\"]=e,aa.results[r]=n,aa.resultGroups[r]=e,aa.resultGroupMap[n]=e})),Object.freeze(aa.results),Object.freeze(aa.resultGroups),Object.freeze(aa.resultGroupMap),Object.freeze(aa),aa),ia=function(){\"object\"===(\"undefined\"==typeof console?\"undefined\":a(console))&&console.log&&Function.prototype.apply.call(console.log,console,arguments)},la=/[\\\\t\\\\r\\\\n\\\\f]/g,ua=W((function e(){H(this,e),this.parent=void 0}),[{key:\"props\",get:function(){throw new Error('VirtualNode class must have \\\na \"props\" object consisting of \"nodeType\" and \"nodeName\" properties')}},{key:\"attrNames\",get:function(){throw new Error('VirtualNode class must have an \"attrNames\" property')}},{key:\"attr\",value:function(){throw new Error('VirtualNode class must have an \"attr\" function')}},{key:\"hasAttr\",value:function(){throw new Error('VirtualNode class must have a \"hasAttr\" function')}},{key:\"hasClass\",value:function(e){var t=this.attr(\"class\");return!!t&&(e=\" \"+e+\" \",0<=(\" \"+t+\" \").replace(la,\" \").indexOf(e))}}]),sa={},ca=(ce(sa,{DqElement:function(){return Pd},RuleError:function(){return wm},aggregate:function(){return ca},aggregateChecks:function(){return ga},aggregateNodeResults:function(){return ba},aggregateResult:function(){return Da},areStylesSet:function(){return wa},assert:function(){return xa},checkHelper:function(){return Id},clone:function(){return Bd},closest:function(){return Wd},collectResultsFromFrames:function(){return zp},contains:function(){return Vp},convertSelector:function(){r\\\neturn Hd},cssParser:function(){return jd},deepMerge:function(){return $p},escapeSelector:function(){return Aa},extendMetaData:function(){return Hp},filterHtmlAttrs:function(){return gm},finalizeRuleResult:function(){return va},findBy:function(){return jp},getAllChecks:function(){return Bp},getAncestry:function(){return Rl},getBaseLang:function(){return of},getCheckMessage:function(){return hf},getCheckOption:function(){return gf},getEnvironmentData:function(){return vf},getFlattenedTree:function(){return tf},getFrameContexts:function(){return Ef},getFriendlyUriEnd:function(){return Ra},getNodeAttributes:function(){return Na},getNodeFromTree:function(){return _l},getPreloadConfig:function(){return cm},getRootNode:function(){return Ml},getRule:function(){return Af},getScroll:function(){return Cf},getScrollState:function(){return kf},getSelector:function(){return Fl},getSelectorData:function(){return wl},getShadowSelector:function(){return pl},getStandards:function(){return Rf},getStyleSh\\\neetFactory:function(){return Tf},getXpath:function(){return Nl},injectStyle:function(){return Sf},isArrayLike:function(){return _f},isContextObject:function(){return Pf},isContextProp:function(){return If},isContextSpec:function(){return Mf},isHidden:function(){return Lf},isHtmlElement:function(){return qf},isLabelledFramesSelector:function(){return Bf},isLabelledShadowDomSelector:function(){return jf},isNodeInContext:function(){return zf},isShadowRoot:function(){return Wp},isValidLang:function(){return Rm},isXHTML:function(){return dl},matchAncestry:function(){return Gf},matches:function(){return Ld},matchesExpression:function(){return Ud},matchesSelector:function(){return Ta},memoize:function(){return cl},mergeResults:function(){return qp},nodeLookup:function(){return Hf},nodeSerializer:function(){return Ip},nodeSorter:function(){return $f},objectHasOwn:function(){return Of},parseCrossOriginStylesheet:function(){return Xf},parseSameOriginStylesheet:function(){return Yf},parseStyleshe\\\net:function(){return Kf},parseTabindex:function(){return Zf},performanceTimer:function(){return Qf},pollyfillElementsFromPoint:function(){return em},preload:function(){return um},preloadCssom:function(){return am},preloadMedia:function(){return lm},processMessage:function(){return mf},publishMetaData:function(){return dm},querySelectorAll:function(){return fm},querySelectorAllFilter:function(){return rm},queue:function(){return Qd},respondable:function(){return Np},ruleShouldRun:function(){return hm},select:function(){return bm},sendCommandToFrame:function(){return Sp},serializeError:function(){return ym},setScrollState:function(){return xm},shadowSelect:function(){return Em},shadowSelectAll:function(){return Am},shouldPreload:function(){return sm},toArray:function(){return Ea},tokenList:function(){return Yp},uniqueArray:function(){return tm},uuid:function(){return pp},validInputTypes:function(){return Fm},validLangs:function(){return km}}),function(e,t,n){return t=t.slice(),n&&t.push(\\\nn),n=t.map((function(t){return e.indexOf(t)})).sort(),e[n.pop()]}),da=oa.CANTTELL_PRIO,pa=oa.FAIL_PRIO,fa=[],ma=(fa[oa.PASS_PRIO]=!0,fa[oa.CANTTELL_PRIO]=null,fa[oa.FAIL_PRIO]=!1,[\"any\",\"all\",\"none\"]);function ha(e,t){ma.reduce((function(n,r){return n[r]=(e[r]||[]).map((function(e){return t(e,r)})),n}),{})}var ga=function(e){var t=Object.assign({},e),n=(ha(t,(function(e,t){var n=void 0===e.result?-1:fa.indexOf(e.result);e.priority=-1!==n?n:oa.CANTTELL_PRIO,\"none\"===t&&(e.priority===oa.PASS_PRIO?e.priority=oa.FAIL_PRIO:e.priority===oa.FAIL_PRIO&&(e.priority=oa.PASS_PRIO))})),{all:t.all.reduce((function(e,t){return Math.max(e,t.priority)}),0),none:t.none.reduce((function(e,t){return Math.max(e,t.priority)}),0),any:t.any.reduce((function(e,t){return Math.min(e,t.priority)}),4)%4}),r=(t.priority=Math.max(n.all,n.none,n.any),[]);return ma.forEach((function(e){t[e]=t[e].filter((function(r){return r.priority===t.priority&&r.priority===n[e]})),t[e].forEach((function(e){return r.push(e.impact)}\\\n))})),[da,pa].includes(t.priority)?t.impact=ca(oa.impact,r):t.impact=null,ha(t,(function(e){delete e.result,delete e.priority})),t.result=oa.results[t.priority],delete t.priority,t};function va(e){var t=o._audit.rules.find((function(t){return t.id===e.id}));return t&&t.impact&&e.nodes.forEach((function(e){[\"any\",\"all\",\"none\"].forEach((function(n){(e[n]||[]).forEach((function(e){e.impact=t.impact}))}))})),Object.assign(e,ba(e.nodes)),delete e.nodes,e}var ba=function(e){var t={},n=((e=e.map((function(e){if(e.any&&e.all&&e.none)return ga(e);if(Array.isArray(e.node))return va(e);throw new TypeError(\"Invalid Result type\")})))&&e.length?(n=e.map((function(e){return e.result})),t.result=ca(oa.results,n,t.result)):t.result=\"inapplicable\",oa.resultGroups.forEach((function(e){return t[e]=[]})),e.forEach((function(e){var n=oa.resultGroupMap[e.result];t[n].push(e)})),oa.FAIL_GROUP);return 0===t[n].length&&(n=oa.CANTTELL_GROUP),0<t[n].length?(e=t[n].map((function(e){return e.impact})),t.impact=ca(o\\\na.impact,e)||null):t.impact=null,t};function ya(e,t,n){var r=Object.assign({},t);r.nodes=(r[n]||[]).concat(),oa.resultGroups.forEach((function(e){delete r[e]})),e[n].push(r)}var Da=function(e){var t={};return oa.resultGroups.forEach((function(e){return t[e]=[]})),e.forEach((function(e){e.error?ya(t,e,oa.CANTTELL_GROUP):e.result===oa.NA?ya(t,e,oa.NA_GROUP):oa.resultGroups.forEach((function(n){Array.isArray(e[n])&&0<e[n].length&&ya(t,e,n)}))})),t},wa=function e(n,r,a){var o=t.getComputedStyle(n,null);if(!o)return!1;for(var i=0;i<r.length;++i){var l=r[i];if(o.getPropertyValue(l.property)===l.value)return!0}return!(!n.parentNode||n.nodeName.toUpperCase()===a.toUpperCase())&&e(n.parentNode,r,a)},xa=function(e,t){if(!e)throw new Error(t)},Ea=function(e){return Array.prototype.slice.call(e)},Aa=function(e){for(var t,n=String(e),r=n.length,a=-1,o=\"\",i=n.charCodeAt(0);++a<r;)0==(t=n.charCodeAt(a))?o+=\"�\":o+=1<=t&&t<=31||127==t||0==a&&48<=t&&t<=57||1==a&&48<=t&&t<=57&&45==i?\"\\\\\\\\\"+t.toString(16)+\"\\\n \":0==a&&1==r&&45==t||!(128<=t||45==t||95==t||48<=t&&t<=57||65<=t&&t<=90||97<=t&&t<=122)?\"\\\\\\\\\"+n.charAt(a):n.charAt(a);return o};function Fa(e,t){return[e.substring(0,t),e.substring(t)]}function Ca(e){return e.replace(/\\\\s+$/,\"\")}var ka,Ra=function(){var e,t,n,r,a,o,i,l,u=0<arguments.length&&void 0!==arguments[0]?arguments[0]:\"\",s=1<arguments.length&&void 0!==arguments[1]?arguments[1]:{};if(!(u.length<=1||\"data:\"===u.substr(0,5)||\"javascript:\"===u.substr(0,11)||u.includes(\"?\")))return e=s.currentDomain,s=void 0===(s=s.maxLength)?25:s,i=o=l=a=r=\"\",(n=u).includes(\"#\")&&(u=(t=V(Fa(u,u.indexOf(\"#\")),2))[0],i=t[1]),u.includes(\"?\")&&(u=(t=V(Fa(u,u.indexOf(\"?\")),2))[0],o=t[1]),u.includes(\"://\")?(r=(t=V(u.split(\"://\"),2))[0],a=(t=V(Fa(u=t[1],u.indexOf(\"/\")),2))[0],u=t[1]):\"//\"===u.substr(0,2)&&(a=(t=V(Fa(u=u.substr(2),u.indexOf(\"/\")),2))[0],u=t[1]),(a=\"www.\"===a.substr(0,4)?a.substr(4):a)&&a.includes(\":\")&&(a=(t=V(Fa(a,a.indexOf(\":\")),2))[0],l=t[1]),n=(t={original:n,protocol:r,domain:a,port:l,pa\\\nth:u,query:o,hash:i}).domain,r=t.hash,l=(a=t.path).substr(a.substr(0,a.length-2).lastIndexOf(\"/\")+1),r?l&&(l+r).length<=s?Ca(l+r):l.length<2&&2<r.length&&r.length<=s?Ca(r):void 0:n&&n.length<s&&a.length<=1||a===\"/\"+l&&n&&e&&n!==e&&(n+a).length<=s?Ca(n+a):(-1===(u=l.lastIndexOf(\".\"))||1<u)&&(-1!==u||2<l.length)&&l.length<=s&&!l.match(/index(\\\\.[a-zA-Z]{2-4})?/)&&!function(e){return 0!==(e=0<arguments.length&&void 0!==e?e:\"\").length&&(e.match(/[0-9]/g)||\"\").length>=e.length/2}(l)?Ca(l):void 0},Na=function(e){return(e.attributes instanceof t.NamedNodeMap?e:e.cloneNode(!1)).attributes},Ta=function(e,t){return!!e[ka=ka&&e[ka]?ka:(e=>{for(var t,n=[\"matches\",\"matchesSelector\",\"mozMatchesSelector\",\"webkitMatchesSelector\",\"msMatchesSelector\"],r=n.length,a=0;a<r;a++)if(e[t=n[a]])return t})(e)]&&e[ka](t)},Sa={},_a=(ye=(ce(Sa,{ArrayFrom:function(){return sl.default},Colorjs:function(){return rl},CssSelectorParser:function(){return _a.CssSelectorParser},doT:function(){return Oa.default},emojiRegexTe\\\nxt:function(){return Ma},memoize:function(){return Pa.default}}),de(ye())),De=de(De()),we=(de(we()),de(Dt())),Dt=de(jt()),jt=de(xn()),\"hasOwn\"in Object||(Object.hasOwn=we.default),\"values\"in Object||(Object.values=Dt.default),\"Promise\"in t||ye.default.polyfill(),\"Uint32Array\"in t||(t.Uint32Array=De.Uint32Array),t.Uint32Array&&(\"some\"in t.Uint32Array.prototype||Object.defineProperty(t.Uint32Array.prototype,\"some\",{value:Array.prototype.some}),\"reduce\"in t.Uint32Array.prototype||Object.defineProperty(t.Uint32Array.prototype,\"reduce\",{value:Array.prototype.reduce})),\"function\"!=typeof Object.assign&&(Object.assign=function(e){if(null==e)throw new TypeError(\"Cannot convert undefined or null to object\");for(var t=Object(e),n=1;n<arguments.length;n++){var r=arguments[n];if(null!=r)for(var a in r)r.hasOwnProperty(a)&&(t[a]=r[a])}return t}),Array.prototype.find||Object.defineProperty(Array.prototype,\"find\",{value:function(e){if(null===this)throw new TypeError(\"Array.prototype.find called on nu\\\nll or undefined\");if(\"function\"!=typeof e)throw new TypeError(\"predicate must be a function\");for(var t,n=Object(this),r=n.length>>>0,a=arguments[1],o=0;o<r;o++)if(t=n[o],e.call(a,t,o,n))return t}}),Array.prototype.findIndex||Object.defineProperty(Array.prototype,\"findIndex\",{value:function(e,t){if(null===this)throw new TypeError(\"Array.prototype.find called on null or undefined\");if(\"function\"!=typeof e)throw new TypeError(\"predicate must be a function\");for(var n,r=Object(this),a=r.length>>>0,o=0;o<a;o++)if(n=r[o],e.call(t,n,o,r))return o;return-1}}),Array.prototype.includes||Object.defineProperty(Array.prototype,\"includes\",{value:function(e){var t=Object(this),n=parseInt(t.length,10)||0;if(0!==n){var r,a,o=parseInt(arguments[1],10)||0;for(0<=o?r=o:(r=n+o)<0&&(r=0);r<n;){if(e===(a=t[r])||e!=e&&a!=a)return!0;r++}}return!1}}),Array.prototype.some||Object.defineProperty(Array.prototype,\"some\",{value:function(e){if(null==this)throw new TypeError(\"Array.prototype.some called on null or un\\\ndefined\");if(\"function\"!=typeof e)throw new TypeError;for(var t=Object(this),n=t.length>>>0,r=2<=arguments.length?arguments[1]:void 0,a=0;a<n;a++)if(a in t&&e.call(r,t[a],a,t))return!0;return!1}}),Array.from||(Array.from=jt.default),String.prototype.includes||(String.prototype.includes=function(e,t){return!((t=\"number\"!=typeof t?0:t)+e.length>this.length)&&-1!==this.indexOf(e,t)}),Array.prototype.flat||Object.defineProperty(Array.prototype,\"flat\",{configurable:!0,value:function e(){var t=isNaN(arguments[0])?1:Number(arguments[0]);return t?Array.prototype.reduce.call(this,(function(n,r){return Array.isArray(r)?n.push.apply(n,e.call(r,t-1)):n.push(r),n}),[]):Array.prototype.slice.call(this)},writable:!0}),!t.Node||\"isConnected\"in t.Node.prototype||Object.defineProperty(t.Node.prototype,\"isConnected\",{get:function(){return!(this.ownerDocument&&this.ownerDocument.compareDocumentPosition(this)&this.DOCUMENT_POSITION_DISCONNECTED)}}),de(Cn())),Oa=de(kn()),Ma=function(){return/[#*0-9]\\\\uFE0F?\\\\\\\nu20E3|[\\\\xA9\\\\xAE\\\\u203C\\\\u2049\\\\u2122\\\\u2139\\\\u2194-\\\\u2199\\\\u21A9\\\\u21AA\\\\u231A\\\\u231B\\\\u2328\\\\u23CF\\\\u23ED-\\\\u23EF\\\\u23F1\\\\u23F2\\\\u23F8-\\\\u23FA\\\\u24C2\\\\u25AA\\\\u25AB\\\\u25B6\\\\u25C0\\\\u25FB\\\\u25FC\\\\u25FE\\\\u2600-\\\\u2604\\\\u260E\\\\u2611\\\\u2614\\\\u2615\\\\u2618\\\\u2620\\\\u2622\\\\u2623\\\\u2626\\\\u262A\\\\u262E\\\\u262F\\\\u2638-\\\\u263A\\\\u2640\\\\u2642\\\\u2648-\\\\u2653\\\\u265F\\\\u2660\\\\u2663\\\\u2665\\\\u2666\\\\u2668\\\\u267B\\\\u267E\\\\u267F\\\\u2692\\\\u2694-\\\\u2697\\\\u2699\\\\u269B\\\\u269C\\\\u26A0\\\\u26A7\\\\u26AA\\\\u26B0\\\\u26B1\\\\u26BD\\\\u26BE\\\\u26C4\\\\u26C8\\\\u26CF\\\\u26D1\\\\u26E9\\\\u26F0-\\\\u26F5\\\\u26F7\\\\u26F8\\\\u26FA\\\\u2702\\\\u2708\\\\u2709\\\\u270F\\\\u2712\\\\u2714\\\\u2716\\\\u271D\\\\u2721\\\\u2733\\\\u2734\\\\u2744\\\\u2747\\\\u2757\\\\u2763\\\\u27A1\\\\u2934\\\\u2935\\\\u2B05-\\\\u2B07\\\\u2B1B\\\\u2B1C\\\\u2B55\\\\u3030\\\\u303D\\\\u3297\\\\u3299]\\\\uFE0F?|[\\\\u261D\\\\u270C\\\\u270D](?:\\\\uD83C[\\\\uDFFB-\\\\uDFFF]|\\\\uFE0F)?|[\\\\u270A\\\\u270B](?:\\\\uD83C[\\\\uDFFB-\\\\uDFFF])?|[\\\\u23E9-\\\\u23EC\\\\u23F0\\\\u23F3\\\\u25FD\\\\u2693\\\\u26A1\\\\u26AB\\\\u26C5\\\\u26CE\\\\u26D4\\\\u26EA\\\\u26FD\\\\u2705\\\\u2728\\\\u274C\\\\u274E\\\\u2753-\\\\u2755\\\\u2795-\\\\u2797\\\\u27B0\\\\u27BF\\\\u2B50]|\\\\u26D3\\\\uFE0F?(?:\\\\u200D\\\\uD83D\\\\uDCA5)?|\\\\u26F9(?:\\\\uD83C[\\\\uDFFB-\\\\uDFFF]|\\\\uFE0F)?(?:\\\\u200D[\\\\u2640\\\n\\\\u2642]\\\\uFE0F?)?|\\\\u2764\\\\uFE0F?(?:\\\\u200D(?:\\\\uD83D\\\\uDD25|\\\\uD83E\\\\uDE79))?|\\\\uD83C(?:[\\\\uDC04\\\\uDD70\\\\uDD71\\\\uDD7E\\\\uDD7F\\\\uDE02\\\\uDE37\\\\uDF21\\\\uDF24-\\\\uDF2C\\\\uDF36\\\\uDF7D\\\\uDF96\\\\uDF97\\\\uDF99-\\\\uDF9B\\\\uDF9E\\\\uDF9F\\\\uDFCD\\\\uDFCE\\\\uDFD4-\\\\uDFDF\\\\uDFF5\\\\uDFF7]\\\\uFE0F?|[\\\\uDF85\\\\uDFC2\\\\uDFC7](?:\\\\uD83C[\\\\uDFFB-\\\\uDFFF])?|[\\\\uDFC4\\\\uDFCA](?:\\\\uD83C[\\\\uDFFB-\\\\uDFFF])?(?:\\\\u200D[\\\\u2640\\\\u2642]\\\\uFE0F?)?|[\\\\uDFCB\\\\uDFCC](?:\\\\uD83C[\\\\uDFFB-\\\\uDFFF]|\\\\uFE0F)?(?:\\\\u200D[\\\\u2640\\\\u2642]\\\\uFE0F?)?|[\\\\uDCCF\\\\uDD8E\\\\uDD91-\\\\uDD9A\\\\uDE01\\\\uDE1A\\\\uDE2F\\\\uDE32-\\\\uDE36\\\\uDE38-\\\\uDE3A\\\\uDE50\\\\uDE51\\\\uDF00-\\\\uDF20\\\\uDF2D-\\\\uDF35\\\\uDF37-\\\\uDF43\\\\uDF45-\\\\uDF4A\\\\uDF4C-\\\\uDF7C\\\\uDF7E-\\\\uDF84\\\\uDF86-\\\\uDF93\\\\uDFA0-\\\\uDFC1\\\\uDFC5\\\\uDFC6\\\\uDFC8\\\\uDFC9\\\\uDFCF-\\\\uDFD3\\\\uDFE0-\\\\uDFF0\\\\uDFF8-\\\\uDFFF]|\\\\uDDE6\\\\uD83C[\\\\uDDE8-\\\\uDDEC\\\\uDDEE\\\\uDDF1\\\\uDDF2\\\\uDDF4\\\\uDDF6-\\\\uDDFA\\\\uDDFC\\\\uDDFD\\\\uDDFF]|\\\\uDDE7\\\\uD83C[\\\\uDDE6\\\\uDDE7\\\\uDDE9-\\\\uDDEF\\\\uDDF1-\\\\uDDF4\\\\uDDF6-\\\\uDDF9\\\\uDDFB\\\\uDDFC\\\\uDDFE\\\\uDDFF]|\\\\uDDE8\\\\uD83C[\\\\uDDE6\\\\uDDE8\\\\uDDE9\\\\uDDEB-\\\\uDDEE\\\\uDDF0-\\\\uDDF7\\\\uDDFA-\\\\uDDFF]|\\\\uDDE9\\\\uD83C[\\\\uDDEA\\\\uDDEC\\\\uDDEF\\\\uDDF0\\\\uDDF2\\\\uDDF4\\\\uDDFF]|\\\\uDDEA\\\\uD8\\\n3C[\\\\uDDE6\\\\uDDE8\\\\uDDEA\\\\uDDEC\\\\uDDED\\\\uDDF7-\\\\uDDFA]|\\\\uDDEB\\\\uD83C[\\\\uDDEE-\\\\uDDF0\\\\uDDF2\\\\uDDF4\\\\uDDF7]|\\\\uDDEC\\\\uD83C[\\\\uDDE6\\\\uDDE7\\\\uDDE9-\\\\uDDEE\\\\uDDF1-\\\\uDDF3\\\\uDDF5-\\\\uDDFA\\\\uDDFC\\\\uDDFE]|\\\\uDDED\\\\uD83C[\\\\uDDF0\\\\uDDF2\\\\uDDF3\\\\uDDF7\\\\uDDF9\\\\uDDFA]|\\\\uDDEE\\\\uD83C[\\\\uDDE8-\\\\uDDEA\\\\uDDF1-\\\\uDDF4\\\\uDDF6-\\\\uDDF9]|\\\\uDDEF\\\\uD83C[\\\\uDDEA\\\\uDDF2\\\\uDDF4\\\\uDDF5]|\\\\uDDF0\\\\uD83C[\\\\uDDEA\\\\uDDEC-\\\\uDDEE\\\\uDDF2\\\\uDDF3\\\\uDDF5\\\\uDDF7\\\\uDDFC\\\\uDDFE\\\\uDDFF]|\\\\uDDF1\\\\uD83C[\\\\uDDE6-\\\\uDDE8\\\\uDDEE\\\\uDDF0\\\\uDDF7-\\\\uDDFB\\\\uDDFE]|\\\\uDDF2\\\\uD83C[\\\\uDDE6\\\\uDDE8-\\\\uDDED\\\\uDDF0-\\\\uDDFF]|\\\\uDDF3\\\\uD83C[\\\\uDDE6\\\\uDDE8\\\\uDDEA-\\\\uDDEC\\\\uDDEE\\\\uDDF1\\\\uDDF4\\\\uDDF5\\\\uDDF7\\\\uDDFA\\\\uDDFF]|\\\\uDDF4\\\\uD83C\\\\uDDF2|\\\\uDDF5\\\\uD83C[\\\\uDDE6\\\\uDDEA-\\\\uDDED\\\\uDDF0-\\\\uDDF3\\\\uDDF7-\\\\uDDF9\\\\uDDFC\\\\uDDFE]|\\\\uDDF6\\\\uD83C\\\\uDDE6|\\\\uDDF7\\\\uD83C[\\\\uDDEA\\\\uDDF4\\\\uDDF8\\\\uDDFA\\\\uDDFC]|\\\\uDDF8\\\\uD83C[\\\\uDDE6-\\\\uDDEA\\\\uDDEC-\\\\uDDF4\\\\uDDF7-\\\\uDDF9\\\\uDDFB\\\\uDDFD-\\\\uDDFF]|\\\\uDDF9\\\\uD83C[\\\\uDDE6\\\\uDDE8\\\\uDDE9\\\\uDDEB-\\\\uDDED\\\\uDDEF-\\\\uDDF4\\\\uDDF7\\\\uDDF9\\\\uDDFB\\\\uDDFC\\\\uDDFF]|\\\\uDDFA\\\\uD83C[\\\\uDDE6\\\\uDDEC\\\\uDDF2\\\\uDDF3\\\\uDDF8\\\\uDDFE\\\\uDDFF]|\\\\uDDFB\\\\uD83C[\\\\uDDE6\\\\uDDE8\\\\uDDEA\\\\uDDEC\\\\uDDEE\\\\uD\\\nDF3\\\\uDDFA]|\\\\uDDFC\\\\uD83C[\\\\uDDEB\\\\uDDF8]|\\\\uDDFD\\\\uD83C\\\\uDDF0|\\\\uDDFE\\\\uD83C[\\\\uDDEA\\\\uDDF9]|\\\\uDDFF\\\\uD83C[\\\\uDDE6\\\\uDDF2\\\\uDDFC]|\\\\uDF44(?:\\\\u200D\\\\uD83D\\\\uDFEB)?|\\\\uDF4B(?:\\\\u200D\\\\uD83D\\\\uDFE9)?|\\\\uDFC3(?:\\\\uD83C[\\\\uDFFB-\\\\uDFFF])?(?:\\\\u200D(?:[\\\\u2640\\\\u2642]\\\\uFE0F?(?:\\\\u200D\\\\u27A1\\\\uFE0F?)?|\\\\u27A1\\\\uFE0F?))?|\\\\uDFF3\\\\uFE0F?(?:\\\\u200D(?:\\\\u26A7\\\\uFE0F?|\\\\uD83C\\\\uDF08))?|\\\\uDFF4(?:\\\\u200D\\\\u2620\\\\uFE0F?|\\\\uDB40\\\\uDC67\\\\uDB40\\\\uDC62\\\\uDB40(?:\\\\uDC65\\\\uDB40\\\\uDC6E\\\\uDB40\\\\uDC67|\\\\uDC73\\\\uDB40\\\\uDC63\\\\uDB40\\\\uDC74|\\\\uDC77\\\\uDB40\\\\uDC6C\\\\uDB40\\\\uDC73)\\\\uDB40\\\\uDC7F)?)|\\\\uD83D(?:[\\\\uDC3F\\\\uDCFD\\\\uDD49\\\\uDD4A\\\\uDD6F\\\\uDD70\\\\uDD73\\\\uDD76-\\\\uDD79\\\\uDD87\\\\uDD8A-\\\\uDD8D\\\\uDDA5\\\\uDDA8\\\\uDDB1\\\\uDDB2\\\\uDDBC\\\\uDDC2-\\\\uDDC4\\\\uDDD1-\\\\uDDD3\\\\uDDDC-\\\\uDDDE\\\\uDDE1\\\\uDDE3\\\\uDDE8\\\\uDDEF\\\\uDDF3\\\\uDDFA\\\\uDECB\\\\uDECD-\\\\uDECF\\\\uDEE0-\\\\uDEE5\\\\uDEE9\\\\uDEF0\\\\uDEF3]\\\\uFE0F?|[\\\\uDC42\\\\uDC43\\\\uDC46-\\\\uDC50\\\\uDC66\\\\uDC67\\\\uDC6B-\\\\uDC6D\\\\uDC72\\\\uDC74-\\\\uDC76\\\\uDC78\\\\uDC7C\\\\uDC83\\\\uDC85\\\\uDC8F\\\\uDC91\\\\uDCAA\\\\uDD7A\\\\uDD95\\\\uDD96\\\\uDE4C\\\\uDE4F\\\\uDEC0\\\\uDECC](?:\\\\uD83C[\\\\uDFFB-\\\\uDFFF])?|[\\\\uDC6E-\\\\uDC71\\\\uDC73\\\\uDC77\\\\uDC81\\\\uDC82\\\\uDC86\\\\uDC87\\\\uDE45-\\\\uD\\\nE47\\\\uDE4B\\\\uDE4D\\\\uDE4E\\\\uDEA3\\\\uDEB4\\\\uDEB5](?:\\\\uD83C[\\\\uDFFB-\\\\uDFFF])?(?:\\\\u200D[\\\\u2640\\\\u2642]\\\\uFE0F?)?|[\\\\uDD74\\\\uDD90](?:\\\\uD83C[\\\\uDFFB-\\\\uDFFF]|\\\\uFE0F)?|[\\\\uDC00-\\\\uDC07\\\\uDC09-\\\\uDC14\\\\uDC16-\\\\uDC25\\\\uDC27-\\\\uDC3A\\\\uDC3C-\\\\uDC3E\\\\uDC40\\\\uDC44\\\\uDC45\\\\uDC51-\\\\uDC65\\\\uDC6A\\\\uDC79-\\\\uDC7B\\\\uDC7D-\\\\uDC80\\\\uDC84\\\\uDC88-\\\\uDC8E\\\\uDC90\\\\uDC92-\\\\uDCA9\\\\uDCAB-\\\\uDCFC\\\\uDCFF-\\\\uDD3D\\\\uDD4B-\\\\uDD4E\\\\uDD50-\\\\uDD67\\\\uDDA4\\\\uDDFB-\\\\uDE2D\\\\uDE2F-\\\\uDE34\\\\uDE37-\\\\uDE41\\\\uDE43\\\\uDE44\\\\uDE48-\\\\uDE4A\\\\uDE80-\\\\uDEA2\\\\uDEA4-\\\\uDEB3\\\\uDEB7-\\\\uDEBF\\\\uDEC1-\\\\uDEC5\\\\uDED0-\\\\uDED2\\\\uDED5-\\\\uDED8\\\\uDEDC-\\\\uDEDF\\\\uDEEB\\\\uDEEC\\\\uDEF4-\\\\uDEFC\\\\uDFE0-\\\\uDFEB\\\\uDFF0]|\\\\uDC08(?:\\\\u200D\\\\u2B1B)?|\\\\uDC15(?:\\\\u200D\\\\uD83E\\\\uDDBA)?|\\\\uDC26(?:\\\\u200D(?:\\\\u2B1B|\\\\uD83D\\\\uDD25))?|\\\\uDC3B(?:\\\\u200D\\\\u2744\\\\uFE0F?)?|\\\\uDC41\\\\uFE0F?(?:\\\\u200D\\\\uD83D\\\\uDDE8\\\\uFE0F?)?|\\\\uDC68(?:\\\\u200D(?:[\\\\u2695\\\\u2696\\\\u2708]\\\\uFE0F?|\\\\u2764\\\\uFE0F?\\\\u200D\\\\uD83D(?:\\\\uDC8B\\\\u200D\\\\uD83D)?\\\\uDC68|\\\\uD83C[\\\\uDF3E\\\\uDF73\\\\uDF7C\\\\uDF93\\\\uDFA4\\\\uDFA8\\\\uDFEB\\\\uDFED]|\\\\uD83D(?:[\\\\uDC68\\\\uDC69]\\\\u200D\\\\uD83D(?:\\\\uDC66(?:\\\\u200D\\\\uD83D\\\\uDC66)?|\\\\uDC67(?:\\\\u200D\\\\uD83D[\\\\uDC66\\\\uD\\\nC67])?)|[\\\\uDCBB\\\\uDCBC\\\\uDD27\\\\uDD2C\\\\uDE80\\\\uDE92]|\\\\uDC66(?:\\\\u200D\\\\uD83D\\\\uDC66)?|\\\\uDC67(?:\\\\u200D\\\\uD83D[\\\\uDC66\\\\uDC67])?)|\\\\uD83E(?:[\\\\uDDAF\\\\uDDBC\\\\uDDBD](?:\\\\u200D\\\\u27A1\\\\uFE0F?)?|[\\\\uDDB0-\\\\uDDB3]))|\\\\uD83C(?:\\\\uDFFB(?:\\\\u200D(?:[\\\\u2695\\\\u2696\\\\u2708]\\\\uFE0F?|\\\\u2764\\\\uFE0F?\\\\u200D\\\\uD83D(?:\\\\uDC8B\\\\u200D\\\\uD83D)?\\\\uDC68\\\\uD83C[\\\\uDFFB-\\\\uDFFF]|\\\\uD83C[\\\\uDF3E\\\\uDF73\\\\uDF7C\\\\uDF93\\\\uDFA4\\\\uDFA8\\\\uDFEB\\\\uDFED]|\\\\uD83D(?:[\\\\uDCBB\\\\uDCBC\\\\uDD27\\\\uDD2C\\\\uDE80\\\\uDE92]|\\\\uDC30\\\\u200D\\\\uD83D\\\\uDC68\\\\uD83C[\\\\uDFFC-\\\\uDFFF])|\\\\uD83E(?:[\\\\uDD1D\\\\uDEEF]\\\\u200D\\\\uD83D\\\\uDC68\\\\uD83C[\\\\uDFFC-\\\\uDFFF]|[\\\\uDDAF\\\\uDDBC\\\\uDDBD](?:\\\\u200D\\\\u27A1\\\\uFE0F?)?|[\\\\uDDB0-\\\\uDDB3])))?|\\\\uDFFC(?:\\\\u200D(?:[\\\\u2695\\\\u2696\\\\u2708]\\\\uFE0F?|\\\\u2764\\\\uFE0F?\\\\u200D\\\\uD83D(?:\\\\uDC8B\\\\u200D\\\\uD83D)?\\\\uDC68\\\\uD83C[\\\\uDFFB-\\\\uDFFF]|\\\\uD83C[\\\\uDF3E\\\\uDF73\\\\uDF7C\\\\uDF93\\\\uDFA4\\\\uDFA8\\\\uDFEB\\\\uDFED]|\\\\uD83D(?:[\\\\uDCBB\\\\uDCBC\\\\uDD27\\\\uDD2C\\\\uDE80\\\\uDE92]|\\\\uDC30\\\\u200D\\\\uD83D\\\\uDC68\\\\uD83C[\\\\uDFFB\\\\uDFFD-\\\\uDFFF])|\\\\uD83E(?:[\\\\uDD1D\\\\uDEEF]\\\\u200D\\\\uD83D\\\\uDC68\\\\uD83C[\\\\uDFFB\\\\uDFFD-\\\\uDFFF]|[\\\\uDDAF\\\\uDDBC\\\\uDDBD](?:\\\\u200D\\\\u27A1\\\\uFE0F?)?|[\\\\uDDB0\\\n-\\\\uDDB3])))?|\\\\uDFFD(?:\\\\u200D(?:[\\\\u2695\\\\u2696\\\\u2708]\\\\uFE0F?|\\\\u2764\\\\uFE0F?\\\\u200D\\\\uD83D(?:\\\\uDC8B\\\\u200D\\\\uD83D)?\\\\uDC68\\\\uD83C[\\\\uDFFB-\\\\uDFFF]|\\\\uD83C[\\\\uDF3E\\\\uDF73\\\\uDF7C\\\\uDF93\\\\uDFA4\\\\uDFA8\\\\uDFEB\\\\uDFED]|\\\\uD83D(?:[\\\\uDCBB\\\\uDCBC\\\\uDD27\\\\uDD2C\\\\uDE80\\\\uDE92]|\\\\uDC30\\\\u200D\\\\uD83D\\\\uDC68\\\\uD83C[\\\\uDFFB\\\\uDFFC\\\\uDFFE\\\\uDFFF])|\\\\uD83E(?:[\\\\uDD1D\\\\uDEEF]\\\\u200D\\\\uD83D\\\\uDC68\\\\uD83C[\\\\uDFFB\\\\uDFFC\\\\uDFFE\\\\uDFFF]|[\\\\uDDAF\\\\uDDBC\\\\uDDBD](?:\\\\u200D\\\\u27A1\\\\uFE0F?)?|[\\\\uDDB0-\\\\uDDB3])))?|\\\\uDFFE(?:\\\\u200D(?:[\\\\u2695\\\\u2696\\\\u2708]\\\\uFE0F?|\\\\u2764\\\\uFE0F?\\\\u200D\\\\uD83D(?:\\\\uDC8B\\\\u200D\\\\uD83D)?\\\\uDC68\\\\uD83C[\\\\uDFFB-\\\\uDFFF]|\\\\uD83C[\\\\uDF3E\\\\uDF73\\\\uDF7C\\\\uDF93\\\\uDFA4\\\\uDFA8\\\\uDFEB\\\\uDFED]|\\\\uD83D(?:[\\\\uDCBB\\\\uDCBC\\\\uDD27\\\\uDD2C\\\\uDE80\\\\uDE92]|\\\\uDC30\\\\u200D\\\\uD83D\\\\uDC68\\\\uD83C[\\\\uDFFB-\\\\uDFFD\\\\uDFFF])|\\\\uD83E(?:[\\\\uDD1D\\\\uDEEF]\\\\u200D\\\\uD83D\\\\uDC68\\\\uD83C[\\\\uDFFB-\\\\uDFFD\\\\uDFFF]|[\\\\uDDAF\\\\uDDBC\\\\uDDBD](?:\\\\u200D\\\\u27A1\\\\uFE0F?)?|[\\\\uDDB0-\\\\uDDB3])))?|\\\\uDFFF(?:\\\\u200D(?:[\\\\u2695\\\\u2696\\\\u2708]\\\\uFE0F?|\\\\u2764\\\\uFE0F?\\\\u200D\\\\uD83D(?:\\\\uDC8B\\\\u200D\\\\uD83D)?\\\\uDC68\\\\uD83C[\\\\uDFFB-\\\\uDFFF]|\\\\uD83C[\\\\uDF3E\\\\uDF73\\\\uDF7C\\\\u\\\nDF93\\\\uDFA4\\\\uDFA8\\\\uDFEB\\\\uDFED]|\\\\uD83D(?:[\\\\uDCBB\\\\uDCBC\\\\uDD27\\\\uDD2C\\\\uDE80\\\\uDE92]|\\\\uDC30\\\\u200D\\\\uD83D\\\\uDC68\\\\uD83C[\\\\uDFFB-\\\\uDFFE])|\\\\uD83E(?:[\\\\uDD1D\\\\uDEEF]\\\\u200D\\\\uD83D\\\\uDC68\\\\uD83C[\\\\uDFFB-\\\\uDFFE]|[\\\\uDDAF\\\\uDDBC\\\\uDDBD](?:\\\\u200D\\\\u27A1\\\\uFE0F?)?|[\\\\uDDB0-\\\\uDDB3])))?))?|\\\\uDC69(?:\\\\u200D(?:[\\\\u2695\\\\u2696\\\\u2708]\\\\uFE0F?|\\\\u2764\\\\uFE0F?\\\\u200D\\\\uD83D(?:\\\\uDC8B\\\\u200D\\\\uD83D)?[\\\\uDC68\\\\uDC69]|\\\\uD83C[\\\\uDF3E\\\\uDF73\\\\uDF7C\\\\uDF93\\\\uDFA4\\\\uDFA8\\\\uDFEB\\\\uDFED]|\\\\uD83D(?:[\\\\uDCBB\\\\uDCBC\\\\uDD27\\\\uDD2C\\\\uDE80\\\\uDE92]|\\\\uDC66(?:\\\\u200D\\\\uD83D\\\\uDC66)?|\\\\uDC67(?:\\\\u200D\\\\uD83D[\\\\uDC66\\\\uDC67])?|\\\\uDC69\\\\u200D\\\\uD83D(?:\\\\uDC66(?:\\\\u200D\\\\uD83D\\\\uDC66)?|\\\\uDC67(?:\\\\u200D\\\\uD83D[\\\\uDC66\\\\uDC67])?))|\\\\uD83E(?:[\\\\uDDAF\\\\uDDBC\\\\uDDBD](?:\\\\u200D\\\\u27A1\\\\uFE0F?)?|[\\\\uDDB0-\\\\uDDB3]))|\\\\uD83C(?:\\\\uDFFB(?:\\\\u200D(?:[\\\\u2695\\\\u2696\\\\u2708]\\\\uFE0F?|\\\\u2764\\\\uFE0F?\\\\u200D\\\\uD83D(?:[\\\\uDC68\\\\uDC69]|\\\\uDC8B\\\\u200D\\\\uD83D[\\\\uDC68\\\\uDC69])\\\\uD83C[\\\\uDFFB-\\\\uDFFF]|\\\\uD83C[\\\\uDF3E\\\\uDF73\\\\uDF7C\\\\uDF93\\\\uDFA4\\\\uDFA8\\\\uDFEB\\\\uDFED]|\\\\uD83D(?:[\\\\uDCBB\\\\uDCBC\\\\uDD27\\\\uDD2C\\\\uDE80\\\\uDE92]|\\\\uDC30\\\\u200D\\\\uD83D\\\\uDC69\\\\uD83C[\\\\uDFFC-\\\\uD\\\nFFF])|\\\\uD83E(?:[\\\\uDDAF\\\\uDDBC\\\\uDDBD](?:\\\\u200D\\\\u27A1\\\\uFE0F?)?|[\\\\uDDB0-\\\\uDDB3]|\\\\uDD1D\\\\u200D\\\\uD83D[\\\\uDC68\\\\uDC69]\\\\uD83C[\\\\uDFFC-\\\\uDFFF]|\\\\uDEEF\\\\u200D\\\\uD83D\\\\uDC69\\\\uD83C[\\\\uDFFC-\\\\uDFFF])))?|\\\\uDFFC(?:\\\\u200D(?:[\\\\u2695\\\\u2696\\\\u2708]\\\\uFE0F?|\\\\u2764\\\\uFE0F?\\\\u200D\\\\uD83D(?:[\\\\uDC68\\\\uDC69]|\\\\uDC8B\\\\u200D\\\\uD83D[\\\\uDC68\\\\uDC69])\\\\uD83C[\\\\uDFFB-\\\\uDFFF]|\\\\uD83C[\\\\uDF3E\\\\uDF73\\\\uDF7C\\\\uDF93\\\\uDFA4\\\\uDFA8\\\\uDFEB\\\\uDFED]|\\\\uD83D(?:[\\\\uDCBB\\\\uDCBC\\\\uDD27\\\\uDD2C\\\\uDE80\\\\uDE92]|\\\\uDC30\\\\u200D\\\\uD83D\\\\uDC69\\\\uD83C[\\\\uDFFB\\\\uDFFD-\\\\uDFFF])|\\\\uD83E(?:[\\\\uDDAF\\\\uDDBC\\\\uDDBD](?:\\\\u200D\\\\u27A1\\\\uFE0F?)?|[\\\\uDDB0-\\\\uDDB3]|\\\\uDD1D\\\\u200D\\\\uD83D[\\\\uDC68\\\\uDC69]\\\\uD83C[\\\\uDFFB\\\\uDFFD-\\\\uDFFF]|\\\\uDEEF\\\\u200D\\\\uD83D\\\\uDC69\\\\uD83C[\\\\uDFFB\\\\uDFFD-\\\\uDFFF])))?|\\\\uDFFD(?:\\\\u200D(?:[\\\\u2695\\\\u2696\\\\u2708]\\\\uFE0F?|\\\\u2764\\\\uFE0F?\\\\u200D\\\\uD83D(?:[\\\\uDC68\\\\uDC69]|\\\\uDC8B\\\\u200D\\\\uD83D[\\\\uDC68\\\\uDC69])\\\\uD83C[\\\\uDFFB-\\\\uDFFF]|\\\\uD83C[\\\\uDF3E\\\\uDF73\\\\uDF7C\\\\uDF93\\\\uDFA4\\\\uDFA8\\\\uDFEB\\\\uDFED]|\\\\uD83D(?:[\\\\uDCBB\\\\uDCBC\\\\uDD27\\\\uDD2C\\\\uDE80\\\\uDE92]|\\\\uDC30\\\\u200D\\\\uD83D\\\\uDC69\\\\uD83C[\\\\uDFFB\\\\uDFFC\\\\uDFFE\\\\uDFFF])|\\\\uD83E(?:[\\\\uDDAF\\\\uDDBC\\\\uD\\\nDBD](?:\\\\u200D\\\\u27A1\\\\uFE0F?)?|[\\\\uDDB0-\\\\uDDB3]|\\\\uDD1D\\\\u200D\\\\uD83D[\\\\uDC68\\\\uDC69]\\\\uD83C[\\\\uDFFB\\\\uDFFC\\\\uDFFE\\\\uDFFF]|\\\\uDEEF\\\\u200D\\\\uD83D\\\\uDC69\\\\uD83C[\\\\uDFFB\\\\uDFFC\\\\uDFFE\\\\uDFFF])))?|\\\\uDFFE(?:\\\\u200D(?:[\\\\u2695\\\\u2696\\\\u2708]\\\\uFE0F?|\\\\u2764\\\\uFE0F?\\\\u200D\\\\uD83D(?:[\\\\uDC68\\\\uDC69]|\\\\uDC8B\\\\u200D\\\\uD83D[\\\\uDC68\\\\uDC69])\\\\uD83C[\\\\uDFFB-\\\\uDFFF]|\\\\uD83C[\\\\uDF3E\\\\uDF73\\\\uDF7C\\\\uDF93\\\\uDFA4\\\\uDFA8\\\\uDFEB\\\\uDFED]|\\\\uD83D(?:[\\\\uDCBB\\\\uDCBC\\\\uDD27\\\\uDD2C\\\\uDE80\\\\uDE92]|\\\\uDC30\\\\u200D\\\\uD83D\\\\uDC69\\\\uD83C[\\\\uDFFB-\\\\uDFFD\\\\uDFFF])|\\\\uD83E(?:[\\\\uDDAF\\\\uDDBC\\\\uDDBD](?:\\\\u200D\\\\u27A1\\\\uFE0F?)?|[\\\\uDDB0-\\\\uDDB3]|\\\\uDD1D\\\\u200D\\\\uD83D[\\\\uDC68\\\\uDC69]\\\\uD83C[\\\\uDFFB-\\\\uDFFD\\\\uDFFF]|\\\\uDEEF\\\\u200D\\\\uD83D\\\\uDC69\\\\uD83C[\\\\uDFFB-\\\\uDFFD\\\\uDFFF])))?|\\\\uDFFF(?:\\\\u200D(?:[\\\\u2695\\\\u2696\\\\u2708]\\\\uFE0F?|\\\\u2764\\\\uFE0F?\\\\u200D\\\\uD83D(?:[\\\\uDC68\\\\uDC69]|\\\\uDC8B\\\\u200D\\\\uD83D[\\\\uDC68\\\\uDC69])\\\\uD83C[\\\\uDFFB-\\\\uDFFF]|\\\\uD83C[\\\\uDF3E\\\\uDF73\\\\uDF7C\\\\uDF93\\\\uDFA4\\\\uDFA8\\\\uDFEB\\\\uDFED]|\\\\uD83D(?:[\\\\uDCBB\\\\uDCBC\\\\uDD27\\\\uDD2C\\\\uDE80\\\\uDE92]|\\\\uDC30\\\\u200D\\\\uD83D\\\\uDC69\\\\uD83C[\\\\uDFFB-\\\\uDFFE])|\\\\uD83E(?:[\\\\uDDAF\\\\uDDBC\\\\uDDBD](?:\\\\u200D\\\\u27A1\\\\\\\nuFE0F?)?|[\\\\uDDB0-\\\\uDDB3]|\\\\uDD1D\\\\u200D\\\\uD83D[\\\\uDC68\\\\uDC69]\\\\uD83C[\\\\uDFFB-\\\\uDFFE]|\\\\uDEEF\\\\u200D\\\\uD83D\\\\uDC69\\\\uD83C[\\\\uDFFB-\\\\uDFFE])))?))?|\\\\uDD75(?:\\\\uD83C[\\\\uDFFB-\\\\uDFFF]|\\\\uFE0F)?(?:\\\\u200D[\\\\u2640\\\\u2642]\\\\uFE0F?)?|\\\\uDE2E(?:\\\\u200D\\\\uD83D\\\\uDCA8)?|\\\\uDE35(?:\\\\u200D\\\\uD83D\\\\uDCAB)?|\\\\uDE36(?:\\\\u200D\\\\uD83C\\\\uDF2B\\\\uFE0F?)?|\\\\uDE42(?:\\\\u200D[\\\\u2194\\\\u2195]\\\\uFE0F?)?|\\\\uDEB6(?:\\\\uD83C[\\\\uDFFB-\\\\uDFFF])?(?:\\\\u200D(?:[\\\\u2640\\\\u2642]\\\\uFE0F?(?:\\\\u200D\\\\u27A1\\\\uFE0F?)?|\\\\u27A1\\\\uFE0F?))?)|\\\\uD83E(?:[\\\\uDD0C\\\\uDD0F\\\\uDD18-\\\\uDD1F\\\\uDD30-\\\\uDD34\\\\uDD36\\\\uDD77\\\\uDDB5\\\\uDDB6\\\\uDDBB\\\\uDDD2\\\\uDDD3\\\\uDDD5\\\\uDEC3-\\\\uDEC5\\\\uDEF0\\\\uDEF2-\\\\uDEF8](?:\\\\uD83C[\\\\uDFFB-\\\\uDFFF])?|[\\\\uDD26\\\\uDD35\\\\uDD37-\\\\uDD39\\\\uDD3C-\\\\uDD3E\\\\uDDB8\\\\uDDB9\\\\uDDCD\\\\uDDCF\\\\uDDD4\\\\uDDD6-\\\\uDDDD](?:\\\\uD83C[\\\\uDFFB-\\\\uDFFF])?(?:\\\\u200D[\\\\u2640\\\\u2642]\\\\uFE0F?)?|[\\\\uDDDE\\\\uDDDF](?:\\\\u200D[\\\\u2640\\\\u2642]\\\\uFE0F?)?|[\\\\uDD0D\\\\uDD0E\\\\uDD10-\\\\uDD17\\\\uDD20-\\\\uDD25\\\\uDD27-\\\\uDD2F\\\\uDD3A\\\\uDD3F-\\\\uDD45\\\\uDD47-\\\\uDD76\\\\uDD78-\\\\uDDB4\\\\uDDB7\\\\uDDBA\\\\uDDBC-\\\\uDDCC\\\\uDDD0\\\\uDDE0-\\\\uDDFF\\\\uDE70-\\\\uDE7C\\\\uDE80-\\\\uDE8A\\\\uDE8E-\\\\uDEC2\\\\uDEC6\\\\uDEC8\\\\uDECD-\\\\uDEDC\\\\u\\\nDEDF-\\\\uDEEA\\\\uDEEF]|\\\\uDDCE(?:\\\\uD83C[\\\\uDFFB-\\\\uDFFF])?(?:\\\\u200D(?:[\\\\u2640\\\\u2642]\\\\uFE0F?(?:\\\\u200D\\\\u27A1\\\\uFE0F?)?|\\\\u27A1\\\\uFE0F?))?|\\\\uDDD1(?:\\\\u200D(?:[\\\\u2695\\\\u2696\\\\u2708]\\\\uFE0F?|\\\\uD83C[\\\\uDF3E\\\\uDF73\\\\uDF7C\\\\uDF84\\\\uDF93\\\\uDFA4\\\\uDFA8\\\\uDFEB\\\\uDFED]|\\\\uD83D[\\\\uDCBB\\\\uDCBC\\\\uDD27\\\\uDD2C\\\\uDE80\\\\uDE92]|\\\\uD83E(?:[\\\\uDDAF\\\\uDDBC\\\\uDDBD](?:\\\\u200D\\\\u27A1\\\\uFE0F?)?|[\\\\uDDB0-\\\\uDDB3\\\\uDE70]|\\\\uDD1D\\\\u200D\\\\uD83E\\\\uDDD1|\\\\uDDD1\\\\u200D\\\\uD83E\\\\uDDD2(?:\\\\u200D\\\\uD83E\\\\uDDD2)?|\\\\uDDD2(?:\\\\u200D\\\\uD83E\\\\uDDD2)?))|\\\\uD83C(?:\\\\uDFFB(?:\\\\u200D(?:[\\\\u2695\\\\u2696\\\\u2708]\\\\uFE0F?|\\\\u2764\\\\uFE0F?\\\\u200D(?:\\\\uD83D\\\\uDC8B\\\\u200D)?\\\\uD83E\\\\uDDD1\\\\uD83C[\\\\uDFFC-\\\\uDFFF]|\\\\uD83C[\\\\uDF3E\\\\uDF73\\\\uDF7C\\\\uDF84\\\\uDF93\\\\uDFA4\\\\uDFA8\\\\uDFEB\\\\uDFED]|\\\\uD83D(?:[\\\\uDCBB\\\\uDCBC\\\\uDD27\\\\uDD2C\\\\uDE80\\\\uDE92]|\\\\uDC30\\\\u200D\\\\uD83E\\\\uDDD1\\\\uD83C[\\\\uDFFC-\\\\uDFFF])|\\\\uD83E(?:[\\\\uDDAF\\\\uDDBC\\\\uDDBD](?:\\\\u200D\\\\u27A1\\\\uFE0F?)?|[\\\\uDDB0-\\\\uDDB3\\\\uDE70]|\\\\uDD1D\\\\u200D\\\\uD83E\\\\uDDD1\\\\uD83C[\\\\uDFFB-\\\\uDFFF]|\\\\uDEEF\\\\u200D\\\\uD83E\\\\uDDD1\\\\uD83C[\\\\uDFFC-\\\\uDFFF])))?|\\\\uDFFC(?:\\\\u200D(?:[\\\\u2695\\\\u2696\\\\u2708]\\\\uFE0F?|\\\\u2764\\\\uFE0F?\\\\u200D(?:\\\\uD83D\\\\uDC\\\n8B\\\\u200D)?\\\\uD83E\\\\uDDD1\\\\uD83C[\\\\uDFFB\\\\uDFFD-\\\\uDFFF]|\\\\uD83C[\\\\uDF3E\\\\uDF73\\\\uDF7C\\\\uDF84\\\\uDF93\\\\uDFA4\\\\uDFA8\\\\uDFEB\\\\uDFED]|\\\\uD83D(?:[\\\\uDCBB\\\\uDCBC\\\\uDD27\\\\uDD2C\\\\uDE80\\\\uDE92]|\\\\uDC30\\\\u200D\\\\uD83E\\\\uDDD1\\\\uD83C[\\\\uDFFB\\\\uDFFD-\\\\uDFFF])|\\\\uD83E(?:[\\\\uDDAF\\\\uDDBC\\\\uDDBD](?:\\\\u200D\\\\u27A1\\\\uFE0F?)?|[\\\\uDDB0-\\\\uDDB3\\\\uDE70]|\\\\uDD1D\\\\u200D\\\\uD83E\\\\uDDD1\\\\uD83C[\\\\uDFFB-\\\\uDFFF]|\\\\uDEEF\\\\u200D\\\\uD83E\\\\uDDD1\\\\uD83C[\\\\uDFFB\\\\uDFFD-\\\\uDFFF])))?|\\\\uDFFD(?:\\\\u200D(?:[\\\\u2695\\\\u2696\\\\u2708]\\\\uFE0F?|\\\\u2764\\\\uFE0F?\\\\u200D(?:\\\\uD83D\\\\uDC8B\\\\u200D)?\\\\uD83E\\\\uDDD1\\\\uD83C[\\\\uDFFB\\\\uDFFC\\\\uDFFE\\\\uDFFF]|\\\\uD83C[\\\\uDF3E\\\\uDF73\\\\uDF7C\\\\uDF84\\\\uDF93\\\\uDFA4\\\\uDFA8\\\\uDFEB\\\\uDFED]|\\\\uD83D(?:[\\\\uDCBB\\\\uDCBC\\\\uDD27\\\\uDD2C\\\\uDE80\\\\uDE92]|\\\\uDC30\\\\u200D\\\\uD83E\\\\uDDD1\\\\uD83C[\\\\uDFFB\\\\uDFFC\\\\uDFFE\\\\uDFFF])|\\\\uD83E(?:[\\\\uDDAF\\\\uDDBC\\\\uDDBD](?:\\\\u200D\\\\u27A1\\\\uFE0F?)?|[\\\\uDDB0-\\\\uDDB3\\\\uDE70]|\\\\uDD1D\\\\u200D\\\\uD83E\\\\uDDD1\\\\uD83C[\\\\uDFFB-\\\\uDFFF]|\\\\uDEEF\\\\u200D\\\\uD83E\\\\uDDD1\\\\uD83C[\\\\uDFFB\\\\uDFFC\\\\uDFFE\\\\uDFFF])))?|\\\\uDFFE(?:\\\\u200D(?:[\\\\u2695\\\\u2696\\\\u2708]\\\\uFE0F?|\\\\u2764\\\\uFE0F?\\\\u200D(?:\\\\uD83D\\\\uDC8B\\\\u200D)?\\\\uD83E\\\\uDDD1\\\\uD83C[\\\\uDFFB-\\\\uDFFD\\\\uD\\\nFFF]|\\\\uD83C[\\\\uDF3E\\\\uDF73\\\\uDF7C\\\\uDF84\\\\uDF93\\\\uDFA4\\\\uDFA8\\\\uDFEB\\\\uDFED]|\\\\uD83D(?:[\\\\uDCBB\\\\uDCBC\\\\uDD27\\\\uDD2C\\\\uDE80\\\\uDE92]|\\\\uDC30\\\\u200D\\\\uD83E\\\\uDDD1\\\\uD83C[\\\\uDFFB-\\\\uDFFD\\\\uDFFF])|\\\\uD83E(?:[\\\\uDDAF\\\\uDDBC\\\\uDDBD](?:\\\\u200D\\\\u27A1\\\\uFE0F?)?|[\\\\uDDB0-\\\\uDDB3\\\\uDE70]|\\\\uDD1D\\\\u200D\\\\uD83E\\\\uDDD1\\\\uD83C[\\\\uDFFB-\\\\uDFFF]|\\\\uDEEF\\\\u200D\\\\uD83E\\\\uDDD1\\\\uD83C[\\\\uDFFB-\\\\uDFFD\\\\uDFFF])))?|\\\\uDFFF(?:\\\\u200D(?:[\\\\u2695\\\\u2696\\\\u2708]\\\\uFE0F?|\\\\u2764\\\\uFE0F?\\\\u200D(?:\\\\uD83D\\\\uDC8B\\\\u200D)?\\\\uD83E\\\\uDDD1\\\\uD83C[\\\\uDFFB-\\\\uDFFE]|\\\\uD83C[\\\\uDF3E\\\\uDF73\\\\uDF7C\\\\uDF84\\\\uDF93\\\\uDFA4\\\\uDFA8\\\\uDFEB\\\\uDFED]|\\\\uD83D(?:[\\\\uDCBB\\\\uDCBC\\\\uDD27\\\\uDD2C\\\\uDE80\\\\uDE92]|\\\\uDC30\\\\u200D\\\\uD83E\\\\uDDD1\\\\uD83C[\\\\uDFFB-\\\\uDFFE])|\\\\uD83E(?:[\\\\uDDAF\\\\uDDBC\\\\uDDBD](?:\\\\u200D\\\\u27A1\\\\uFE0F?)?|[\\\\uDDB0-\\\\uDDB3\\\\uDE70]|\\\\uDD1D\\\\u200D\\\\uD83E\\\\uDDD1\\\\uD83C[\\\\uDFFB-\\\\uDFFF]|\\\\uDEEF\\\\u200D\\\\uD83E\\\\uDDD1\\\\uD83C[\\\\uDFFB-\\\\uDFFE])))?))?|\\\\uDEF1(?:\\\\uD83C(?:\\\\uDFFB(?:\\\\u200D\\\\uD83E\\\\uDEF2\\\\uD83C[\\\\uDFFC-\\\\uDFFF])?|\\\\uDFFC(?:\\\\u200D\\\\uD83E\\\\uDEF2\\\\uD83C[\\\\uDFFB\\\\uDFFD-\\\\uDFFF])?|\\\\uDFFD(?:\\\\u200D\\\\uD83E\\\\uDEF2\\\\uD83C[\\\\uDFFB\\\\uDFFC\\\\uDFFE\\\\uDFFF])?|\\\\uDFFE(?:\\\\\\\nu200D\\\\uD83E\\\\uDEF2\\\\uD83C[\\\\uDFFB-\\\\uDFFD\\\\uDFFF])?|\\\\uDFFF(?:\\\\u200D\\\\uD83E\\\\uDEF2\\\\uD83C[\\\\uDFFB-\\\\uDFFE])?))?)/g},Pa=de(ra());function Ia(e,t){var n=e.length,r=(Array.isArray(e[0])||(e=[e]),(t=Array.isArray(t[0])?t:t.map((function(e){return[e]})))[0].length),a=t[0].map((function(e,n){return t.map((function(e){return e[n]}))}));e=e.map((function(e){return a.map((function(t){var n=0;if(Array.isArray(e))for(var r=0;r<e.length;r++)n+=e[r]*(t[r]||0);else{var a,o=K(t);try{for(o.s();!(a=o.n()).done;)n+=e*a.value}catch(t){o.e(t)}finally{o.f()}}return n}))}));return 1===n&&(e=e[0]),1===r?e.map((function(e){return e[0]})):e}function Ba(e){return\"string\"===ja(e)}function ja(e){return(Object.prototype.toString.call(e).match(/^\\\\[object\\\\s+(.*?)\\\\]$/)[1]||\"\").toLowerCase()}function La(e,t){e=+e,t=+t;var n=(Math.floor(e)+\"\").length;return n<t?+e.toFixed(t-n):(n=Math.pow(10,n-t),Math.round(e/n)*n)}function qa(e){var t,n;if(e)return e=e.trim(),t=/^-?[\\\\d.]+$/,(e=e.match(/^([a-z]+)\\\\((.+?)\\\\)$/i))?(n=[],e[2].replace(\\\n/\\\\/?\\\\s*([-\\\\w.]+(?:%|deg)?)/g,(function(e,r){/%$/.test(r)?(r=new Number(r.slice(0,-1)/100)).type=\"<percentage>\":/deg$/.test(r)?((r=new Number(+r.slice(0,-3))).type=\"<angle>\",r.unit=\"deg\"):t.test(r)&&((r=new Number(r)).type=\"<number>\"),e.startsWith(\"/\")&&((r=r instanceof Number?r:new Number(r)).alpha=!0),n.push(r)})),{name:e[1].toLowerCase(),rawName:e[1],rawArgs:e[2],args:n}):void 0}function za(e){return e[e.length-1]}function Va(e,t,n){return isNaN(e)?t:isNaN(t)?e:e+(t-e)*n}function Ga(e,t,n){return(n-e)/(t-e)}function $a(e,t,n){return Va(t[0],t[1],Ga(e[0],e[1],n))}function Ha(e){return e.map((function(e){return e.split(\"|\").map((function(e){var t,n=(e=e.trim()).match(/^(<[a-z]+>)\\\\[(-?[.\\\\d]+),\\\\s*(-?[.\\\\d]+)\\\\]?$/);return n?((t=new String(n[1])).range=[+n[2],+n[3]],t):e}))}))}we=Object.freeze({__proto__:null,isString:Ba,type:ja,toPrecision:La,parseFunction:qa,last:za,interpolate:Va,interpolateInv:Ga,mapRange:$a,parseCoordGrammar:Ha,multiplyMatrices:Ia});var Ua=new(W((function e(){H(this,e)\\\n}),[{key:\"add\",value:function(e,t,n){if(\"string\"!=typeof arguments[0])for(var e in arguments[0])this.add(e,arguments[0][e],t);else(Array.isArray(e)?e:[e]).forEach((function(e){this[e]=this[e]||[],t&&this[e][n?\"unshift\":\"push\"](t)}),this)}},{key:\"run\",value:function(e,t){this[e]=this[e]||[],this[e].forEach((function(e){e.call(t&&t.context?t.context:t,t)}))}}])),Wa={gamut_mapping:\"lch.c\",precision:5,deltaE:\"76\"},Ya={D50:[.3457/.3585,1,.2958/.3585],D65:[.3127/.329,1,.3583/.329]};function Ka(e){return Array.isArray(e)?e:Ya[e]}function Xa(e,t,n,r){if(r=3<arguments.length&&void 0!==r?r:{},e=Ka(e),t=Ka(t),!e||!t)throw new TypeError(\"Missing white point to convert \".concat(e?\"\":\"from\").concat(e||t?\"\":\"/\").concat(t?\"\":\"to\"));if(e===t)return n;if(e={W1:e,W2:t,XYZ:n,options:r},Ua.run(\"chromatic-adaptation-start\",e),e.M||(e.W1===Ya.D65&&e.W2===Ya.D50?e.M=[[1.0479298208405488,.022946793341019088,-.05019222954313557],[.029627815688159344,.990434484573249,-.01707382502938514],[-.009243058152591178,.0\\\n15055144896577895,.7518742899580008]]:e.W1===Ya.D50&&e.W2===Ya.D65&&(e.M=[[.9554734527042182,-.023098536874261423,.0632593086610217],[-.028369706963208136,1.0099954580058226,.021041398966943008],[.012314001688319899,-.020507696433477912,1.3303659366080753]])),Ua.run(\"chromatic-adaptation-end\",e),e.M)return Ia(e.M,e.XYZ);throw new TypeError(\"Only Bradford CAT with white points D50 and D65 supported for now.\")}J=new WeakSet,Q=new WeakMap;var Za=W((function e(t){H(this,e),B(this,J),I(this,Q,void 0),this.id=t.id,this.name=t.name,this.base=t.base?Za.get(t.base):null,this.aliases=t.aliases,this.base&&(this.fromBase=t.fromBase,this.toBase=t.toBase);var n,r=null!=(r=t.coords)?r:this.base.coords;this.coords=r,r=null!=(r=null!=(r=t.white)?r:this.base.white)?r:\"D65\";for(n in this.white=Ka(r),this.formats=null!=(r=t.formats)?r:{},this.formats){var a=this.formats[n];a.type||(a.type=\"function\"),a.name||(a.name=n)}!t.cssId||null!=(r=this.formats.functions)&&r.color?null==(r=this.formats)||!r.color||n\\\null!=(r=this.formats)&&r.color.id||(this.formats.color.id=this.id):(this.formats.color={id:t.cssId},Object.defineProperty(this,\"cssId\",{value:t.cssId})),this.referred=t.referred,q(Q,this,z(J,this,Qa).call(this).reverse()),Ua.run(\"colorspace-init-end\",this)}),[{key:\"inGamut\",value:function(e){var t,n=(1<arguments.length&&void 0!==arguments[1]?arguments[1]:{}).epsilon,r=void 0===n?75e-6:n;return this.isPolar?(e=this.toBase(e),this.base.inGamut(e,{epsilon:r})):(t=Object.values(this.coords),e.every((function(e,n){var a;return\"angle\"===(n=t[n]).type||!n.range||!!Number.isNaN(e)||(a=(n=V(n.range,2))[0],n=n[1],(void 0===a||a-r<=e)&&(void 0===n||e<=n+r))})))}},{key:\"cssId\",get:function(){var e;return(null==(e=this.formats.functions)||null==(e=e.color)?void 0:e.id)||this.id}},{key:\"isPolar\",get:function(){for(var e in this.coords)if(\"angle\"===this.coords[e].type)return!0;return!1}},{key:\"getFormat\",value:function(e){return\"object\"===a(e)||(e=\"default\"===e?Object.values(this.formats)[0]:this.for\\\nmats[e])?z(J,this,Ja).call(this,e):null}},{key:\"to\",value:function(e,t){var n;if(1===arguments.length&&(e=(n=[e.space,e.coords])[0],t=n[1]),this!==(e=Za.get(e))){t=t.map((function(e){return Number.isNaN(e)?0:e}));for(var r,a,o=L(Q,this),i=L(Q,e),l=0;l<o.length&&o[l]===i[l];l++)r=o[l],a=l;if(!r)throw new Error(\"Cannot convert between color spaces \".concat(this,\" and \").concat(e,\": no connection space was found\"));for(var u=o.length-1;a<u;u--)t=o[u].toBase(t);for(var s=a+1;s<i.length;s++)t=i[s].fromBase(t)}return t}},{key:\"from\",value:function(e,t){var n;return 1===arguments.length&&(e=(n=[e.space,e.coords])[0],t=n[1]),(e=Za.get(e)).to(this,t)}},{key:\"toString\",value:function(){return\"\".concat(this.name,\" (\").concat(this.id,\")\")}},{key:\"getMinCoords\",value:function(){var e,t=[];for(e in this.coords){var n=(n=this.coords[e]).range||n.refRange;t.push(null!=(n=null==n?void 0:n.min)?n:0)}return t}}],[{key:\"all\",get:function(){return M(new Set(Object.values(Za.registry)))}},{key:\"register\",va\\\nlue:function(e,t){if(1===arguments.length&&(e=(t=arguments[0]).id),t=this.get(t),this.registry[e]&&this.registry[e]!==t)throw new Error(\"Duplicate color space registration: '\".concat(e,\"'\"));if(this.registry[e]=t,1===arguments.length&&t.aliases){var n,r=K(t.aliases);try{for(r.s();!(n=r.n()).done;){var a=n.value;this.register(a,t)}}catch(e){r.e(e)}finally{r.f()}}return t}},{key:\"get\",value:function(e){if(!e||e instanceof Za)return e;if(\"string\"===ja(e)){var t=Za.registry[e.toLowerCase()];if(t)return t;throw new TypeError('No color space found with id = \"'.concat(e,'\"'))}for(var n=arguments.length,r=new Array(1<n?n-1:0),a=1;a<n;a++)r[a-1]=arguments[a];if(r.length)return Za.get.apply(Za,r);throw new TypeError(\"\".concat(e,\" is not a valid color space\"))}},{key:\"resolveCoord\",value:function(e,t){var n,r;if(r=\"string\"===ja(e)?e.includes(\".\")?(n=(r=V(e.split(\".\"),2))[0],r[1]):(n=void 0,e):Array.isArray(e)?(n=(r=V(e,2))[0],r[1]):(n=e.space,e.coordId),!(n=(n=Za.get(n))||t))throw new TypeError(\"\\\nCannot resolve coordinate reference \".concat(e,\": No color space specified and relative references are not allowed here\"));if((\"number\"===(t=ja(r))||\"string\"===t&&0<=r)&&(e=Object.entries(n.coords)[r]))return O({space:n,id:e[0],index:r},e[1]);n=Za.get(n);var a,o=r.toLowerCase(),i=0;for(a in n.coords){var l,u=n.coords[a];if(a.toLowerCase()===o||(null==(l=u.name)?void 0:l.toLowerCase())===o)return O({space:n,id:a,index:i},u);i++}throw new TypeError('No \"'.concat(r,'\" coordinate found in ').concat(n.name,\". Its coordinates are: \").concat(Object.keys(n.coords).join(\", \")))}}]);function Ja(e){var t;return e.coords&&!e.coordGrammar&&(e.type||(e.type=\"function\"),e.name||(e.name=\"color\"),e.coordGrammar=Ha(e.coords),t=Object.entries(this.coords).map((function(t,n){(t=V(t,2))[0],t=t[1],n=e.coordGrammar[n][0],t=t.range||t.refRange;var r=n.range,a=\"\";return\"<percentage>\"==n?(r=[0,100],a=\"%\"):\"<angle>\"==n&&(a=\"deg\"),{fromRange:t,toRange:r,suffix:a}})),e.serializeCoords=function(e,n){return e.map((f\\\nunction(e,r){var a=(r=t[r]).fromRange,o=r.toRange;r=r.suffix;return e=La(e=a&&o?$a(a,o,e):e,n),r&&(e+=r),e}))}),e}function Qa(){for(var e=[this],t=this;t=t.base;)e.push(t);return e}var eo=Za,to=(pe(eo,\"registry\",{}),pe(eo,\"DEFAULT_FORMAT\",{type:\"functions\",name:\"color\"}),new eo({id:\"xyz-d65\",name:\"XYZ D65\",coords:{x:{name:\"X\"},y:{name:\"Y\"},z:{name:\"Z\"}},white:\"D65\",formats:{color:{ids:[\"xyz-d65\",\"xyz\"]}},aliases:[\"xyz\"]}));S(no,eo),Dt=W(no);function no(e){var t;return H(this,no),e.coords||(e.coords={r:{range:[0,1],name:\"Red\"},g:{range:[0,1],name:\"Green\"},b:{range:[0,1],name:\"Blue\"}}),e.base||(e.base=to),e.toXYZ_M&&e.fromXYZ_M&&(null==e.toBase&&(e.toBase=function(n){return n=Ia(e.toXYZ_M,n),t.white!==t.base.white?Xa(t.white,t.base.white,n):n}),null==e.fromBase)&&(e.fromBase=function(n){return n=Xa(t.base.white,t.white,n),Ia(e.fromXYZ_M,n)}),null==e.referred&&(e.referred=\"display\"),t=R(this,no,[e])}function ro(e){var t={str:null==(s=String(e))?void 0:s.trim()};if(Ua.run(\"parse-start\",t),\\\nt.color)return t.color;if(t.parsed=qa(t.str),t.parsed){var n=t.parsed.name;if(\"color\"===n){var r,a=t.parsed.args.shift(),o=0<t.parsed.rawArgs.indexOf(\"/\")?t.parsed.args.pop():1,i=K(eo.all);try{var l;for(i.s();!(r=i.n()).done;)if(l=(()=>{var e,n=r.value,i=n.getFormat(\"color\");if(i&&(a===i.id||null!=(i=i.ids)&&i.includes(a)))return i=Object.keys(n.coords).length,(e=Array(i).fill(0)).forEach((function(n,r){return e[r]=t.parsed.args[r]||0})),{v:{spaceId:n.id,coords:e,alpha:o}}})())return l.v}catch(e){i.e(e)}finally{i.f()}var u,s=\"\";throw a in eo.registry&&(u=null==(u=eo.registry[a].formats)||null==(u=u.functions)||null==(u=u.color)?void 0:u.id)&&(s=\"Did you mean color(\".concat(u,\")?\")),new TypeError(\"Cannot parse color(\".concat(a,\"). \")+(s||\"Missing a plugin?\"))}var c,d=K(eo.all);try{var p;for(d.s();!(c=d.n()).done;)if(p=(()=>{var e,r,a=c.value,o=a.getFormat(n);if(o&&\"function\"===o.type)return e=1,(o.lastAlpha||za(t.parsed.args).alpha)&&(e=t.parsed.args.pop()),r=t.parsed.args,o.coordGramma\\\nr&&Object.entries(a.coords).forEach((function(e,t){var a=(e=V(e,2))[0],i=(e=e[1],o.coordGrammar[t]),l=null==(u=r[t])?void 0:u.type;if(!(i=i.find((function(e){return e==l}))))throw u=e.name||a,new TypeError(\"\".concat(l,\" not allowed for \").concat(u,\" in \").concat(n,\"()\"));a=i.range;var u=e.range||e.refRange;(a=\"<percentage>\"===l?a||[0,1]:a)&&u&&(r[t]=$a(a,u,r[t]))})),{v:{spaceId:a.id,coords:r,alpha:e}}})())return p.v}catch(e){d.e(e)}finally{d.f()}}else{var f,m=K(eo.all);try{for(m.s();!(f=m.n()).done;){var h,g=f.value;for(h in g.formats){var v=g.formats[h];if(\"custom\"===v.type&&(!v.test||v.test(t.str))){var b=v.parse(t.str);if(b)return null==b.alpha&&(b.alpha=1),b}}}}catch(e){m.e(e)}finally{m.f()}}throw new TypeError(\"Could not parse \".concat(e,\" as a color. Missing a plugin?\"))}function ao(e){var t;if(e)return(t=(e=Ba(e)?ro(e):e).space||e.spaceId)instanceof eo||(e.space=eo.get(t)),void 0===e.alpha&&(e.alpha=1),e;throw new TypeError(\"Empty color reference\")}function oo(e,t){return(t=eo.g\\\net(t)).from(e)}function io(e,t){var n=(t=eo.resolveCoord(t,e.space)).space;t=t.index;return oo(e,n)[t]}function lo(e,t,n){return t=eo.get(t),e.coords=t.to(e.space,n),e}function uo(e,t,n){if(e=ao(e),2===arguments.length&&\"object\"===ja(t)){var r,a=t;for(r in a)uo(e,r,a[r])}else{\"function\"==typeof n&&(n=n(io(e,t)));var o=(t=eo.resolveCoord(t,e.space)).space,i=(t=t.index,oo(e,o));i[t]=n,lo(e,o,i)}return e}ye=new eo({id:\"xyz-d50\",name:\"XYZ D50\",white:\"D50\",base:to,fromBase:function(e){return Xa(to.white,\"D50\",e)},toBase:function(e){return Xa(\"D50\",to.white,e)},formats:{color:{}}});var so=24389/27,co=Ya.D50,po=new eo({id:\"lab\",name:\"Lab\",coords:{l:{refRange:[0,100],name:\"L\"},a:{refRange:[-125,125]},b:{refRange:[-125,125]}},white:co,base:ye,fromBase:function(e){return e=e.map((function(e,t){return e/co[t]})).map((function(e){return 216/24389<e?Math.cbrt(e):(so*e+16)/116})),[116*e[1]-16,500*(e[0]-e[1]),200*(e[1]-e[2])]},toBase:function(e){var t=[];return t[1]=(e[0]+16)/116,t[0]=e[1]/500+t[1],t\\\n[2]=t[1]-e[2]/200,[24/116<t[0]?Math.pow(t[0],3):(116*t[0]-16)/so,8<e[0]?Math.pow((e[0]+16)/116,3):e[0]/so,24/116<t[2]?Math.pow(t[2],3):(116*t[2]-16)/so].map((function(e,t){return e*co[t]}))},formats:{lab:{coords:[\"<number> | <percentage>\",\"<number>\",\"<number>\"]}}});function fo(e){return(e%360+360)%360}var mo=new eo({id:\"lch\",name:\"LCH\",coords:{l:{refRange:[0,100],name:\"Lightness\"},c:{refRange:[0,150],name:\"Chroma\"},h:{refRange:[0,360],type:\"angle\",name:\"Hue\"}},base:po,fromBase:function(e){var t=(e=V(e,3))[0],n=e[1],r=(e=e[2],Math.abs(n)<.02&&Math.abs(e)<.02?NaN:180*Math.atan2(e,n)/Math.PI);return[t,Math.sqrt(Math.pow(n,2)+Math.pow(e,2)),fo(r)]},toBase:function(e){var t=(e=V(e,3))[0],n=e[1];e=e[2];return n<0&&(n=0),isNaN(e)&&(e=0),[t,n*Math.cos(e*Math.PI/180),n*Math.sin(e*Math.PI/180)]},formats:{lch:{coords:[\"<number> | <percentage>\",\"<number>\",\"<number> | <angle>\"]}}}),ho=Math.pow(25,7),go=Math.PI,vo=180/go,bo=go/180;function yo(e,t){var n=void 0===(n=(a=2<arguments.length&&void 0!==ar\\\nguments[2]?arguments[2]:{}).kL)?1:n,r=void 0===(r=a.kC)?1:r,a=void 0===(a=a.kH)?1:a,o=(e=V(po.from(e),3))[0],i=e[1],l=(e=e[2],mo.from(po,[o,i,e])[1]),u=(t=V(po.from(t),3))[0],s=t[1],c=(t=t[2],l=((l=l<0?0:l)+(c=(c=mo.from(po,[u,s,t])[1])<0?0:c))/2,Math.pow(l,7)),d=(c=(1+(l=.5*(1-Math.sqrt(c/(c+ho)))))*i,i=(1+l)*s,l=Math.sqrt(Math.pow(c,2)+Math.pow(e,2)),s=Math.sqrt(Math.pow(i,2)+Math.pow(t,2)),e=0==c&&0===e?0:Math.atan2(e,c),c=0==i&&0===t?0:Math.atan2(t,i),t=(e<0&&(e+=2*go),c<0&&(c+=2*go),u-o),i=s-l,(c*=vo)-(e*=vo)),p=(e=e+c,c=Math.abs(d),d=(l*s==0?p=0:c<=180?p=d:180<d?p=d-360:d<-180?p=360+d:console.log(\"the unthinkable has happened\"),2*Math.sqrt(s*l)*Math.sin(p*bo/2)),(o+u)/2);o=(l+s)/2,u=Math.pow(o,7),l=l*s==0?e:c<=180?e/2:e<360?(e+360)/2:(e-360)/2,c=1+.015*(s=Math.pow(p-50,2))/Math.sqrt(20+s),e=1+.045*o,p=1,s=1+.015*o*((p-=.17*Math.cos((l-30)*bo))+.24*Math.cos(2*l*bo)+.32*Math.cos((3*l+6)*bo)-.2*Math.cos((4*l-63)*bo)),o=30*Math.exp(-1*Math.pow((l-275)/25,2)),p=2*Math.sqrt(u/(u+ho)),l\\\n=-1*Math.sin(2*o*bo)*p,u=Math.pow(t/(n*c),2),u=(u+=Math.pow(i/(r*e),2))+Math.pow(d/(a*s),2)+i/(r*e)*l*(d/(a*s));return Math.sqrt(u)}var Do=75e-6;function wo(e){var t=1<arguments.length&&void 0!==arguments[1]?arguments[1]:e.space,n=void 0===(n=(2<arguments.length&&void 0!==arguments[2]?arguments[2]:{}).epsilon)?Do:n,r=(e=ao(e),t=eo.get(t),e.coords);return t!==e.space&&(r=t.from(e)),t.inGamut(r,{epsilon:n})}function xo(e){return{space:e.space,coords:e.coords.slice(),alpha:e.alpha}}function Eo(e){var t=void 0===(t=(a=1<arguments.length&&void 0!==arguments[1]?arguments[1]:{}).method)?Wa.gamut_mapping:t,n=void 0===(a=a.space)?e.space:a;if(Ba(arguments[1])&&(n=arguments[1]),!wo(e,n=eo.get(n),{epsilon:0})){var r,a=Ao(e,n);if(\"clip\"!==t&&!wo(e,n)){var o=Eo(xo(a),{method:\"clip\",space:n});if(2<yo(e,o)){for(var i=eo.resolveCoord(t),l=i.space,u=i.id,s=Ao(a,l),c=(i.range||i.refRange)[0],d=io(s,u);.01<d-c;)yo(s,Eo(xo(s),{space:n,method:\"clip\"}))-2<.01?c=io(s,u):d=io(s,u),uo(s,u,(c+d)/2);a=Ao(s,n)}el\\\nse a=o}\"clip\"!==t&&wo(a,n,{epsilon:0})||(r=Object.values(n.coords).map((function(e){return e.range||[]})),a.coords=a.coords.map((function(e,t){var n=(t=V(r[t],2))[0];t=t[1];return void 0!==n&&(e=Math.max(n,e)),void 0!==t?Math.min(e,t):e}))),n!==e.space&&(a=Ao(a,e.space)),e.coords=a.coords}return e}function Ao(e,t){var n=(2<arguments.length&&void 0!==arguments[2]?arguments[2]:{}).inGamut,r=(e=ao(e),(t=eo.get(t)).from(e));t={space:t,coords:r,alpha:e.alpha};return n?Eo(t):t}function Fo(e){var t=void 0===(n=(a=1<arguments.length&&void 0!==arguments[1]?arguments[1]:{}).precision)?Wa.precision:n,n=void 0===(n=a.format)?\"default\":n,r=void 0===(r=a.inGamut)||r,a=k(a,i),o=n,l=(n=null!=(l=null!=(l=(e=ao(e)).space.getFormat(n))?l:e.space.getFormat(\"default\"))?l:eo.DEFAULT_FORMAT,r=r||n.toGamut,(l=e.coords).map((function(e){return e||0})));if(r&&!wo(e)&&(l=Eo(xo(e),!0===r?void 0:r).coords),\"custom\"===n.type){if(a.precision=t,!n.serialize)throw new TypeError(\"format \".concat(o,\" can only be used to\\\n parse colors, not for serialization\"));u=n.serialize(l,e.alpha,a)}else{r=n.name||\"color\",o=(n.serializeCoords?l=n.serializeCoords(l,t):null!==t&&(l=l.map((function(e){return La(e,t)}))),M(l)),a=(\"color\"===r&&(l=n.id||(null==(a=n.ids)?void 0:a[0])||e.space.id,o.unshift(l)),e.alpha),l=(null!==t&&(a=La(a,t)),e.alpha<1&&!n.noAlpha?\"\".concat(n.commas?\",\":\" /\",\" \").concat(a):\"\");var u=\"\".concat(r,\"(\").concat(o.join(n.commas?\", \":\" \")).concat(l,\")\")}return u}Ao.returns=Eo.returns=\"color\";De=new Dt({id:\"rec2020-linear\",name:\"Linear REC.2020\",white:\"D65\",toXYZ_M:[[.6369580483012914,.14461690358620832,.1688809751641721],[.2627002120112671,.6779980715188708,.05930171646986196],[0,.028072693049087428,1.060985057710791]],fromXYZ_M:[[1.716651187971268,-.355670783776392,-.25336628137366],[-.666684351832489,1.616481236634939,.0157685458139111],[.017639857445311,-.042770613257809,.942103121235474]],formats:{color:{}}});var Co=1.09929682680944,ko=.018053968510807,Ro=(jt=new Dt({id:\"rec2020\",name:\"REC.2\\\n020\",base:De,toBase:function(e){return e.map((function(e){return e<4.5*ko?e/4.5:Math.pow((e+Co-1)/Co,1/.45)}))},fromBase:function(e){return e.map((function(e){return ko<=e?Co*Math.pow(e,.45)-(Co-1):4.5*e}))},formats:{color:{}}}),Cn=new Dt({id:\"p3-linear\",name:\"Linear P3\",white:\"D65\",toXYZ_M:[[.4865709486482162,.26566769316909306,.1982172852343625],[.2289745640697488,.6917385218365064,.079286914093745],[0,.04511338185890264,1.043944368900976]],fromXYZ_M:[[2.493496911941425,-.9313836179191239,-.40271078445071684],[-.8294889695615747,1.7626640603183463,.023624685841943577],[.03584583024378447,-.07617238926804182,.9568845240076872]]}),kn=new Dt({id:\"srgb-linear\",name:\"Linear sRGB\",white:\"D65\",toXYZ_M:[[.41239079926595934,.357584339383878,.1804807884018343],[.21263900587151027,.715168678767756,.07219231536073371],[.01933081871559182,.11919477979462598,.9505321522496607]],fromXYZ_M:[[3.2409699419045226,-1.537383177570094,-.4986107602930034],[-.9692436362808796,1.8759675015077202,.04155505740\\\n717559],[.05563007969699366,-.20397695888897652,1.0569715142428786]],formats:{color:{}}}),{aliceblue:[240/255,248/255,1],antiquewhite:[250/255,235/255,215/255],aqua:[0,1,1],aquamarine:[127/255,1,212/255],azure:[240/255,1,1],beige:[245/255,245/255,220/255],bisque:[1,228/255,196/255],black:[0,0,0],blanchedalmond:[1,235/255,205/255],blue:[0,0,1],blueviolet:[138/255,43/255,226/255],brown:[165/255,42/255,42/255],burlywood:[222/255,184/255,135/255],cadetblue:[95/255,158/255,160/255],chartreuse:[127/255,1,0],chocolate:[210/255,105/255,30/255],coral:[1,127/255,80/255],cornflowerblue:[100/255,149/255,237/255],cornsilk:[1,248/255,220/255],crimson:[220/255,20/255,60/255],cyan:[0,1,1],darkblue:[0,0,139/255],darkcyan:[0,139/255,139/255],darkgoldenrod:[184/255,134/255,11/255],darkgray:[169/255,169/255,169/255],darkgreen:[0,100/255,0],darkgrey:[169/255,169/255,169/255],darkkhaki:[189/255,183/255,107/255],darkmagenta:[139/255,0,139/255],darkolivegreen:[85/255,107/255,47/255],darkorange:[1,140/255,0],d\\\narkorchid:[.6,50/255,.8],darkred:[139/255,0,0],darksalmon:[233/255,150/255,122/255],darkseagreen:[143/255,188/255,143/255],darkslateblue:[72/255,61/255,139/255],darkslategray:[47/255,79/255,79/255],darkslategrey:[47/255,79/255,79/255],darkturquoise:[0,206/255,209/255],darkviolet:[148/255,0,211/255],deeppink:[1,20/255,147/255],deepskyblue:[0,191/255,1],dimgray:[105/255,105/255,105/255],dimgrey:[105/255,105/255,105/255],dodgerblue:[30/255,144/255,1],firebrick:[178/255,34/255,34/255],floralwhite:[1,250/255,240/255],forestgreen:[34/255,139/255,34/255],fuchsia:[1,0,1],gainsboro:[220/255,220/255,220/255],ghostwhite:[248/255,248/255,1],gold:[1,215/255,0],goldenrod:[218/255,165/255,32/255],gray:[128/255,128/255,128/255],green:[0,128/255,0],greenyellow:[173/255,1,47/255],grey:[128/255,128/255,128/255],honeydew:[240/255,1,240/255],hotpink:[1,105/255,180/255],indianred:[205/255,92/255,92/255],indigo:[75/255,0,130/255],ivory:[1,1,240/255],khaki:[240/255,230/255,140/255],lavender:[230/255,230/255,2\\\n50/255],lavenderblush:[1,240/255,245/255],lawngreen:[124/255,252/255,0],lemonchiffon:[1,250/255,205/255],lightblue:[173/255,216/255,230/255],lightcoral:[240/255,128/255,128/255],lightcyan:[224/255,1,1],lightgoldenrodyellow:[250/255,250/255,210/255],lightgray:[211/255,211/255,211/255],lightgreen:[144/255,238/255,144/255],lightgrey:[211/255,211/255,211/255],lightpink:[1,182/255,193/255],lightsalmon:[1,160/255,122/255],lightseagreen:[32/255,178/255,170/255],lightskyblue:[135/255,206/255,250/255],lightslategray:[119/255,136/255,.6],lightslategrey:[119/255,136/255,.6],lightsteelblue:[176/255,196/255,222/255],lightyellow:[1,1,224/255],lime:[0,1,0],limegreen:[50/255,205/255,50/255],linen:[250/255,240/255,230/255],magenta:[1,0,1],maroon:[128/255,0,0],mediumaquamarine:[.4,205/255,170/255],mediumblue:[0,0,205/255],mediumorchid:[186/255,85/255,211/255],mediumpurple:[147/255,112/255,219/255],mediumseagreen:[60/255,179/255,113/255],mediumslateblue:[123/255,104/255,238/255],mediumspringgreen:[0,250/\\\n255,154/255],mediumturquoise:[72/255,209/255,.8],mediumvioletred:[199/255,21/255,133/255],midnightblue:[25/255,25/255,112/255],mintcream:[245/255,1,250/255],mistyrose:[1,228/255,225/255],moccasin:[1,228/255,181/255],navajowhite:[1,222/255,173/255],navy:[0,0,128/255],oldlace:[253/255,245/255,230/255],olive:[128/255,128/255,0],olivedrab:[107/255,142/255,35/255],orange:[1,165/255,0],orangered:[1,69/255,0],orchid:[218/255,112/255,214/255],palegoldenrod:[238/255,232/255,170/255],palegreen:[152/255,251/255,152/255],paleturquoise:[175/255,238/255,238/255],palevioletred:[219/255,112/255,147/255],papayawhip:[1,239/255,213/255],peachpuff:[1,218/255,185/255],peru:[205/255,133/255,63/255],pink:[1,192/255,203/255],plum:[221/255,160/255,221/255],powderblue:[176/255,224/255,230/255],purple:[128/255,0,128/255],rebeccapurple:[.4,.2,.6],red:[1,0,0],rosybrown:[188/255,143/255,143/255],royalblue:[65/255,105/255,225/255],saddlebrown:[139/255,69/255,19/255],salmon:[250/255,128/255,114/255],sandybrown:[244/2\\\n55,164/255,96/255],seagreen:[46/255,139/255,87/255],seashell:[1,245/255,238/255],sienna:[160/255,82/255,45/255],silver:[192/255,192/255,192/255],skyblue:[135/255,206/255,235/255],slateblue:[106/255,90/255,205/255],slategray:[112/255,128/255,144/255],slategrey:[112/255,128/255,144/255],snow:[1,250/255,250/255],springgreen:[0,1,127/255],steelblue:[70/255,130/255,180/255],tan:[210/255,180/255,140/255],teal:[0,128/255,128/255],thistle:[216/255,191/255,216/255],tomato:[1,99/255,71/255],turquoise:[64/255,224/255,208/255],violet:[238/255,130/255,238/255],wheat:[245/255,222/255,179/255],white:[1,1,1],whitesmoke:[245/255,245/255,245/255],yellow:[1,1,0],yellowgreen:[154/255,205/255,50/255]}),No=(ra=new Dt({id:\"srgb\",name:\"sRGB\",base:kn,fromBase:function(e){return e.map((function(e){var t=e<0?-1:1,n=e*t;return.0031308<n?t*(1.055*Math.pow(n,1/2.4)-.055):12.92*e}))},toBase:function(e){return e.map((function(e){var t=e<0?-1:1,n=e*t;return n<.04045?e/12.92:t*Math.pow((.055+n)/1.055,2.4)}))},formats:{\\\nrgb:{coords:ra=Array(3).fill(\"<percentage> | <number>[0, 255]\")},rgb_number:{name:\"rgb\",commas:!0,coords:No=Array(3).fill(\"<number>[0, 255]\"),noAlpha:!0},color:{},rgba:{coords:ra,commas:!0,lastAlpha:!0},rgba_number:{name:\"rgba\",commas:!0,coords:No},hex:{type:\"custom\",toGamut:!0,test:function(e){return/^#([a-f0-9]{3,4}){1,2}$/i.test(e)},parse:function(e){e.length<=5&&(e=e.replace(/[a-f0-9]/gi,\"$&$&\"));var t=[];return e.replace(/[a-f0-9]{2}/gi,(function(e){t.push(parseInt(e,16)/255)})),{spaceId:\"srgb\",coords:t.slice(0,3),alpha:t.slice(3)[0]}},serialize:function(e,t){var n=void 0===(n=(2<arguments.length&&void 0!==arguments[2]?arguments[2]:{}).collapse)||n,r=(t<1&&e.push(t),e=e.map((function(e){return Math.round(255*e)})),n&&e.every((function(e){return e%17==0})));return\"#\"+e.map((function(e){return r?(e/17).toString(16):e.toString(16).padStart(2,\"0\")})).join(\"\")}},keyword:{type:\"custom\",test:function(e){return/^[a-z]+$/i.test(e)},parse:function(e){var t={spaceId:\"srgb\",coords:null,alpha:\\\n1};if(\"transparent\"===(e=e.toLowerCase())?(t.coords=Ro.black,t.alpha=0):t.coords=Ro[e],t.coords)return t}}}}),new Dt({id:\"p3\",name:\"P3\",base:Cn,fromBase:ra.fromBase,toBase:ra.toBase,formats:{color:{id:\"display-p3\"}}}));if(Wa.display_space=ra,\"undefined\"!=typeof CSS&&null!=(ue=CSS)&&ue.supports)for(var To=0,So=[po,jt,No];To<So.length;To++){var _o=So[To],Oo=_o.getMinCoords();Oo=Fo({space:_o,coords:Oo,alpha:1});if(CSS.supports(\"color\",Oo)){Wa.display_space=_o;break}}function Mo(e,t){var n=2<arguments.length&&void 0!==arguments[2]?arguments[2]:\"lab\",r=(e=(n=eo.get(n)).from(e),n.from(t));return Math.sqrt(e.reduce((function(e,t,n){return n=r[n],isNaN(t)||isNaN(n)?e:e+Math.pow(n-t,2)}),0))}function Po(e){return io(e,[to,\"y\"])}function Io(e,t){uo(e,[to,\"y\"],t)}ue=Object.freeze({__proto__:null,getLuminance:Po,setLuminance:Io,register:function(e){Object.defineProperty(e.prototype,\"luminance\",{get:function(){return Po(this)},set:function(e){Io(this,e)}})}});function Bo(e){return.022<=e?e:e+Math.p\\\now(.022-e,1.414)}function jo(e){var t=e<0?-1:1;e=Math.abs(e);return t*Math.pow(e,2.4)}var Lo=24389/27,qo=Ya.D65,zo=new eo({id:\"lab-d65\",name:\"Lab D65\",coords:{l:{refRange:[0,100],name:\"L\"},a:{refRange:[-125,125]},b:{refRange:[-125,125]}},white:qo,base:to,fromBase:function(e){return e=e.map((function(e,t){return e/qo[t]})).map((function(e){return 216/24389<e?Math.cbrt(e):(Lo*e+16)/116})),[116*e[1]-16,500*(e[0]-e[1]),200*(e[1]-e[2])]},toBase:function(e){var t=[];return t[1]=(e[0]+16)/116,t[0]=e[1]/500+t[1],t[2]=t[1]-e[2]/200,[24/116<t[0]?Math.pow(t[0],3):(116*t[0]-16)/Lo,8<e[0]?Math.pow((e[0]+16)/116,3):e[0]/Lo,24/116<t[2]?Math.pow(t[2],3):(116*t[2]-16)/Lo].map((function(e,t){return e*qo[t]}))},formats:{\"lab-d65\":{coords:[\"<number> | <percentage>\",\"<number>\",\"<number>\"]}}}),Vo=.5*Math.pow(5,.5)+.5,Go=Object.freeze({__proto__:null,contrastWCAG21:function(e,t){var n;return e=ao(e),t=ao(t),(e=Math.max(Po(e),0))<(t=Math.max(Po(t),0))&&(e=(n=[t,e])[0],t=n[1]),(e+.05)/(t+.05)},contrastAPCA:fun\\\nction(e,t){t=ao(t),e=ao(e);var n=(t=V((t=Ao(t,\"srgb\")).coords,3))[0],r=t[1],a=(t=t[2],.2126729*jo(n)+.7151522*jo(r)+.072175*jo(t));n=(e=V((e=Ao(e,\"srgb\")).coords,3))[0],r=e[1],t=e[2],e=.2126729*jo(n)+.7151522*jo(r)+.072175*jo(t),t=(n=Bo(a))<(r=Bo(e)),a=Math.abs(r-n)<5e-4?0:t?1.14*(Math.pow(r,.56)-Math.pow(n,.57)):1.14*(Math.pow(r,.65)-Math.pow(n,.62));return 100*(Math.abs(a)<.1?0:0<a?a-.027:a+.027)},contrastMichelson:function(e,t){e=ao(e),t=ao(t);var n=((e=Math.max(Po(e),0))<(t=Math.max(Po(t),0))&&(e=(n=[t,e])[0],t=n[1]),e+t);return 0===n?0:(e-t)/n},contrastWeber:function(e,t){var n;return e=ao(e),t=ao(t),(e=Math.max(Po(e),0))<(t=Math.max(Po(t),0))&&(e=(n=[t,e])[0],t=n[1]),0===t?5e4:(e-t)/t},contrastLstar:function(e,t){return e=ao(e),t=ao(t),e=io(e,[po,\"l\"]),t=io(t,[po,\"l\"]),Math.abs(e-t)},contrastDeltaPhi:function(e,t){return e=ao(e),t=ao(t),e=io(e,[zo,\"l\"]),t=io(t,[zo,\"l\"]),e=Math.abs(Math.pow(e,Vo)-Math.pow(t,Vo)),(t=Math.pow(e,1/Vo)*Math.SQRT2-40)<7.5?0:t}});function $o(e){var t=(e\\\n=V(oo(e,to),3))[0],n=e[1];return[4*t/(e=t+15*n+3*e[2]),9*n/e]}function Ho(e){var t=(e=V(oo(e,to),3))[0],n=e[1];return[t/(e=t+n+e[2]),n/e]}var Uo=Object.freeze({__proto__:null,uv:$o,xy:Ho,register:function(e){Object.defineProperty(e.prototype,\"uv\",{get:function(){return $o(this)}}),Object.defineProperty(e.prototype,\"xy\",{get:function(){return Ho(this)}})}}),Wo=Math.PI/180,Yo=new eo({id:\"xyz-abs-d65\",name:\"Absolute XYZ D65\",coords:{x:{refRange:[0,9504.7],name:\"Xa\"},y:{refRange:[0,1e4],name:\"Ya\"},z:{refRange:[0,10888.3],name:\"Za\"}},base:to,fromBase:function(e){return e.map((function(e){return Math.max(203*e,0)}))},toBase:function(e){return e.map((function(e){return Math.max(e/203,0)}))}}),Ko=2610/Math.pow(2,14),Xo=Math.pow(2,14)/2610,Zo=3424/Math.pow(2,12),Jo=2413/Math.pow(2,7),Qo=2392/Math.pow(2,7),ei=1.7*2523/Math.pow(2,5),ti=Math.pow(2,5)/(1.7*2523),ni=16295499532821565e-27,ri=[[.41478972,.579999,.014648],[-.20151,1.120649,.0531008],[-.0166008,.2648,.6684799]],ai=[[1.9242264357876067,-\\\n1.0047923125953657,.037651404030618],[.35031676209499907,.7264811939316552,-.06538442294808501],[-.09098281098284752,-.3127282905230739,1.5227665613052603]],oi=[[.5,.5,0],[3.524,-4.066708,.542708],[.199076,1.096799,-1.295875]],ii=[[1,.1386050432715393,.05804731615611886],[.9999999999999999,-.1386050432715393,-.05804731615611886],[.9999999999999998,-.09601924202631895,-.8118918960560388]],li=new eo({id:\"jzazbz\",name:\"Jzazbz\",coords:{jz:{refRange:[0,1],name:\"Jz\"},az:{refRange:[-.5,.5]},bz:{refRange:[-.5,.5]}},base:Yo,fromBase:function(e){var t=(e=V(e,3))[0],n=e[2];e=Ia(ri,[1.15*t-(1.15-1)*n,.66*e[1]-(.66-1)*t,n]).map((function(e){var t=Zo+Jo*Math.pow(e/1e4,Ko);e=1+Qo*Math.pow(e/1e4,Ko);return Math.pow(t/e,ei)}));return[(1-.56)*(n=(t=V(Ia(oi,e),3))[0])/(1+-.56*n)-ni,t[1],t[2]]},toBase:function(e){var t=(e=V(e,3))[0],n=(t=Ia(ii,[(t+ni)/(1-.56- -.56*(t+ni)),e[1],e[2]]).map((function(e){var t=Zo-Math.pow(e,ti);e=Qo*Math.pow(e,ti)-Jo;return 1e4*Math.pow(t/e,Xo)})),t=(e=V(Ia(ai,t),3))[0],e[2])\\\n;return[t=(t+(1.15-1)*n)/1.15,(e[1]+(.66-1)*t)/.66,n]},formats:{color:{}}}),ui=new eo({id:\"jzczhz\",name:\"JzCzHz\",coords:{jz:{refRange:[0,1],name:\"Jz\"},cz:{refRange:[0,1],name:\"Chroma\"},hz:{refRange:[0,360],type:\"angle\",name:\"Hue\"}},base:li,fromBase:function(e){var t=(e=V(e,3))[0],n=e[1],r=(e=e[2],Math.abs(n)<2e-4&&Math.abs(e)<2e-4?NaN:180*Math.atan2(e,n)/Math.PI);return[t,Math.sqrt(Math.pow(n,2)+Math.pow(e,2)),fo(r)]},toBase:function(e){return[e[0],e[1]*Math.cos(e[2]*Math.PI/180),e[1]*Math.sin(e[2]*Math.PI/180)]},formats:{color:{}}}),si=2610/16384,ci=[[.3592,.6976,-.0358],[-.1922,1.1004,.0755],[.007,.0749,.8434]],di=[[.5,.5,0],[6610/4096,-13613/4096,7003/4096],[17933/4096,-17390/4096,-543/4096]],pi=[[.9999888965628402,.008605050147287059,.11103437159861648],[1.00001110343716,-.008605050147287059,-.11103437159861648],[1.0000320633910054,.56004913547279,-.3206339100541203]],fi=[[2.0701800566956137,-1.326456876103021,.20661600684785517],[.3649882500326575,.6804673628522352,-.0454217530758\\\n5323],[-.04959554223893211,-.04942116118675749,1.1879959417328034]],mi=new eo({id:\"ictcp\",name:\"ICTCP\",coords:{i:{refRange:[0,1],name:\"I\"},ct:{refRange:[-.5,.5],name:\"CT\"},cp:{refRange:[-.5,.5],name:\"CP\"}},base:Yo,fromBase:function(e){var t=e=Ia(ci,e);return t=e.map((function(e){var t=.8359375+2413/128*Math.pow(e/1e4,si);e=1+18.6875*Math.pow(e/1e4,si);return Math.pow(t/e,2523/32)})),Ia(di,t)},toBase:function(e){return e=Ia(pi,e).map((function(e){var t=Math.max(Math.pow(e,32/2523)-.8359375,0);e=2413/128-18.6875*Math.pow(e,32/2523);return 1e4*Math.pow(t/e,16384/2610)})),Ia(fi,e)},formats:{color:{}}}),hi=[[.8190224432164319,.3619062562801221,-.12887378261216414],[.0329836671980271,.9292868468965546,.03614466816999844],[.048177199566046255,.26423952494422764,.6335478258136937]],gi=[[1.2268798733741557,-.5578149965554813,.28139105017721583],[-.04057576262431372,1.1122868293970594,-.07171106666151701],[-.07637294974672142,-.4214933239627914,1.5869240244272418]],vi=[[.2104542553,.793617785,-.\\\n0040720468],[1.9779984951,-2.428592205,.4505937099],[.0259040371,.7827717662,-.808675766]],bi=[[.9999999984505198,.39633779217376786,.2158037580607588],[1.0000000088817609,-.10556134232365635,-.06385417477170591],[1.0000000546724108,-.08948418209496575,-1.2914855378640917]],yi=new eo({id:\"oklab\",name:\"OKLab\",coords:{l:{refRange:[0,1],name:\"L\"},a:{refRange:[-.4,.4]},b:{refRange:[-.4,.4]}},white:\"D65\",base:to,fromBase:function(e){return e=Ia(hi,e).map((function(e){return Math.cbrt(e)})),Ia(vi,e)},toBase:function(e){return e=Ia(bi,e).map((function(e){return Math.pow(e,3)})),Ia(gi,e)},formats:{oklab:{coords:[\"<number> | <percentage>\",\"<number>\",\"<number>\"]}}}),Di=Object.freeze({__proto__:null,deltaE76:function(e,t){return Mo(e,t,\"lab\")},deltaECMC:function(e,t){var n=void 0===(n=(r=2<arguments.length&&void 0!==arguments[2]?arguments[2]:{}).l)?2:n,r=void 0===(r=r.c)?1:r,a=(e=V(po.from(e),3))[0],o=e[1],i=(e=e[2],(l=V(mo.from(po,[a,o,e]),3))[1]),l=l[2],u=(t=V(po.from(t),3))[0],s=t[1],c=(t=t[2]\\\n,mo.from(po,[u,s,t])[1]);u=a-u,c=(i=i<0?0:i)-(c=c<0?0:c),e-=t,t=Math.pow(o-s,2)+Math.pow(e,2)-Math.pow(c,2),o=.511,16<=a&&(o=.040975*a/(1+.01765*a)),s=.0638*i/(1+.0131*i)+.638,e=164<=(l=Number.isNaN(l)?0:l)&&l<=345?.56+Math.abs(.2*Math.cos((l+168)*Wo)):.36+Math.abs(.4*Math.cos((l+35)*Wo)),a=Math.pow(i,4),i=s*((l=Math.sqrt(a/(a+1900)))*e+1-l),a=Math.pow(u/(n*o),2),a=(a+=Math.pow(c/(r*s),2))+t/Math.pow(i,2);return Math.sqrt(a)},deltaE2000:yo,deltaEJz:function(e,t){var n=(e=V(ui.from(e),3))[0],r=e[1],a=(e=e[2],(t=V(ui.from(t),3))[0]),o=t[1];t=t[2],n-=a,a=r-o,Number.isNaN(e)&&Number.isNaN(t)?t=e=0:Number.isNaN(e)?e=t:Number.isNaN(t)&&(t=e),e-=t,t=2*Math.sqrt(r*o)*Math.sin(e/2*(Math.PI/180));return Math.sqrt(Math.pow(n,2)+Math.pow(a,2)+Math.pow(t,2))},deltaEITP:function(e,t){var n=(e=V(mi.from(e),3))[0],r=e[1],a=(e=e[2],(t=V(mi.from(t),3))[0]),o=t[1];t=t[2];return 720*Math.sqrt(Math.pow(n-a,2)+.25*Math.pow(r-o,2)+Math.pow(e-t,2))},deltaEOK:function(e,t){var n=(e=V(yi.from(e),3))[0],r=e[1],a\\\n=(e=e[2],(t=V(yi.from(t),3))[0]);r-=t[1],e-=t[2];return Math.sqrt(Math.pow(n-a,2)+Math.pow(r,2)+Math.pow(e,2))}});function wi(e,t){var n,r,a=(r=r=Ba(r=2<arguments.length&&void 0!==arguments[2]?arguments[2]:{})?{method:r}:r).method,o=void 0===a?Wa.deltaE:a,i=k(r,s);for(n in e=ao(e),t=ao(t),Di)if(\"deltae\"+o.toLowerCase()===n.toLowerCase())return Di[n](e,t,i);throw new TypeError(\"Unknown deltaE method: \".concat(o))}var xi=Object.freeze({__proto__:null,lighten:function(e){var t=1<arguments.length&&void 0!==arguments[1]?arguments[1]:.25;return uo(e,[eo.get(\"oklch\",\"lch\"),\"l\"],(function(e){return e*(1+t)}))},darken:function(e){var t=1<arguments.length&&void 0!==arguments[1]?arguments[1]:.25;return uo(e,[eo.get(\"oklch\",\"lch\"),\"l\"],(function(e){return e*(1-t)}))}});function Ei(e,t){var n=2<arguments.length&&void 0!==arguments[2]?arguments[2]:.5,r=3<arguments.length&&void 0!==arguments[3]?arguments[3]:{},a=(e=(a=[ao(e),ao(t)])[0],t=a[1],\"object\"===ja(n)&&(n=(a=[.5,n])[0],r=a[1]),r);return Fi(e,\\\nt,{space:a.space,outputSpace:a.outputSpace,premultiplied:a.premultiplied})(n)}function Ai(e,t){var n,r,a=2<arguments.length&&void 0!==arguments[2]?arguments[2]:{},o=(s=(Ci(e)&&(a=t,e=(s=V((n=e).rangeArgs.colors,2))[0],t=s[1]),a)).maxDeltaE,i=s.deltaEMethod,l=(a=void 0===(a=s.steps)?2:a,void 0===(u=s.maxSteps)?1e3:u),u=k(s,c),s=(n||(s=[ao(e),ao(t)],n=Fi(e=s[0],t=s[1],u)),wi(e,t)),d=(u=0<o?Math.max(a,Math.ceil(s/o)+1):a,[]);if(void 0!==l&&(u=Math.min(u,l)),d=1===u?[{p:.5,color:n(.5)}]:(r=1/(u-1),Array.from({length:u},(function(e,t){return{p:t*=r,color:n(t)}}))),0<o)for(var p=d.reduce((function(e,t,n){return 0===n?0:(t=wi(t.color,d[n-1].color,i),Math.max(e,t))}),0);o<p;){p=0;for(var f=1;f<d.length&&d.length<l;f++){var m=d[f-1],h=d[f],g=(h.p+m.p)/2,v=n(g);p=Math.max(p,wi(v,m.color),wi(v,h.color));d.splice(f,0,{p:g,color:n(g)}),f++}}return d=d.map((function(e){return e.color}))}function Fi(e,t){var n,r,a,o,i,l,u,s,c,d,p,f,m=2<arguments.length&&void 0!==arguments[2]?arguments[2]:{};return Ci\\\n(e)?(a=e,o=t,Fi.apply(void 0,M(a.rangeArgs.colors).concat([O({},a.rangeArgs.options,o)]))):(p=m.space,f=m.outputSpace,n=m.progression,r=m.premultiplied,e=ao(e),t=ao(t),e=xo(e),t=xo(t),a={colors:[e,t],options:m},p=p?eo.get(p):eo.registry[Wa.interpolationSpace]||e.space,f=f?eo.get(f):p,e=Ao(e,p),t=Ao(t,p),e=Eo(e),t=Eo(t),p.coords.h&&\"angle\"===p.coords.h.type&&(o=m.hue=m.hue||\"shorter\",s=[(l=[io(e,m=[p,\"h\"]),io(t,m)])[0],l=l[1]],u=\"raw\"===(u=o)?s:(c=(s=V(s.map(fo),2))[0],d=(s=s[1])-c,\"increasing\"===u?d<0&&(s+=360):\"decreasing\"===u?0<d&&(c+=360):\"longer\"===u?-180<d&&d<180&&(0<d?s+=360:c+=360):\"shorter\"===u&&(180<d?c+=360:d<-180&&(s+=360)),[c,s]),i=(d=V(u,2))[0],l=d[1],uo(e,m,i),uo(t,m,l)),r&&(e.coords=e.coords.map((function(t){return t*e.alpha})),t.coords=t.coords.map((function(e){return e*t.alpha}))),Object.assign((function(a){a=n?n(a):a;var o=e.coords.map((function(e,n){return Va(e,t.coords[n],a)})),i=Va(e.alpha,t.alpha,a);o={space:p,coords:o,alpha:i};return r&&(o.coords=o.coords.map((fu\\\nnction(e){return e/i}))),f!==p?Ao(o,f):o}),{rangeArgs:a}))}function Ci(e){return\"function\"===ja(e)&&!!e.rangeArgs}Wa.interpolationSpace=\"lab\";var ki=Object.freeze({__proto__:null,mix:Ei,steps:Ai,range:Fi,isRange:Ci,register:function(e){e.defineFunction(\"mix\",Ei,{returns:\"color\"}),e.defineFunction(\"range\",Fi,{returns:\"function<color>\"}),e.defineFunction(\"steps\",Ai,{returns:\"array<color>\"})}}),Ri=new eo({id:\"hsl\",name:\"HSL\",coords:{h:{refRange:[0,360],type:\"angle\",name:\"Hue\"},s:{range:[0,100],name:\"Saturation\"},l:{range:[0,100],name:\"Lightness\"}},base:ra,fromBase:function(e){var t=Math.max.apply(Math,M(e)),n=Math.min.apply(Math,M(e)),r=(e=V(e,3))[0],a=e[1],o=e[2],i=NaN,l=(e=0,(n+t)/2),u=t-n;if(0!=u){switch(e=0==l||1==l?0:(t-l)/Math.min(l,1-l),t){case r:i=(a-o)/u+(a<o?6:0);break;case a:i=(o-r)/u+2;break;case o:i=(r-a)/u+4}i*=60}return[i,100*e,100*l]},toBase:function(e){var t=(e=V(e,3))[0],n=e[1],r=e[2];function a(e){e=(e+t/30)%12;var a=n*Math.min(r,1-r);return r-a*Math.max(-1,Math.min(e-3\\\n,9-e,1))}return(t%=360)<0&&(t+=360),n/=100,r/=100,[a(0),a(8),a(4)]},formats:{hsl:{toGamut:!0,coords:[\"<number> | <angle>\",\"<percentage>\",\"<percentage>\"]},hsla:{coords:[\"<number> | <angle>\",\"<percentage>\",\"<percentage>\"],commas:!0,lastAlpha:!0}}}),Ni=new eo({id:\"hsv\",name:\"HSV\",coords:{h:{refRange:[0,360],type:\"angle\",name:\"Hue\"},s:{range:[0,100],name:\"Saturation\"},v:{range:[0,100],name:\"Value\"}},base:Ri,fromBase:function(e){var t=(e=V(e,3))[0],n=e[1];e=e[2];return[t,0==(n=(e/=100)+(n/=100)*Math.min(e,1-e))?0:200*(1-e/n),100*n]},toBase:function(e){var t=(e=V(e,3))[0],n=e[1];e=e[2];return[t,0==(n=(e/=100)*(1-(n/=100)/2))||1==n?0:(e-n)/Math.min(n,1-n)*100,100*n]},formats:{color:{toGamut:!0}}}),Ti=new eo({id:\"hwb\",name:\"HWB\",coords:{h:{refRange:[0,360],type:\"angle\",name:\"Hue\"},w:{range:[0,100],name:\"Whiteness\"},b:{range:[0,100],name:\"Blackness\"}},base:Ni,fromBase:function(e){var t=(e=V(e,3))[0],n=e[2];return[t,n*(100-e[1])/100,100-n]},toBase:function(e){var t=(e=V(e,3))[0],n=e[1],r=(e=e[2]\\\n,(n/=100)+(e/=100));return 1<=r?[t,0,n/r*100]:[t,100*(0==(r=1-e)?0:1-n/r),100*r]},formats:{hwb:{toGamut:!0,coords:[\"<number> | <angle>\",\"<percentage>\",\"<percentage>\"]}}}),Si=new Dt({id:\"a98rgb-linear\",name:\"Linear Adobe® 98 RGB compatible\",white:\"D65\",toXYZ_M:[[.5766690429101305,.1855582379065463,.1882286462349947],[.29734497525053605,.6273635662554661,.07529145849399788],[.02703136138641234,.07068885253582723,.9913375368376388]],fromXYZ_M:[[2.0415879038107465,-.5650069742788596,-.34473135077832956],[-.9692436362808795,1.8759675015077202,.04155505740717557],[.013444280632031142,-.11836239223101838,1.0151749943912054]]}),_i=new Dt({id:\"a98rgb\",name:\"Adobe® 98 RGB compatible\",base:Si,toBase:function(e){return e.map((function(e){return Math.pow(Math.abs(e),563/256)*Math.sign(e)}))},fromBase:function(e){return e.map((function(e){return Math.pow(Math.abs(e),256/563)*Math.sign(e)}))},formats:{color:{id:\"a98-rgb\"}}}),Oi=new Dt({id:\"prophoto-linear\",name:\"Linear ProPhoto\",white:\"D50\",base:ye,t\\\noXYZ_M:[[.7977604896723027,.13518583717574031,.0313493495815248],[.2880711282292934,.7118432178101014,8565396060525902e-20],[0,0,.8251046025104601]],fromXYZ_M:[[1.3457989731028281,-.25558010007997534,-.05110628506753401],[-.5446224939028347,1.5082327413132781,.02053603239147973],[0,0,1.2119675456389454]]}),Mi=new Dt({id:\"prophoto\",name:\"ProPhoto\",base:Oi,toBase:function(e){return e.map((function(e){return e<.03125?e/16:Math.pow(e,1.8)}))},fromBase:function(e){return e.map((function(e){return 1/512<=e?Math.pow(e,1/1.8):16*e}))},formats:{color:{id:\"prophoto-rgb\"}}}),Pi=new eo({id:\"oklch\",name:\"OKLCh\",coords:{l:{refRange:[0,1],name:\"Lightness\"},c:{refRange:[0,.4],name:\"Chroma\"},h:{refRange:[0,360],type:\"angle\",name:\"Hue\"}},white:\"D65\",base:yi,fromBase:function(e){var t=(e=V(e,3))[0],n=e[1],r=(e=e[2],Math.abs(n)<2e-4&&Math.abs(e)<2e-4?NaN:180*Math.atan2(e,n)/Math.PI);return[t,Math.sqrt(Math.pow(n,2)+Math.pow(e,2)),fo(r)]},toBase:function(e){var t,n=(e=V(e,3))[0],r=e[1];e=e[2],r=isNaN(e)?t=\\\n0:(t=r*Math.cos(e*Math.PI/180),r*Math.sin(e*Math.PI/180));return[n,t,r]},formats:{oklch:{coords:[\"<number> | <percentage>\",\"<number>\",\"<number> | <angle>\"]}}}),Ii=2610/Math.pow(2,14),Bi=Math.pow(2,14)/2610,ji=2523/Math.pow(2,5),Li=Math.pow(2,5)/2523,qi=3424/Math.pow(2,12),zi=2413/Math.pow(2,7),Vi=2392/Math.pow(2,7),Gi=new Dt({id:\"rec2100pq\",name:\"REC.2100-PQ\",base:De,toBase:function(e){return e.map((function(e){return 1e4*Math.pow(Math.max(Math.pow(e,Li)-qi,0)/(zi-Vi*Math.pow(e,Li)),Bi)/203}))},fromBase:function(e){return e.map((function(e){e=Math.max(203*e/1e4,0);var t=qi+zi*Math.pow(e,Ii);e=1+Vi*Math.pow(e,Ii);return Math.pow(t/e,ji)}))},formats:{color:{id:\"rec2100-pq\"}}}),$i=.17883277,Hi=.28466892,Ui=.55991073,Wi=3.7743,Yi=new Dt({id:\"rec2100hlg\",cssid:\"rec2100-hlg\",name:\"REC.2100-HLG\",referred:\"scene\",base:De,toBase:function(e){return e.map((function(e){return e<=.5?Math.pow(e,2)/3*Wi:Math.exp((e-Ui)/$i+Hi)/12*Wi}))},fromBase:function(e){return e.map((function(e){return(e/=Wi)<=1/1\\\n2?Math.sqrt(3*e):$i*Math.log(12*e-Hi)+Ui}))},formats:{color:{id:\"rec2100-hlg\"}}}),Ki={};function Xi(e){var t=e.id;Ki[t]=e}function Zi(e,t,n){var r=(e=V(Ia((n=Ki[2<arguments.length&&void 0!==n?n:\"Bradford\"]).toCone_M,e),3))[0],a=e[1];e=e[2],t=V(Ia(n.toCone_M,t),3),r=Ia([[t[0]/r,0,0],[0,t[1]/a,0],[0,0,t[2]/e]],n.toCone_M);return Ia(n.fromCone_M,r)}Ua.add(\"chromatic-adaptation-start\",(function(e){e.options.method&&(e.M=Zi(e.W1,e.W2,e.options.method))})),Ua.add(\"chromatic-adaptation-end\",(function(e){e.M||(e.M=Zi(e.W1,e.W2,e.options.method))})),Xi({id:\"von Kries\",toCone_M:[[.40024,.7076,-.08081],[-.2263,1.16532,.0457],[0,0,.91822]],fromCone_M:[[1.8599364,-1.1293816,.2198974],[.3611914,.6388125,-64e-7],[0,0,1.0890636]]}),Xi({id:\"Bradford\",toCone_M:[[.8951,.2664,-.1614],[-.7502,1.7135,.0367],[.0389,-.0685,1.0296]],fromCone_M:[[.9869929,-.1470543,.1599627],[.4323053,.5183603,.0492912],[-.0085287,.0400428,.9684867]]}),Xi({id:\"CAT02\",toCone_M:[[.7328,.4296,-.1624],[-.7036,1.6975,.0061],[.003,.0\\\n136,.9834]],fromCone_M:[[1.0961238,-.278869,.1827452],[.454369,.4735332,.0720978],[-.0096276,-.005698,1.0153256]]}),Xi({id:\"CAT16\",toCone_M:[[.401288,.650173,-.051461],[-.250268,1.204414,.045854],[-.002079,.048952,.953127]],fromCone_M:[[1.862067855087233,-1.011254630531685,.1491867754444518],[.3875265432361372,.6214474419314753,-.008973985167612518],[-.01584149884933386,-.03412293802851557,1.04996443687785]]}),Object.assign(Ya,{A:[1.0985,1,.35585],C:[.98074,1,1.18232],D55:[.95682,1,.92149],D75:[.94972,1,1.22638],E:[1,1,1],F2:[.99186,1,.67393],F7:[.95041,1,1.08747],F11:[1.00962,1,.6435]}),Ya.ACES=[.32168/.33767,1,.34065/.33767];var Ji=new Dt({id:\"acescg\",name:\"ACEScg\",coords:{r:{range:[0,65504],name:\"Red\"},g:{range:[0,65504],name:\"Green\"},b:{range:[0,65504],name:\"Blue\"}},referred:\"scene\",white:Ya.ACES,toXYZ_M:[[.6624541811085053,.13400420645643313,.1561876870049078],[.27222871678091454,.6740817658111484,.05368951740793705],[-.005574649490394108,.004060733528982826,1.0103391003129971]],f\\\nromXYZ_M:[[1.6410233796943257,-.32480329418479,-.23642469523761225],[-.6636628587229829,1.6153315916573379,.016756347685530137],[.011721894328375376,-.008284441996237409,.9883948585390215]],formats:{color:{}}}),Qi=Math.pow(2,-16),el=-.35828683,tl=(Math.log2(65504)+9.72)/17.52,nl=(Dt=new Dt({id:\"acescc\",name:\"ACEScc\",coords:{r:{range:[el,tl],name:\"Red\"},g:{range:[el,tl],name:\"Green\"},b:{range:[el,tl],name:\"Blue\"}},referred:\"scene\",base:Ji,toBase:function(e){return e.map((function(e){return e<=(9.72-15)/17.52?2*(Math.pow(2,17.52*e-9.72)-Qi):e<tl?Math.pow(2,17.52*e-9.72):65504}))},fromBase:function(e){return e.map((function(e){return e<=0?(Math.log2(Qi)+9.72)/17.52:e<Qi?(Math.log2(Qi+.5*e)+9.72)/17.52:(Math.log2(e)+9.72)/17.52}))},formats:{color:{}}}),Object.freeze({__proto__:null,XYZ_D65:to,XYZ_D50:ye,XYZ_ABS_D65:Yo,Lab_D65:zo,Lab:po,LCH:mo,sRGB_Linear:kn,sRGB:ra,HSL:Ri,HWB:Ti,HSV:Ni,P3_Linear:Cn,P3:No,A98RGB_Linear:Si,A98RGB:_i,ProPhoto_Linear:Oi,ProPhoto:Mi,REC_2020_Linear:De,REC_2020:\\\njt,OKLab:yi,OKLCH:Pi,Jzazbz:li,JzCzHz:ui,ICTCP:mi,REC_2100_PQ:Gi,REC_2100_HLG:Yi,ACEScg:Ji,ACEScc:Dt})),rl=(ee=new WeakMap,W((function e(){var t=this;H(this,e),I(this,ee,void 0);for(var n,r,a,o=arguments.length,i=new Array(o),l=0;l<o;l++)i[l]=arguments[l];a=(a=1===i.length?ao(i[0]):a)?(n=a.space||a.spaceId,r=a.coords,a.alpha):(n=i[0],r=i[1],i[2]),q(ee,this,eo.get(n)),this.coords=r?r.slice():[0,0,0],this.alpha=a<1?a:1;for(var u=0;u<this.coords.length;u++)\"NaN\"===this.coords[u]&&(this.coords[u]=NaN);for(var s in L(ee,this).coords)(e=>{Object.defineProperty(t,e,{get:function(){return t.get(e)},set:function(n){return t.set(e,n)}})})(s)}),[{key:\"space\",get:function(){return L(ee,this)}},{key:\"spaceId\",get:function(){return L(ee,this).id}},{key:\"clone\",value:function(){return new rl(this.space,this.coords,this.alpha)}},{key:\"toJSON\",value:function(){return{spaceId:this.spaceId,coords:this.coords,alpha:this.alpha}}},{key:\"display\",value:function(){for(var e=arguments.length,t=new Array(e),n=0\\\n;n<e;n++)t[n]=arguments[n];var r=function(e){var t,n=void 0===(n=(r=1<arguments.length&&void 0!==arguments[1]?arguments[1]:{}).space)?Wa.display_space:n,r=k(r,l),a=Fo(e,r);return\"undefined\"==typeof CSS||null!=(t=CSS)&&t.supports(\"color\",a)||!Wa.display_space?(a=new String(a)).color=e:(t=Ao(e,n),(a=new String(Fo(t,r))).color=t),a}.apply(void 0,[this].concat(t));return r.color=new rl(r.color),r}}],[{key:\"get\",value:function(e){if(e instanceof rl)return e;for(var t=arguments.length,n=new Array(1<t?t-1:0),r=1;r<t;r++)n[r-1]=arguments[r];return C(rl,[e].concat(n))}},{key:\"defineFunction\",value:function(e,t){function n(){var e,n=t.apply(void 0,arguments);return\"color\"===o?n=rl.get(n):\"function<color>\"===o?(e=n,n=function(){var t=e.apply(void 0,arguments);return rl.get(t)},Object.assign(n,e)):\"array<color>\"===o&&(n=n.map((function(e){return rl.get(e)}))),n}var r=2<arguments.length&&void 0!==arguments[2]?arguments[2]:t,a=void 0===(a=r.instance)||a,o=r.returns;e in rl||(rl[e]=n),a&&(rl.prototyp\\\ne[e]=function(){for(var e=arguments.length,t=new Array(e),r=0;r<e;r++)t[r]=arguments[r];return n.apply(void 0,[this].concat(t))})}},{key:\"defineFunctions\",value:function(e){for(var t in e)rl.defineFunction(t,e[t],e[t])}},{key:\"extend\",value:function(e){if(e.register)e.register(rl);else for(var t in e)rl.defineFunction(t,e[t])}}]));rl.defineFunctions({get:io,getAll:oo,set:uo,setAll:lo,to:Ao,equals:function(e,t){return e=ao(e),t=ao(t),e.space===t.space&&e.alpha===t.alpha&&e.coords.every((function(e,n){return e===t.coords[n]}))},inGamut:wo,toGamut:Eo,distance:Mo,toString:Fo}),Object.assign(rl,{util:we,hooks:Ua,WHITES:Ya,Space:eo,spaces:eo.registry,parse:ro,defaults:Wa});for(var al,ol=0,il=Object.keys(nl);ol<il.length;ol++){var ll=il[ol];eo.register(nl[ll])}for(al in eo.registry)ul(al,eo.registry[al]);function ul(e,t){Object.keys(t.coords),Object.values(t.coords).map((function(e){return e.name}));var n=e.replace(/-/g,\"_\");Object.defineProperty(rl.prototype,n,{get:function(){var n=this,r=th\\\nis.getAll(e);return\"undefined\"==typeof Proxy?r:new Proxy(r,{has:function(e,n){try{return eo.resolveCoord([t,n]),!0}catch(e){}return Reflect.has(e,n)},get:function(e,n,r){if(n&&\"symbol\"!==a(n)&&!(n in e)){var o=eo.resolveCoord([t,n]).index;if(0<=o)return e[o]}return Reflect.get(e,n,r)},set:function(r,o,i,l){if(o&&\"symbol\"!==a(o)&&!(o in r)||0<=o){var u=eo.resolveCoord([t,o]).index;if(0<=u)return r[u]=i,n.setAll(e,r),!0}return Reflect.set(r,o,i,l)}})},set:function(t){this.setAll(e,t)},configurable:!0,enumerable:!0})}Ua.add(\"colorspace-init-end\",(function(e){var t;ul(e.id,e),null!=(t=e.aliases)&&t.forEach((function(t){ul(t,e)}))})),rl.extend(Di),rl.extend({deltaE:wi}),rl.extend(xi),rl.extend({contrast:function(e,t){var n,r=2<arguments.length&&void 0!==arguments[2]?arguments[2]:{},a=(r=r=Ba(r)?{algorithm:r}:r).algorithm,o=k(r,u);if(!a)throw r=Object.keys(Go).map((function(e){return e.replace(/^contrast/,\"\")})).join(\", \"),new TypeError(\"contrast() function needs a contrast algorithm. Please\\\n specify one of: \".concat(r));for(n in e=ao(e),t=ao(t),Go)if(\"contrast\"+a.toLowerCase()===n.toLowerCase())return Go[n](e,t,o);throw new TypeError(\"Unknown contrast algorithm: \".concat(a))}}),rl.extend(Uo),rl.extend(ue),rl.extend(ki),rl.extend(Go);var sl=de(xn()),cl=(Oa.default.templateSettings.strip=!1,o._memoizedFns=[],function(e){return e=(0,Pa.default)(e),o._memoizedFns.push(e),e}),dl=cl((function(e){return!(null==e||!e.createElement)&&\"A\"===e.createElement(\"A\").localName}));function pl(e,t){var n=2<arguments.length&&void 0!==arguments[2]?arguments[2]:{};if(!t)return\"\";var a=t.getRootNode&&t.getRootNode()||r;if(11!==a.nodeType)return e(t,n,a);for(var o=[];11===a.nodeType;){if(!a.host)return\"\";o.unshift({elm:t,doc:a}),a=(t=a.host).getRootNode()}return o.unshift({elm:t,doc:a}),o.map((function(t){return e(t.elm,n,t.doc)}))}var fl=[\"class\",\"style\",\"id\",\"selected\",\"checked\",\"disabled\",\"tabindex\",\"aria-checked\",\"aria-selected\",\"aria-invalid\",\"aria-activedescendant\",\"aria-busy\",\"aria-disab\\\nled\",\"aria-expanded\",\"aria-grabbed\",\"aria-pressed\",\"aria-valuenow\",\"xmlns\"],ml=31,hl=/([\\\\\\\\\"])/g,gl=/(\\\\r\\\\n|\\\\r|\\\\n)/g;function vl(e){return e.replace(hl,\"\\\\\\\\$1\").replace(gl,\"\\\\\\\\a \")}function bl(e,t){var n,r=t.name;return-1!==r.indexOf(\"href\")||-1!==r.indexOf(\"src\")?(n=Ra(e.getAttribute(r)))?Aa(t.name)+'$=\"'+vl(n)+'\"':Aa(t.name)+'=\"'+vl(e.getAttribute(r))+'\"':Aa(r)+'=\"'+vl(t.value)+'\"'}function yl(e,t){return e.count<t.count?-1:e.count===t.count?0:1}function Dl(e){return!fl.includes(e.name)&&-1===e.name.indexOf(\":\")&&(!e.value||e.value.length<ml)}function wl(e){for(var t={classes:{},tags:{},attributes:{}},n=(e=Array.isArray(e)?e:[e]).slice(),r=[];n.length;)(()=>{var e,a=n.pop(),o=a.actualNode;for(o.querySelectorAll&&(e=o.nodeName,t.tags[e]?t.tags[e]++:t.tags[e]=1,o.classList&&Array.from(o.classList).forEach((function(e){e=Aa(e),t.classes[e]?t.classes[e]++:t.classes[e]=1})),o.hasAttributes())&&Array.from(Na(o)).filter(Dl).forEach((function(e){(e=bl(o,e))&&(t.attributes[e]?t.attributes[e]++:t.\\\nattributes[e]=1)})),a.children.length&&(r.push(n),n=a.children.slice());!n.length&&r.length;)n=r.pop()})();return t}function xl(e){var t=dl(r);return Aa(t?e.localName:e.nodeName.toLowerCase())}function El(e,t){var n,r,a,o,i,l,u,s,c,d=\"\",p=(r=e,a=[],o=t.classes,i=t.tags,r.classList&&Array.from(r.classList).forEach((function(e){e=Aa(e),o[e]<i[r.nodeName]&&a.push({name:e,count:o[e],species:\"class\"})})),a.sort(yl));l=e,u=[],s=t.attributes,c=t.tags,l.hasAttributes()&&Array.from(Na(l)).filter(Dl).forEach((function(e){(e=bl(l,e))&&s[e]<c[l.nodeName]&&u.push({name:e,count:s[e],species:\"attribute\"})})),t=u.sort(yl);return p.length&&1===p[0].count?n=[p[0]]:t.length&&1===t[0].count?(n=[t[0]],d=xl(e)):((n=p.concat(t)).sort(yl),(n=n.slice(0,3)).some((function(e){return\"class\"===e.species}))?n.sort((function(e,t){return e.species!==t.species&&\"class\"===e.species?-1:e.species===t.species?0:1})):d=xl(e)),d+n.reduce((function(e,t){switch(t.species){case\"class\":return e+\".\"+t.name;case\"attribute\":return\\\n e+\"[\"+t.name+\"]\"}return e}),\"\")}function Al(e,t,n){if(!o._selectorData)throw new Error(\"Expect axe._selectorData to be set up\");var a,i,l=void 0!==(t=t.toRoot)&&t;do{var u=(e=>{var t;if(e.getAttribute(\"id\"))return t=e.getRootNode&&e.getRootNode()||r,(e=\"#\"+Aa(e.getAttribute(\"id\")||\"\")).match(/player_uid_/)||1!==t.querySelectorAll(e).length?void 0:e})(e);u||(u=El(e,o._selectorData),u+=((e,t)=>{var n=e.parentNode&&Array.from(e.parentNode.children||\"\")||[];return n.find((function(n){return n!==e&&Ta(n,t)}))?\":nth-child(\"+(1+n.indexOf(e))+\")\":\"\"})(e,u)),a=a?u+\" > \"+a:u,i=!i||i.length>oa.selectorSimilarFilterLimit?Cl(n,a):i.filter((function(e){return Ta(e,a)})),e=e.parentElement}while((1<i.length||l)&&e&&11!==e.nodeType);return 1===i.length?a:-1!==a.indexOf(\" > \")?\":root\"+a.substring(a.indexOf(\" > \")):\":root\"}var Fl=cl((function(e,t){return pl(Al,e,t)})),Cl=cl((function(e,t){return Array.from(e.querySelectorAll(t))}));function kl(e){var t=e.nodeName.toLowerCase(),n=e.parentElement,r=e.pare\\\nntNode,a=\"\";return\"head\"!==t&&\"body\"!==t&&1<(null==r?void 0:r.children.length)&&(r=Array.prototype.indexOf.call(r.children,e)+1,a=\":nth-child(\".concat(r,\")\")),n?kl(n)+\" > \"+t+a:t+a}function Rl(e,t){return pl(kl,e,t)}var Nl=function(e){return function e(t,n){var r,a,o,i;if(!t)return[];if(!n&&9===t.nodeType)return[{str:\"html\"}];if(n=n||[],t.parentNode&&t.parentNode!==t&&(n=e(t.parentNode,n)),t.previousSibling){for(a=1,r=t.previousSibling;1===r.nodeType&&r.nodeName===t.nodeName&&a++,r=r.previousSibling;);1===a&&(a=null)}else if(t.nextSibling)for(r=t.nextSibling;r=1===r.nodeType&&r.nodeName===t.nodeName?(a=1,null):(a=null,r.previousSibling););return 1===t.nodeType&&((o={}).str=t.nodeName.toLowerCase(),(i=t.getAttribute&&Aa(t.getAttribute(\"id\")))&&1===t.ownerDocument.querySelectorAll(\"#\"+i).length&&(o.id=t.getAttribute(\"id\")),1<a&&(o.count=a),n.push(o)),n}(e).reduce((function(e,t){return t.id?\"//\".concat(t.str,\"[@id='\").concat(t.id,\"']\"):e+\"/\".concat(t.str)+(0<t.count?\"[\".concat(t.count,\"]\"\\\n):\"\")}),\"\")},Tl={},Sl={set:function(e,t){var n;xa(\"string\"==typeof(n=e),\"key must be a string, \"+a(n)+\" given\"),xa(\"\"!==n,\"key must not be empty\"),Tl[e]=t},get:function(e,t){var n;return xa(\"function\"==typeof(n=t)||void 0===n,\"creator must be a function or undefined, \"+a(n)+\" given\"),e in Tl?Tl[e]:\"function\"==typeof t?(n=t(),xa(void 0!==n,\"Cache creator function should not return undefined\"),this.set(e,n),Tl[e]):void 0},clear:function(){Tl={}}},_l=function(e,t){return t=t||e,Sl.get(\"nodeMap\")?Sl.get(\"nodeMap\").get(t):null},Ol={},Ml=(ce(Ol,{createGrid:function(){return Su},findElmsInContext:function(){return Il},findNearbyElms:function(){return Lu},findUp:function(){return jl},findUpVirtual:function(){return Bl},focusDisabled:function(){return Uu},getComposedParent:function(){return ou},getElementByReference:function(){return Xu},getElementCoordinates:function(){return lu},getElementStack:function(){return es},getModalDialog:function(){return zu},getNodeGrid:function(){return ju},getOve\\\nrflowHiddenAncestors:function(){return zl},getRootNode:function(){return Pl},getScrollOffset:function(){return iu},getTabbableElements:function(){return ts},getTargetRects:function(){return os},getTargetSize:function(){return is},getTextElementStack:function(){return zc},getViewportSize:function(){return uu},getVisibleChildTextRects:function(){return Lc},hasContent:function(){return Wc},hasContentVirtual:function(){return Uc},hasLangText:function(){return Yc},idrefs:function(){return us},insertedIntoFocusOrder:function(){return Kc},isCurrentPageLink:function(){return Ku},isFocusable:function(){return rs},isHTML5:function(){return Qc},isHiddenForEveryone:function(){return nu},isHiddenWithCSS:function(){return Jc},isInTabOrder:function(){return as},isInTextBlock:function(){return rd},isInert:function(){return Vu},isModalOpen:function(){return ad},isMultiline:function(){return od},isNativelyFocusable:function(){return ns},isNode:function(){return id},isOffscreen:function(){return su},isOp\\\naque:function(){return vd},isSkipLink:function(){return bd},isVisible:function(){return xd},isVisibleOnScreen:function(){return du},isVisibleToScreenReaders:function(){return nc},isVisualContent:function(){return Gc},reduceToElementsBelowFloating:function(){return Ed},shadowElementsFromPoint:function(){return Cd},urlPropsFromAttribute:function(){return kd},visuallyContains:function(){return Ad},visuallyOverlaps:function(){return Rd},visuallySort:function(){return Zu}}),function(e){var t=e.getRootNode&&e.getRootNode()||r;return t===e?r:t}),Pl=Ml,Il=function(e){var t=e.context,n=e.attr,r=void 0===(r=e.elm)?\"\":r;e=Aa(e.value),t=9===t.nodeType||11===t.nodeType?t:Pl(t);return Array.from(t.querySelectorAll(r+\"[\"+n+\"=\"+e+\"]\"))},Bl=function(e,t){var n=e.actualNode;if(!e.shadowId&&\"function\"==typeof e.actualNode.closest)return e.actualNode.closest(t)||null;for(;(n=(n=n.assignedSlot||n.parentNode)&&11===n.nodeType?n.host:n)&&!Ta(n,t)&&n!==r.documentElement;);return n&&Ta(n,t)?n:null},jl=function\\\n(e,t){return Bl(_l(e),t)};function Ll(e,t){return(0|e.left)<(0|t.right)&&(0|e.right)>(0|t.left)&&(0|e.top)<(0|t.bottom)&&(0|e.bottom)>(0|t.top)}var ql=cl((function(e){var t=[];return e?(\"hidden\"===e.getComputedStylePropertyValue(\"overflow\")&&t.push(e),t.concat(ql(e.parent))):t})),zl=ql,Vl=/rect\\\\s*\\\\(([0-9]+)px,?\\\\s*([0-9]+)px,?\\\\s*([0-9]+)px,?\\\\s*([0-9]+)px\\\\s*\\\\)/,Gl=/(\\\\w+)\\\\((\\\\d+)/;function $l(e){return[\"style\",\"script\",\"noscript\",\"template\"].includes(e.props.nodeName)}function Hl(e){return\"area\"!==e.props.nodeName&&\"none\"===e.getComputedStylePropertyValue(\"display\")}function Ul(e){return!(1<arguments.length&&void 0!==arguments[1]?arguments[1]:{}).isAncestor&&[\"hidden\",\"collapse\"].includes(e.getComputedStylePropertyValue(\"visibility\"))}function Wl(e){return!!(1<arguments.length&&void 0!==arguments[1]?arguments[1]:{}).isAncestor&&\"hidden\"===e.getComputedStylePropertyValue(\"content-visibility\")}function Yl(e){return\"true\"===e.attr(\"aria-hidden\")}function Kl(e){return\"0\"===e.getComputedStylePr\\\nopertyValue(\"opacity\")}function Xl(e){var t=Cf(e.actualNode),n=parseInt(e.getComputedStylePropertyValue(\"height\"));e=parseInt(e.getComputedStylePropertyValue(\"width\"));return!!t&&(0===n||0===e)}function Zl(e){var t,n,r;return!(1<arguments.length&&void 0!==arguments[1]?arguments[1]:{}).isAncestor&&\"fixed\"!==(t=e.getComputedStylePropertyValue(\"position\"))&&!!(n=zl(e)).length&&(r=e.boundingClientRect,n.some((function(n){return!(\"absolute\"===t&&!((e,t)=>{for(var n=e.parent;n&&n!==t;){if([\"relative\",\"sticky\"].includes(n.getComputedStylePropertyValue(\"position\")))return 1;n=n.parent}})(e,n)&&\"static\"===n.getComputedStylePropertyValue(\"position\"))&&((n=n.boundingClientRect).width<2||n.height<2||!Ll(r,n))})))}function Jl(e){var t=e.getComputedStylePropertyValue(\"clip\").match(Vl),n=e.getComputedStylePropertyValue(\"clip-path\").match(Gl);if(t&&5===t.length&&(e=e.getComputedStylePropertyValue(\"position\"),[\"fixed\",\"absolute\"].includes(e)))return t[3]-t[1]<=0&&t[2]-t[4]<=0;if(n){e=n[1];var r=parseIn\\\nt(n[2],10);switch(e){case\"inset\":return 50<=r;case\"circle\":return 0===r}}return!1}function Ql(e,t){var n,r=Wd(e,\"map\");return!r||!((r=r.attr(\"name\"))&&(e=Ml(e.actualNode))&&9===e.nodeType&&(n=fm(o._tree,'img[usemap=\"#'.concat(Aa(r),'\"]')))&&n.length)||n.some((function(e){return!t(e)}))}function eu(e){var t;return\"details\"===(null==(t=e.parent)?void 0:t.props.nodeName)&&((\"summary\"!==e.props.nodeName||e.parent.children.find((function(e){return\"summary\"===e.props.nodeName}))!==e)&&!e.parent.hasAttr(\"open\"))}var tu=[Hl,Ul,Wl,eu];function nu(e){var t=(n=1<arguments.length&&void 0!==arguments[1]?arguments[1]:{}).skipAncestors,n=void 0!==(n=n.isAncestor)&&n;return e=Hf(e).vNode,(t?ru:au)(e,n)}var ru=cl((function(e,t){return!!$l(e)||!(!e.actualNode||!tu.some((function(n){return n(e,{isAncestor:t})}))&&e.actualNode.isConnected)})),au=cl((function(e,t){return!!ru(e,t)||!!e.parent&&au(e.parent,!0)})),ou=function e(t){if(t.assignedSlot)return e(t.assignedSlot);if(t.parentNode){if(1===(t=t.parentN\\\node).nodeType)return t;if(t.host)return t.host}return null},iu=function(e){var t,n;return 9===(e=!e.nodeType&&e.document?e.document:e).nodeType?(t=e.documentElement,n=e.body,{left:t&&t.scrollLeft||n&&n.scrollLeft||0,top:t&&t.scrollTop||n&&n.scrollTop||0}):{left:e.scrollLeft,top:e.scrollTop}},lu=function(e){var t=(n=iu(r)).left,n=n.top;return{top:(e=e.getBoundingClientRect()).top+n,right:e.right+t,bottom:e.bottom+n,left:e.left+t,width:e.right-e.left,height:e.bottom-e.top}},uu=function(e){var t=e.document,n=t.documentElement;return e.innerWidth?{width:e.innerWidth,height:e.innerHeight}:n?{width:n.clientWidth,height:n.clientHeight}:{width:(e=t.body).clientWidth,height:e.clientHeight}},su=function(e){if((1<arguments.length&&void 0!==arguments[1]?arguments[1]:{}).isAncestor)return!1;if(e=Hf(e).domNode){var n=r.documentElement,a=t.getComputedStyle(e),o=t.getComputedStyle(r.body||n).getPropertyValue(\"direction\"),i=lu(e);if(i.bottom<0&&(((e,t)=>{for(e=ou(e);e&&\"html\"!==e.nodeName.toLowerCase()\\\n;){if(e.scrollTop&&0<=(t+=e.scrollTop))return;e=ou(e)}return 1})(e,i.bottom)||\"absolute\"===a.position))return!0;if(0!==i.left||0!==i.right)if(\"ltr\"===o){if(i.right<=0)return!0}else if(e=Math.max(n.scrollWidth,uu(t).width),i.left>=e)return!0;return!1}},cu=[Kl,Xl,Zl,Jl,su];function du(e){return e=Hf(e).vNode,pu(e)}var pu=cl((function(e,t){return e.actualNode&&\"area\"===e.props.nodeName?!Ql(e,pu):!(nu(e,{skipAncestors:!0,isAncestor:t})||e.actualNode&&cu.some((function(n){return n(e,{isAncestor:t})})))&&(!e.parent||pu(e.parent,!0))}));function fu(e,n){var r=Math.min(e.top,n.top),a=Math.max(e.right,n.right),o=Math.max(e.bottom,n.bottom);e=Math.min(e.left,n.left);return new t.DOMRect(e,r,a-e,o-r)}function mu(e,t){var n=e.x;e=e.y;return t.top<=e&&n<=t.right&&e<=t.bottom&&t.left<=n}var hu={};function gu(e,n){var r=Math.max(e.left,n.left),a=Math.min(e.right,n.right),o=Math.max(e.top,n.top);e=Math.min(e.bottom,n.bottom);return a<=r||e<=o?null:new t.DOMRect(r,o,a-r,e-o)}function vu(e){var n=e.left\\\n;return new t.DOMPoint(n+e.width/2,e.top+e.height/2)}ce(hu,{getBoundingRect:function(){return fu},getIntersectionRect:function(){return gu},getOffset:function(){return Du},getRectCenter:function(){return vu},hasVisualOverlap:function(){return xu},isPointInRect:function(){return mu},rectHasMinimumSize:function(){return yu},rectsOverlap:function(){return Ll},splitRects:function(){return Eu}});var bu=.05;function yu(e,t){return e<=t.width+bu&&e<=t.height+bu}function Du(e,t){var n=2<arguments.length&&void 0!==arguments[2]?arguments[2]:12,r=(e=os(e),os(t));if(!e.length||!r.length)return null;var a,o=vu(e.reduce(fu)),i=1/0,l=K(r);try{for(l.s();!(a=l.n()).done;){var u=a.value;if(mu(o,u))return 0;var s=wu(o,((e,t)=>({x:e.x<t.left?t.left:e.x>t.right?t.right:e.x,y:t=e.y<t.top?t.top:e.y>t.bottom?t.bottom:e.y}))(o,u));i=Math.min(i,s)}}catch(e){l.e(e)}finally{l.f()}return yu(2*n,is(t))?i:(e=wu(o,vu(r.reduce(fu)))-n,Math.max(0,Math.min(i,e)))}function wu(e,t){return Math.hypot(e.x-t.x,e.y-t.y)}funct\\\nion xu(e,t){var n=e.boundingClientRect,r=t.boundingClientRect;return!(n.left>=r.right||n.right<=r.left||n.top>=r.bottom||n.bottom<=r.top)&&0<Zu(e,t)}function Eu(e,t){var n,r=[e],a=K(t);try{var o=function(){var e=n.value;if(4e3<(r=r.reduce((function(t,n){return t.concat(((e,t)=>{var n=e.top,r=e.left,a=e.bottom,o=e.right,i=n<t.bottom&&a>t.top,l=r<t.right&&o>t.left,u=[];if(Au(t.top,n,a)&&l&&u.push({top:n,left:r,bottom:t.top,right:o}),Au(t.right,r,o)&&i&&u.push({top:n,left:t.right,bottom:a,right:o}),Au(t.bottom,n,a)&&l&&u.push({top:t.bottom,right:o,bottom:a,left:r}),Au(t.left,r,o)&&i&&u.push({top:n,left:r,bottom:a,right:t.left}),0===u.length){if(((e,t)=>e.top>=t.top&&e.left>=t.left&&e.bottom<=t.bottom&&e.right<=t.right)(e,t))return[];u.push(e)}return u.map(Fu)})(n,e))}),[])).length)throw new Error(\"splitRects: Too many rects\")};for(a.s();!(n=a.n()).done;)o()}catch(e){a.e(e)}finally{a.f()}return r}var Au=function(e,t,n){return t<e&&e<n};function Fu(e){return new t.DOMRect(e.left,e.top,e.rig\\\nht-e.left,e.bottom-e.top)}var Cu=0,ku=.1,Ru=.2,Nu=.3,Tu=0;function Su(){var e=0<arguments.length&&void 0!==arguments[0]?arguments[0]:r.body,n=1<arguments.length?arguments[1]:void 0,a=2<arguments.length&&void 0!==arguments[2]?arguments[2]:null;if(!Sl.get(\"gridCreated\")||a){Sl.set(\"gridCreated\",!0),a||(l=(l=_l(r.documentElement))||new Sd(r.documentElement),Tu=0,l._stackingOrder=[Mu(Cu,Tu++,null)],Pu(n=null!=n?n:new Iu,l),Cf(l.actualNode)&&(i=new Iu(l),l._subGrid=i));for(var i,l,u=r.createTreeWalker(e,t.NodeFilter.SHOW_ELEMENT,null,!1),s=a?u.nextNode():u.currentNode;s;){var c=_l(s),d=(c&&c.parent?a=c.parent:s.assignedSlot?a=_l(s.assignedSlot):s.parentElement?a=_l(s.parentElement):s.parentNode&&_l(s.parentNode)&&(a=_l(s.parentNode)),(c=c||new o.VirtualNode(s,a))._stackingOrder=((e,t,n)=>{var r=t._stackingOrder.slice(),a=(_u(e,t)&&-1!==(a=r.findIndex((function(e){return e=e.stackLevel,[Cu,Ru,Nu].includes(e)})))&&r.splice(a,r.length-a),((e,t)=>{var n=((e,t)=>\"static\"!==e.getComputedStyleProp\\\nertyValue(\"position\")||Ou(t)?e.getComputedStylePropertyValue(\"z-index\"):\"auto\")(e,t);return[\"auto\",\"0\"].includes(n)?\"static\"!==e.getComputedStylePropertyValue(\"position\")?Nu:\"none\"!==e.getComputedStylePropertyValue(\"float\")?Ru:_u(e,t)?ku:null:parseInt(n)})(e,t));return null!==a&&r.push(Mu(a,n,e)),r})(c,a,Tu++),((e,t)=>{for(var n=null,r=[e];t;){if(Cf(t.actualNode)){n=t;break}if(t._scrollRegionParent){n=t._scrollRegionParent;break}r.push(t),t=_l(t.actualNode.parentElement||t.actualNode.parentNode)}return r.forEach((function(e){return e._scrollRegionParent=n})),n})(c,a)),p=(d=d?d._subGrid:n,Cf(c.actualNode)&&(p=new Iu(c),c._subGrid=p),c.boundingClientRect);0!==p.width&&0!==p.height&&du(s)&&Pu(d,c),Wp(s)&&Su(s.shadowRoot,d,c),s=u.nextNode()}}return oa.gridSize}function _u(e,t){var n=e.getComputedStylePropertyValue(\"position\"),r=e.getComputedStylePropertyValue(\"z-index\");return\"fixed\"===n||\"sticky\"===n||\"auto\"!==r&&\"static\"!==n||\"1\"!==e.getComputedStylePropertyValue(\"opacity\")||\"none\"!==(e.\\\ngetComputedStylePropertyValue(\"-webkit-transform\")||e.getComputedStylePropertyValue(\"-ms-transform\")||e.getComputedStylePropertyValue(\"transform\")||\"none\")||(n=e.getComputedStylePropertyValue(\"mix-blend-mode\"))&&\"normal\"!==n||(n=e.getComputedStylePropertyValue(\"filter\"))&&\"none\"!==n||(n=e.getComputedStylePropertyValue(\"perspective\"))&&\"none\"!==n||(n=e.getComputedStylePropertyValue(\"clip-path\"))&&\"none\"!==n||\"none\"!==(e.getComputedStylePropertyValue(\"-webkit-mask\")||e.getComputedStylePropertyValue(\"mask\")||\"none\")||\"none\"!==(e.getComputedStylePropertyValue(\"-webkit-mask-image\")||e.getComputedStylePropertyValue(\"mask-image\")||\"none\")||\"none\"!==(e.getComputedStylePropertyValue(\"-webkit-mask-border\")||e.getComputedStylePropertyValue(\"mask-border\")||\"none\")||\"isolate\"===e.getComputedStylePropertyValue(\"isolation\")||\"transform\"===(n=e.getComputedStylePropertyValue(\"will-change\"))||\"opacity\"===n||\"touch\"===e.getComputedStylePropertyValue(\"-webkit-overflow-scrolling\")||(n=e.getComputedStylePro\\\npertyValue(\"contain\"),[\"layout\",\"paint\",\"strict\",\"content\"].includes(n))||!(\"auto\"===r||!Ou(t))}function Ou(e){if(e)return e=e.getComputedStylePropertyValue(\"display\"),[\"flex\",\"inline-flex\",\"grid\",\"inline-grid\"].includes(e)}function Mu(e,t,n){return{stackLevel:e,treeOrder:t,vNode:n}}function Pu(e,t){var n=zl(t);t.clientRects.forEach((function(r){r=n.reduce((function(e,t){return e&&gu(e,t.boundingClientRect)}),r);r&&(null==t._grid&&(t._grid=e),r=e.getGridPositionOfRect(r),e.loopGridPosition(r,(function(e){e.includes(t)||e.push(t)})))}))}var Iu=W((function e(){var t=0<arguments.length&&void 0!==arguments[0]?arguments[0]:null;H(this,e),this.container=t,this.cells=[]}),[{key:\"toGridIndex\",value:function(e){return Math.floor(e/oa.gridSize)}},{key:\"getCellFromPoint\",value:function(e){var t=e.x;e=e.y,xa(this.boundaries,\"Grid does not have cells added\"),e=this.toGridIndex(e),t=this.toGridIndex(t);return null!=(t=(e=(xa(mu({y:e,x:t},this.boundaries),\"Element midpoint exceeds the grid bounds\"),n\\\null!=(e=this.cells[e-this.cells._negativeIndex])?e:[]))[t-e._negativeIndex])?t:[]}},{key:\"loopGridPosition\",value:function(e,t){var n=(o=e).left,r=o.right,a=o.top,o=o.bottom;this.boundaries&&(e=fu(this.boundaries,e)),this.boundaries=e,Bu(this.cells,a,o,(function(e,a){Bu(e,n,r,(function(e,n){t(e,{row:a,col:n})}))}))}},{key:\"getGridPositionOfRect\",value:function(e){var n=e.top,r=e.right,a=e.bottom,o=(e=e.left,1<arguments.length&&void 0!==arguments[1]?arguments[1]:0);n=this.toGridIndex(n-o),r=this.toGridIndex(r+o-1),a=this.toGridIndex(a+o-1),e=this.toGridIndex(e-o);return new t.DOMRect(e,n,r-e,a-n)}}]);function Bu(e,t,n,r){if(null!=e._negativeIndex||(e._negativeIndex=0),t<e._negativeIndex){for(var a=0;a<e._negativeIndex-t;a++)e.splice(0,0,[]);e._negativeIndex=t}for(var o,i=n-e._negativeIndex,l=t-e._negativeIndex;l<=i;l++)null==e[o=l]&&(e[o]=[]),r(e[l],l+e._negativeIndex)}function ju(e){return Su(),Hf(e).vNode._grid}function Lu(e){var t,n,r,a=1<arguments.length&&void 0!==arguments[1]?argum\\\nents[1]:0,o=ju(e);return null!=o&&null!=(n=o.cells)&&n.length?(n=e.boundingClientRect,t=qu(e),n=o.getGridPositionOfRect(n,a),r=[],o.loopGridPosition(n,(function(n){var a,o=K(n);try{for(o.s();!(a=o.n()).done;){var i=a.value;i&&i!==e&&!r.includes(i)&&t===qu(i)&&r.push(i)}}catch(n){o.e(n)}finally{o.f()}})),r):[]}var qu=cl((function(e){return!!e&&(\"fixed\"===e.getComputedStylePropertyValue(\"position\")||qu(e.parent))})),zu=cl((function(){var e;return o._tree&&(e=rm(o._tree[0],\"dialog[open]\",(function(e){var t=e.boundingClientRect;return r.elementsFromPoint(t.left+1,t.top+1).includes(e.actualNode)&&du(e)}))).length?e.find((function(e){var t=e.boundingClientRect;return r.elementsFromPoint(t.left-10,t.top-10).includes(e.actualNode)}))||(null!=(e=e.find((function(e){e=null!=(e=(e=>{Su();var n=o._tree[0]._grid,r=new t.DOMRect(0,0,t.innerWidth,t.innerHeight);if(n)for(var a=0;a<n.cells.length;a++){var i=n.cells[a];if(i)for(var l=0;l<i.length;l++){var u=i[l];if(u)for(var s=0;s<u.length;s++){var c=u[\\\ns],d=gu(c.boundingClientRect,r);if(\"html\"!==c.props.nodeName&&c!==e&&\"none\"!==c.getComputedStylePropertyValue(\"pointer-events\")&&d)return{vNode:c,rect:d}}}}})(e))?e:{};var n=e.vNode;e=e.rect;return!!n&&!r.elementsFromPoint(e.left+1,e.top+1).includes(n.actualNode)})))?e:null):null}));function Vu(e){var t=(n=1<arguments.length&&void 0!==arguments[1]?arguments[1]:{}).skipAncestors,n=n.isAncestor;return(t?Gu:$u)(e,n)}var Gu=cl((function(e,t){return!!e.hasAttr(\"inert\")||!(t||!e.actualNode||!(t=zu())||Vp(t,e))})),$u=cl((function(e,t){return!!Gu(e,t)||!!e.parent&&$u(e.parent,!0)})),Hu=[\"button\",\"command\",\"fieldset\",\"keygen\",\"optgroup\",\"option\",\"select\",\"textarea\",\"input\"],Uu=function(e){var t=Hf(e).vNode;if(e=t.props.nodeName,Hu.includes(e)&&t.hasAttr(\"disabled\")||Vu(t))return!0;for(var n=t.parent,r=[],a=!1;n&&n.shadowId===t.shadowId&&!a&&(r.push(n),\"legend\"!==n.props.nodeName);){if(void 0!==n._inDisabledFieldset){a=n._inDisabledFieldset;break}\"fieldset\"===n.props.nodeName&&n.hasAttr(\"disable\\\nd\")&&(a=!0),n=n.parent}return r.forEach((function(e){return e._inDisabledFieldset=a})),!!a||\"area\"!==t.props.nodeName&&!!t.actualNode&&nu(t)},Wu=/^\\\\/\\\\#/,Yu=/^#[!/]/;function Ku(e){var n,r,a,o,i=e.getAttribute(\"href\");return!(!i||\"#\"===i)&&(!!Wu.test(i)||(o=e.hash,n=e.protocol,r=e.hostname,a=e.port,e=e.pathname,!Yu.test(o)&&(\"#\"===i.charAt(0)||(\"string\"!=typeof(null==(o=t.location)?void 0:o.origin)||-1===t.location.origin.indexOf(\"://\")?null:(i=t.location.origin+t.location.pathname,o=r?\"\".concat(n,\"//\").concat(r).concat(a?\":\".concat(a):\"\"):t.location.origin,(o+=e?(\"/\"!==e[0]?\"/\":\"\")+e:t.location.pathname)===i)))))}var Xu=function(e,t){var n=e.getAttribute(t);return n&&(\"href\"!==t||Ku(e))?(-1!==n.indexOf(\"#\")&&(n=decodeURIComponent(n.substr(n.indexOf(\"#\")+1))),(t=r.getElementById(n))||((t=r.getElementsByName(n)).length?t[0]:null)):null};function Zu(e,n){Su();for(var r=Math.max(e._stackingOrder.length,n._stackingOrder.length),a=0;a<r;a++){if(void 0===n._stackingOrder[a])return-1;if(void 0\\\n===e._stackingOrder[a])return 1;if(n._stackingOrder[a].stackLevel>e._stackingOrder[a].stackLevel)return 1;if(n._stackingOrder[a].stackLevel<e._stackingOrder[a].stackLevel)return-1;if(n._stackingOrder[a].treeOrder!==e._stackingOrder[a].treeOrder)return n._stackingOrder[a].treeOrder-e._stackingOrder[a].treeOrder}var o=e.actualNode,i=n.actualNode;if(o.getRootNode&&o.getRootNode()!==i.getRootNode()){for(var l=[];o;)l.push({root:o.getRootNode(),node:o}),o=o.getRootNode().host;for(;i&&!l.find((function(e){return e.root===i.getRootNode()}));)i=i.getRootNode().host;if((o=l.find((function(e){return e.root===i.getRootNode()})).node)===i)return e.actualNode.getRootNode()!==o.getRootNode()?-1:1}var u,s=(d=t.Node).DOCUMENT_POSITION_FOLLOWING,c=d.DOCUMENT_POSITION_CONTAINS,d=d.DOCUMENT_POSITION_CONTAINED_BY;s=(u=o.compareDocumentPosition(i))&s?1:-1,c=u&c||u&d;return(u=Ju(e))===(d=Ju(n))||c?s:d-u}function Ju(e){return-1!==e.getComputedStylePropertyValue(\"display\").indexOf(\"inline\")?2:function e(t){if\\\n(!t)return!1;if(void 0!==t._isFloated)return t._isFloated;var n=t.getComputedStylePropertyValue(\"float\");return\"none\"!==n?t._isFloated=!0:(n=e(t.parent),t._isFloated=n,n)}(e)?1:0}function Qu(e,t,n){n=2<arguments.length&&void 0!==n&&n,t=vu(t);var a=e.getCellFromPoint(t)||[],o=Math.floor(t.x),i=Math.floor(t.y);t=a.filter((function(e){return e.clientRects.some((function(e){var t=e.left,n=e.top;return o<Math.floor(t+e.width)&&o>=Math.floor(t)&&i<Math.floor(n+e.height)&&i>=Math.floor(n)}))}));return(a=e.container)&&(t=Qu(a._grid,a.boundingClientRect,!0).concat(t)),n?t:t.sort(Zu).map((function(e){return e.actualNode})).concat(r.documentElement).filter((function(e,t,n){return n.indexOf(e)===t}))}var es=function(e){var t=ju(e);return t?Qu(t,_l(e).boundingClientRect):[]},ts=function(e){return fm(e,\"*\").filter((function(e){var t=e.isFocusable;return null!==(e=Zf(e.actualNode.getAttribute(\"tabindex\")))?t&&0<=e:t}))},ns=function(e){var t=Hf(e).vNode;if(t&&!Uu(t))switch(t.props.nodeName){case\"a\":ca\\\nse\"area\":if(t.hasAttr(\"href\"))return!0;break;case\"input\":return\"hidden\"!==t.props.type;case\"textarea\":case\"select\":case\"summary\":case\"button\":return!0;case\"details\":return!fm(t,\"summary\").length}return!1};function rs(e){return 1===(e=Hf(e).vNode).props.nodeType&&!(Uu(e)||!ns(e)&&null===Zf(e.attr(\"tabindex\")))}function as(e){return 1===(e=Hf(e).vNode).props.nodeType&&!(Zf(e.attr(\"tabindex\"))<=-1)&&rs(e)}var os=cl((function(e){var t=e.boundingClientRect,n=Lu(e).filter((function(t){return xu(e,t)&&\"none\"!==t.getComputedStylePropertyValue(\"pointer-events\")&&!(Vp(e,t)&&!as(t))}));return n.length?(n=n.map((function(e){return e.boundingClientRect})),Eu(t,n)):[t]})),is=cl((function(e,t){return((e,t)=>e.reduce((function(e,n){var r=yu(t,e);return r!==yu(t,n)?r?e:n:(r=e.width*e.height,n.width*n.height<r?e:n)})))(os(e),t)})),ls={},us=(ce(ls,{accessibleText:function(){return ss},accessibleTextVirtual:function(){return kc},autocomplete:function(){return Sc},formControlValue:function(){return gc},for\\\nmControlValueMethods:function(){return mc},hasUnicode:function(){return Fc},isHumanInterpretable:function(){return Tc},isIconLigature:function(){return Cc},isValidAutocomplete:function(){return _c},label:function(){return Ic},labelText:function(){return yc},labelVirtual:function(){return Pc},nativeElementType:function(){return Bc},nativeTextAlternative:function(){return Ac},nativeTextMethods:function(){return Ec},removeUnicode:function(){return Nc},sanitize:function(){return Ns},subtreeText:function(){return bc},titleText:function(){return Js},unsupported:function(){return tc},visible:function(){return Mc},visibleTextNodes:function(){return jc},visibleVirtual:function(){return ac}}),function(e,t){e=e.actualNode||e;try{var n=Pl(e),r=[];if(a=e.getAttribute(t))for(var a=Yp(a),o=0;o<a.length;o++)r.push(n.getElementById(a[o]));return r}catch(e){throw new TypeError(\"Cannot resolve id references for non-DOM nodes\")}}),ss=function(e,t){return kc(_l(e),t)},cs=function(e){var t=1<arguments.lengt\\\nh&&void 0!==arguments[1]?arguments[1]:{},n=Hf(e).vNode;return 1!==(null==n?void 0:n.props.nodeType)||1!==n.props.nodeType||t.inLabelledByContext||t.inControlContext||!n.attr(\"aria-labelledby\")?\"\":us(n,\"aria-labelledby\").filter((function(e){return e})).reduce((function(e,r){return r=ss(r,O({inLabelledByContext:!0,startNode:t.startNode||n},t)),e?\"\".concat(e,\" \").concat(r):r}),\"\")};function ds(e){return 1===(null==(e=Hf(e).vNode)?void 0:e.props.nodeType)&&e.attr(\"aria-label\")||\"\"}var ps={\"aria-activedescendant\":{type:\"idref\",allowEmpty:!0},\"aria-atomic\":{type:\"boolean\",global:!0},\"aria-autocomplete\":{type:\"nmtoken\",values:[\"inline\",\"list\",\"both\",\"none\"]},\"aria-braillelabel\":{type:\"string\",allowEmpty:!0,global:!0},\"aria-brailleroledescription\":{type:\"string\",allowEmpty:!0,global:!0},\"aria-busy\":{type:\"boolean\",global:!0},\"aria-checked\":{type:\"nmtoken\",values:[\"false\",\"mixed\",\"true\",\"undefined\"]},\"aria-colcount\":{type:\"int\",minValue:-1},\"aria-colindex\":{type:\"int\",minValue:1},\"aria-colspan\"\\\n:{type:\"int\",minValue:1},\"aria-controls\":{type:\"idrefs\",allowEmpty:!0,global:!0},\"aria-current\":{type:\"nmtoken\",allowEmpty:!0,values:[\"page\",\"step\",\"location\",\"date\",\"time\",\"true\",\"false\"],global:!0},\"aria-describedby\":{type:\"idrefs\",allowEmpty:!0,global:!0},\"aria-description\":{type:\"string\",allowEmpty:!0,global:!0},\"aria-details\":{type:\"idref\",allowEmpty:!0,global:!0},\"aria-disabled\":{type:\"boolean\",global:!0},\"aria-dropeffect\":{type:\"nmtokens\",values:[\"copy\",\"execute\",\"link\",\"move\",\"none\",\"popup\"],global:!0},\"aria-errormessage\":{type:\"idref\",allowEmpty:!0,global:!0},\"aria-expanded\":{type:\"nmtoken\",values:[\"true\",\"false\",\"undefined\"]},\"aria-flowto\":{type:\"idrefs\",allowEmpty:!0,global:!0},\"aria-grabbed\":{type:\"nmtoken\",values:[\"true\",\"false\",\"undefined\"],global:!0},\"aria-haspopup\":{type:\"nmtoken\",allowEmpty:!0,values:[\"true\",\"false\",\"menu\",\"listbox\",\"tree\",\"grid\",\"dialog\"],global:!0},\"aria-hidden\":{type:\"nmtoken\",values:[\"true\",\"false\",\"undefined\"],global:!0},\"aria-invalid\":{type:\"nmto\\\nken\",values:[\"grammar\",\"false\",\"spelling\",\"true\"],global:!0},\"aria-keyshortcuts\":{type:\"string\",allowEmpty:!0,global:!0},\"aria-label\":{type:\"string\",allowEmpty:!0,global:!0},\"aria-labelledby\":{type:\"idrefs\",allowEmpty:!0,global:!0},\"aria-level\":{type:\"int\",minValue:1},\"aria-live\":{type:\"nmtoken\",values:[\"assertive\",\"off\",\"polite\"],global:!0},\"aria-modal\":{type:\"boolean\"},\"aria-multiline\":{type:\"boolean\"},\"aria-multiselectable\":{type:\"boolean\"},\"aria-orientation\":{type:\"nmtoken\",values:[\"horizontal\",\"undefined\",\"vertical\"]},\"aria-owns\":{type:\"idrefs\",allowEmpty:!0,global:!0},\"aria-placeholder\":{type:\"string\",allowEmpty:!0},\"aria-posinset\":{type:\"int\",minValue:1},\"aria-pressed\":{type:\"nmtoken\",values:[\"false\",\"mixed\",\"true\",\"undefined\"]},\"aria-readonly\":{type:\"boolean\"},\"aria-relevant\":{type:\"nmtokens\",values:[\"additions\",\"all\",\"removals\",\"text\"],global:!0},\"aria-required\":{type:\"boolean\"},\"aria-roledescription\":{type:\"string\",allowEmpty:!0,global:!0},\"aria-rowcount\":{type:\"int\",minValue\\\n:-1},\"aria-rowindex\":{type:\"int\",minValue:1},\"aria-rowspan\":{type:\"int\",minValue:0},\"aria-selected\":{type:\"nmtoken\",values:[\"false\",\"true\",\"undefined\"]},\"aria-setsize\":{type:\"int\",minValue:-1},\"aria-sort\":{type:\"nmtoken\",values:[\"ascending\",\"descending\",\"none\",\"other\"]},\"aria-valuemax\":{type:\"decimal\"},\"aria-valuemin\":{type:\"decimal\"},\"aria-valuenow\":{type:\"decimal\"},\"aria-valuetext\":{type:\"string\",allowEmpty:!0}},fs={alert:{type:\"structure\",allowedAttrs:[\"aria-expanded\"],superclassRole:[\"section\"]},alertdialog:{type:\"window\",allowedAttrs:[\"aria-expanded\",\"aria-modal\"],superclassRole:[\"alert\",\"dialog\"],accessibleNameRequired:!0},application:{type:\"landmark\",allowedAttrs:[\"aria-activedescendant\",\"aria-expanded\"],superclassRole:[\"structure\"],accessibleNameRequired:!0},article:{type:\"structure\",allowedAttrs:[\"aria-posinset\",\"aria-setsize\",\"aria-expanded\"],superclassRole:[\"document\"]},banner:{type:\"landmark\",allowedAttrs:[\"aria-expanded\"],superclassRole:[\"landmark\"]},blockquote:{type:\"stru\\\ncture\",superclassRole:[\"section\"]},button:{type:\"widget\",allowedAttrs:[\"aria-expanded\",\"aria-pressed\"],superclassRole:[\"command\"],accessibleNameRequired:!0,nameFromContent:!0,childrenPresentational:!0},caption:{type:\"structure\",requiredContext:[\"figure\",\"table\",\"grid\",\"treegrid\"],superclassRole:[\"section\"],prohibitedAttrs:[\"aria-label\",\"aria-labelledby\"]},cell:{type:\"structure\",requiredContext:[\"row\"],allowedAttrs:[\"aria-colindex\",\"aria-colspan\",\"aria-rowindex\",\"aria-rowspan\",\"aria-expanded\"],superclassRole:[\"section\"],nameFromContent:!0},checkbox:{type:\"widget\",requiredAttrs:[\"aria-checked\"],allowedAttrs:[\"aria-readonly\",\"aria-expanded\",\"aria-required\"],superclassRole:[\"input\"],accessibleNameRequired:!0,nameFromContent:!0,childrenPresentational:!0},code:{type:\"structure\",superclassRole:[\"section\"],prohibitedAttrs:[\"aria-label\",\"aria-labelledby\"]},columnheader:{type:\"structure\",requiredContext:[\"row\"],allowedAttrs:[\"aria-sort\",\"aria-colindex\",\"aria-colspan\",\"aria-expanded\",\"aria-readon\\\nly\",\"aria-required\",\"aria-rowindex\",\"aria-rowspan\",\"aria-selected\"],superclassRole:[\"cell\",\"gridcell\",\"sectionhead\"],accessibleNameRequired:!1,nameFromContent:!0},combobox:{type:\"widget\",requiredAttrs:[\"aria-expanded\",\"aria-controls\"],allowedAttrs:[\"aria-owns\",\"aria-autocomplete\",\"aria-readonly\",\"aria-required\",\"aria-activedescendant\",\"aria-orientation\"],superclassRole:[\"select\"],accessibleNameRequired:!0},command:{type:\"abstract\",superclassRole:[\"widget\"]},complementary:{type:\"landmark\",allowedAttrs:[\"aria-expanded\"],superclassRole:[\"landmark\"]},composite:{type:\"abstract\",superclassRole:[\"widget\"]},contentinfo:{type:\"landmark\",allowedAttrs:[\"aria-expanded\"],superclassRole:[\"landmark\"]},comment:{type:\"structure\",allowedAttrs:[\"aria-level\",\"aria-posinset\",\"aria-setsize\"],superclassRole:[\"article\"]},definition:{type:\"structure\",allowedAttrs:[\"aria-expanded\"],superclassRole:[\"section\"]},deletion:{type:\"structure\",superclassRole:[\"section\"],prohibitedAttrs:[\"aria-label\",\"aria-labelledby\"]}\\\n,dialog:{type:\"window\",allowedAttrs:[\"aria-expanded\",\"aria-modal\"],superclassRole:[\"window\"],accessibleNameRequired:!0},directory:{type:\"structure\",deprecated:!0,allowedAttrs:[\"aria-expanded\"],superclassRole:[\"list\"],nameFromContent:!0},document:{type:\"structure\",allowedAttrs:[\"aria-expanded\"],superclassRole:[\"structure\"]},emphasis:{type:\"structure\",superclassRole:[\"section\"],prohibitedAttrs:[\"aria-label\",\"aria-labelledby\"]},feed:{type:\"structure\",requiredOwned:[\"article\"],allowedAttrs:[\"aria-expanded\"],superclassRole:[\"list\"]},figure:{type:\"structure\",allowedAttrs:[\"aria-expanded\"],superclassRole:[\"section\"],nameFromContent:!0},form:{type:\"landmark\",allowedAttrs:[\"aria-expanded\"],superclassRole:[\"landmark\"]},grid:{type:\"composite\",requiredOwned:[\"rowgroup\",\"row\"],allowedAttrs:[\"aria-level\",\"aria-multiselectable\",\"aria-readonly\",\"aria-activedescendant\",\"aria-colcount\",\"aria-expanded\",\"aria-rowcount\"],superclassRole:[\"composite\",\"table\"],accessibleNameRequired:!1},gridcell:{type:\"widget\\\n\",requiredContext:[\"row\"],allowedAttrs:[\"aria-readonly\",\"aria-required\",\"aria-selected\",\"aria-colindex\",\"aria-colspan\",\"aria-expanded\",\"aria-rowindex\",\"aria-rowspan\"],superclassRole:[\"cell\",\"widget\"],nameFromContent:!0},group:{type:\"structure\",allowedAttrs:[\"aria-activedescendant\",\"aria-expanded\"],superclassRole:[\"section\"]},heading:{type:\"structure\",requiredAttrs:[\"aria-level\"],allowedAttrs:[\"aria-expanded\"],superclassRole:[\"sectionhead\"],accessibleNameRequired:!1,nameFromContent:!0},img:{type:\"structure\",allowedAttrs:[\"aria-expanded\"],superclassRole:[\"section\"],accessibleNameRequired:!0,childrenPresentational:!0},input:{type:\"abstract\",superclassRole:[\"widget\"]},insertion:{type:\"structure\",superclassRole:[\"section\"],prohibitedAttrs:[\"aria-label\",\"aria-labelledby\"]},landmark:{type:\"abstract\",superclassRole:[\"section\"]},link:{type:\"widget\",allowedAttrs:[\"aria-expanded\"],superclassRole:[\"command\"],accessibleNameRequired:!0,nameFromContent:!0},list:{type:\"structure\",requiredOwned:[\"listi\\\ntem\"],allowedAttrs:[\"aria-expanded\"],superclassRole:[\"section\"]},listbox:{type:\"widget\",requiredOwned:[\"group\",\"option\"],allowedAttrs:[\"aria-multiselectable\",\"aria-readonly\",\"aria-required\",\"aria-activedescendant\",\"aria-expanded\",\"aria-orientation\"],superclassRole:[\"select\"],accessibleNameRequired:!0},listitem:{type:\"structure\",requiredContext:[\"list\"],allowedAttrs:[\"aria-level\",\"aria-posinset\",\"aria-setsize\",\"aria-expanded\"],superclassRole:[\"section\"],nameFromContent:!0},log:{type:\"structure\",allowedAttrs:[\"aria-expanded\"],superclassRole:[\"section\"]},main:{type:\"landmark\",allowedAttrs:[\"aria-expanded\"],superclassRole:[\"landmark\"]},marquee:{type:\"structure\",allowedAttrs:[\"aria-expanded\"],superclassRole:[\"section\"]},math:{type:\"structure\",allowedAttrs:[\"aria-expanded\"],superclassRole:[\"section\"],childrenPresentational:!0},menu:{type:\"composite\",requiredOwned:[\"group\",\"menuitemradio\",\"menuitem\",\"menuitemcheckbox\",\"menu\",\"separator\"],allowedAttrs:[\"aria-activedescendant\",\"aria-expanded\",\"\\\naria-orientation\"],superclassRole:[\"select\"]},menubar:{type:\"composite\",requiredOwned:[\"group\",\"menuitemradio\",\"menuitem\",\"menuitemcheckbox\",\"menu\",\"separator\"],allowedAttrs:[\"aria-activedescendant\",\"aria-expanded\",\"aria-orientation\"],superclassRole:[\"menu\"]},menuitem:{type:\"widget\",requiredContext:[\"menu\",\"menubar\",\"group\"],allowedAttrs:[\"aria-posinset\",\"aria-setsize\",\"aria-expanded\"],superclassRole:[\"command\"],accessibleNameRequired:!0,nameFromContent:!0},menuitemcheckbox:{type:\"widget\",requiredContext:[\"menu\",\"menubar\",\"group\"],requiredAttrs:[\"aria-checked\"],allowedAttrs:[\"aria-expanded\",\"aria-posinset\",\"aria-readonly\",\"aria-setsize\"],superclassRole:[\"checkbox\",\"menuitem\"],accessibleNameRequired:!0,nameFromContent:!0,childrenPresentational:!0},menuitemradio:{type:\"widget\",requiredContext:[\"menu\",\"menubar\",\"group\"],requiredAttrs:[\"aria-checked\"],allowedAttrs:[\"aria-expanded\",\"aria-posinset\",\"aria-readonly\",\"aria-setsize\"],superclassRole:[\"menuitemcheckbox\",\"radio\"],accessibleNameRequ\\\nired:!0,nameFromContent:!0,childrenPresentational:!0},meter:{type:\"structure\",requiredAttrs:[\"aria-valuenow\"],allowedAttrs:[\"aria-valuemax\",\"aria-valuemin\",\"aria-valuetext\"],superclassRole:[\"range\"],accessibleNameRequired:!0,childrenPresentational:!0},mark:{type:\"structure\",superclassRole:[\"section\"],prohibitedAttrs:[\"aria-label\",\"aria-labelledby\"]},navigation:{type:\"landmark\",allowedAttrs:[\"aria-expanded\"],superclassRole:[\"landmark\"]},none:{type:\"structure\",superclassRole:[\"structure\"],prohibitedAttrs:[\"aria-label\",\"aria-labelledby\"]},note:{type:\"structure\",allowedAttrs:[\"aria-expanded\"],superclassRole:[\"section\"]},option:{type:\"widget\",requiredContext:[\"group\",\"listbox\"],allowedAttrs:[\"aria-selected\",\"aria-checked\",\"aria-posinset\",\"aria-setsize\"],superclassRole:[\"input\"],accessibleNameRequired:!0,nameFromContent:!0,childrenPresentational:!0},paragraph:{type:\"structure\",superclassRole:[\"section\"],prohibitedAttrs:[\"aria-label\",\"aria-labelledby\"]},presentation:{type:\"structure\",supercla\\\nssRole:[\"structure\"],prohibitedAttrs:[\"aria-label\",\"aria-labelledby\"]},progressbar:{type:\"widget\",allowedAttrs:[\"aria-expanded\",\"aria-valuemax\",\"aria-valuemin\",\"aria-valuenow\",\"aria-valuetext\"],superclassRole:[\"range\"],accessibleNameRequired:!0,childrenPresentational:!0},radio:{type:\"widget\",requiredAttrs:[\"aria-checked\"],allowedAttrs:[\"aria-posinset\",\"aria-setsize\",\"aria-required\"],superclassRole:[\"input\"],accessibleNameRequired:!0,nameFromContent:!0,childrenPresentational:!0},radiogroup:{type:\"composite\",allowedAttrs:[\"aria-readonly\",\"aria-required\",\"aria-activedescendant\",\"aria-expanded\",\"aria-orientation\"],superclassRole:[\"select\"],accessibleNameRequired:!1},range:{type:\"abstract\",superclassRole:[\"widget\"]},region:{type:\"landmark\",allowedAttrs:[\"aria-expanded\"],superclassRole:[\"landmark\"],accessibleNameRequired:!1},roletype:{type:\"abstract\",superclassRole:[]},row:{type:\"structure\",requiredContext:[\"grid\",\"rowgroup\",\"table\",\"treegrid\"],requiredOwned:[\"cell\",\"columnheader\",\"gridcell\"\\\n,\"rowheader\"],allowedAttrs:[\"aria-colindex\",\"aria-level\",\"aria-rowindex\",\"aria-selected\",\"aria-activedescendant\",\"aria-expanded\",\"aria-posinset\",\"aria-setsize\"],superclassRole:[\"group\",\"widget\"],nameFromContent:!0},rowgroup:{type:\"structure\",requiredContext:[\"grid\",\"table\",\"treegrid\"],requiredOwned:[\"row\"],superclassRole:[\"structure\"],nameFromContent:!0},rowheader:{type:\"structure\",requiredContext:[\"row\"],allowedAttrs:[\"aria-sort\",\"aria-colindex\",\"aria-colspan\",\"aria-expanded\",\"aria-readonly\",\"aria-required\",\"aria-rowindex\",\"aria-rowspan\",\"aria-selected\"],superclassRole:[\"cell\",\"gridcell\",\"sectionhead\"],accessibleNameRequired:!1,nameFromContent:!0},scrollbar:{type:\"widget\",requiredAttrs:[\"aria-valuenow\"],allowedAttrs:[\"aria-controls\",\"aria-orientation\",\"aria-valuemax\",\"aria-valuemin\",\"aria-valuetext\"],superclassRole:[\"range\"],childrenPresentational:!0},search:{type:\"landmark\",allowedAttrs:[\"aria-expanded\"],superclassRole:[\"landmark\"]},searchbox:{type:\"widget\",allowedAttrs:[\"aria-active\\\ndescendant\",\"aria-autocomplete\",\"aria-multiline\",\"aria-placeholder\",\"aria-readonly\",\"aria-required\"],superclassRole:[\"textbox\"],accessibleNameRequired:!0},section:{type:\"abstract\",superclassRole:[\"structure\"],nameFromContent:!0},sectionhead:{type:\"abstract\",superclassRole:[\"structure\"],nameFromContent:!0},select:{type:\"abstract\",superclassRole:[\"composite\",\"group\"]},separator:{type:\"structure\",requiredAttrs:[\"aria-valuenow\"],allowedAttrs:[\"aria-valuemax\",\"aria-valuemin\",\"aria-orientation\",\"aria-valuetext\"],superclassRole:[\"structure\",\"widget\"],childrenPresentational:!0},slider:{type:\"widget\",requiredAttrs:[\"aria-valuenow\"],allowedAttrs:[\"aria-valuemax\",\"aria-valuemin\",\"aria-orientation\",\"aria-readonly\",\"aria-required\",\"aria-valuetext\"],superclassRole:[\"input\",\"range\"],accessibleNameRequired:!0,childrenPresentational:!0},spinbutton:{type:\"widget\",allowedAttrs:[\"aria-valuemax\",\"aria-valuemin\",\"aria-readonly\",\"aria-required\",\"aria-activedescendant\",\"aria-valuetext\",\"aria-valuenow\"],superc\\\nlassRole:[\"composite\",\"input\",\"range\"],accessibleNameRequired:!0},status:{type:\"structure\",allowedAttrs:[\"aria-expanded\"],superclassRole:[\"section\"]},strong:{type:\"structure\",superclassRole:[\"section\"],prohibitedAttrs:[\"aria-label\",\"aria-labelledby\"]},structure:{type:\"abstract\",superclassRole:[\"roletype\"]},subscript:{type:\"structure\",superclassRole:[\"section\"],prohibitedAttrs:[\"aria-label\",\"aria-labelledby\"]},superscript:{type:\"structure\",superclassRole:[\"section\"],prohibitedAttrs:[\"aria-label\",\"aria-labelledby\"]},switch:{type:\"widget\",requiredAttrs:[\"aria-checked\"],allowedAttrs:[\"aria-expanded\",\"aria-readonly\",\"aria-required\"],superclassRole:[\"checkbox\"],accessibleNameRequired:!0,nameFromContent:!0,childrenPresentational:!0},suggestion:{type:\"structure\",requiredOwned:[\"insertion\",\"deletion\"],superclassRole:[\"section\"],prohibitedAttrs:[\"aria-label\",\"aria-labelledby\"]},tab:{type:\"widget\",requiredContext:[\"tablist\"],allowedAttrs:[\"aria-posinset\",\"aria-selected\",\"aria-setsize\",\"aria-expan\\\nded\"],superclassRole:[\"sectionhead\",\"widget\"],nameFromContent:!0,childrenPresentational:!0},table:{type:\"structure\",requiredOwned:[\"rowgroup\",\"row\"],allowedAttrs:[\"aria-colcount\",\"aria-rowcount\",\"aria-expanded\"],superclassRole:[\"section\"],accessibleNameRequired:!1,nameFromContent:!0},tablist:{type:\"composite\",requiredOwned:[\"tab\"],allowedAttrs:[\"aria-level\",\"aria-multiselectable\",\"aria-orientation\",\"aria-activedescendant\",\"aria-expanded\"],superclassRole:[\"composite\"]},tabpanel:{type:\"structure\",allowedAttrs:[\"aria-expanded\"],superclassRole:[\"section\"],accessibleNameRequired:!1},term:{type:\"structure\",allowedAttrs:[\"aria-expanded\"],superclassRole:[\"section\"],nameFromContent:!0},text:{type:\"structure\",superclassRole:[\"section\"],nameFromContent:!0},textbox:{type:\"widget\",allowedAttrs:[\"aria-activedescendant\",\"aria-autocomplete\",\"aria-multiline\",\"aria-placeholder\",\"aria-readonly\",\"aria-required\"],superclassRole:[\"input\"],accessibleNameRequired:!0},time:{type:\"structure\",superclassRole:[\"se\\\nction\"]},timer:{type:\"structure\",allowedAttrs:[\"aria-expanded\"],superclassRole:[\"status\"]},toolbar:{type:\"structure\",allowedAttrs:[\"aria-orientation\",\"aria-activedescendant\",\"aria-expanded\"],superclassRole:[\"group\"],accessibleNameRequired:!0},tooltip:{type:\"structure\",allowedAttrs:[\"aria-expanded\"],superclassRole:[\"section\"],nameFromContent:!0},tree:{type:\"composite\",requiredOwned:[\"group\",\"treeitem\"],allowedAttrs:[\"aria-multiselectable\",\"aria-required\",\"aria-activedescendant\",\"aria-expanded\",\"aria-orientation\"],superclassRole:[\"select\"],accessibleNameRequired:!1},treegrid:{type:\"composite\",requiredOwned:[\"rowgroup\",\"row\"],allowedAttrs:[\"aria-activedescendant\",\"aria-colcount\",\"aria-expanded\",\"aria-level\",\"aria-multiselectable\",\"aria-orientation\",\"aria-readonly\",\"aria-required\",\"aria-rowcount\"],superclassRole:[\"grid\",\"tree\"],accessibleNameRequired:!1},treeitem:{type:\"widget\",requiredContext:[\"group\",\"tree\"],allowedAttrs:[\"aria-checked\",\"aria-expanded\",\"aria-level\",\"aria-posinset\",\"aria-\\\nselected\",\"aria-setsize\"],superclassRole:[\"listitem\",\"option\"],accessibleNameRequired:!0,nameFromContent:!0},widget:{type:\"abstract\",superclassRole:[\"roletype\"]},window:{type:\"abstract\",superclassRole:[\"roletype\"]}},ms=(el={a:{variant:{href:{matches:\"[href]\",contentTypes:[\"interactive\",\"phrasing\",\"flow\"],allowedRoles:[\"button\",\"checkbox\",\"menuitem\",\"menuitemcheckbox\",\"menuitemradio\",\"option\",\"radio\",\"switch\",\"tab\",\"treeitem\",\"doc-backlink\",\"doc-biblioref\",\"doc-glossref\",\"doc-noteref\"],namingMethods:[\"subtreeText\"]},default:{contentTypes:[\"phrasing\",\"flow\"],allowedRoles:!0}}},abbr:{contentTypes:[\"phrasing\",\"flow\"],allowedRoles:!0},address:{contentTypes:[\"flow\"],allowedRoles:!0},area:{variant:{href:{matches:\"[href]\",allowedRoles:!1},default:{allowedRoles:[\"button\",\"link\"]}},contentTypes:[\"phrasing\",\"flow\"],namingMethods:[\"altText\"]},article:{contentTypes:[\"sectioning\",\"flow\"],allowedRoles:[\"feed\",\"presentation\",\"none\",\"document\",\"application\",\"main\",\"region\"],shadowRoot:!0},aside:{conten\\\ntTypes:[\"sectioning\",\"flow\"],allowedRoles:[\"feed\",\"note\",\"presentation\",\"none\",\"region\",\"search\",\"doc-dedication\",\"doc-example\",\"doc-footnote\",\"doc-glossary\",\"doc-pullquote\",\"doc-tip\"]},audio:{variant:{controls:{matches:\"[controls]\",contentTypes:[\"interactive\",\"embedded\",\"phrasing\",\"flow\"]},default:{contentTypes:[\"embedded\",\"phrasing\",\"flow\"]}},allowedRoles:[\"application\"],chromiumRole:\"Audio\"},b:{contentTypes:[\"phrasing\",\"flow\"],allowedRoles:!0},base:{allowedRoles:!1,noAriaAttrs:!0},bdi:{contentTypes:[\"phrasing\",\"flow\"],allowedRoles:!0},bdo:{contentTypes:[\"phrasing\",\"flow\"],allowedRoles:!0},blockquote:{contentTypes:[\"flow\"],allowedRoles:!0,shadowRoot:!0},body:{allowedRoles:!1,shadowRoot:!0},br:{contentTypes:[\"phrasing\",\"flow\"],allowedRoles:[\"presentation\",\"none\"],namingMethods:[\"titleText\",\"singleSpace\"]},button:{contentTypes:[\"interactive\",\"phrasing\",\"flow\"],allowedRoles:[\"checkbox\",\"combobox\",\"gridcell\",\"link\",\"menuitem\",\"menuitemcheckbox\",\"menuitemradio\",\"option\",\"radio\",\"separator\\\n\",\"slider\",\"switch\",\"tab\",\"treeitem\"],namingMethods:[\"subtreeText\"]},canvas:{allowedRoles:!0,contentTypes:[\"embedded\",\"phrasing\",\"flow\"],chromiumRole:\"Canvas\"},caption:{allowedRoles:!1},cite:{contentTypes:[\"phrasing\",\"flow\"],allowedRoles:!0},code:{contentTypes:[\"phrasing\",\"flow\"],allowedRoles:!0},col:{allowedRoles:!1,noAriaAttrs:!0},colgroup:{allowedRoles:!1,noAriaAttrs:!0},data:{contentTypes:[\"phrasing\",\"flow\"],allowedRoles:!0},datalist:{contentTypes:[\"phrasing\",\"flow\"],allowedRoles:!1,noAriaAttrs:!0,implicitAttrs:{\"aria-multiselectable\":\"false\"}},dd:{allowedRoles:!1},del:{contentTypes:[\"phrasing\",\"flow\"],allowedRoles:!0},dfn:{contentTypes:[\"phrasing\",\"flow\"],allowedRoles:!0},details:{contentTypes:[\"interactive\",\"flow\"],allowedRoles:!1},dialog:{contentTypes:[\"flow\"],allowedRoles:[\"alertdialog\"]},div:{contentTypes:[\"flow\"],allowedRoles:!0,shadowRoot:!0},dl:{contentTypes:[\"flow\"],allowedRoles:[\"group\",\"list\",\"presentation\",\"none\"],chromiumRole:\"DescriptionList\"},dt:{allowedRoles:[\"listi\\\ntem\"]},em:{contentTypes:[\"phrasing\",\"flow\"],allowedRoles:!0},embed:{contentTypes:[\"interactive\",\"embedded\",\"phrasing\",\"flow\"],allowedRoles:[\"application\",\"document\",\"img\",\"presentation\",\"none\"],chromiumRole:\"EmbeddedObject\"},fieldset:{contentTypes:[\"flow\"],allowedRoles:[\"none\",\"presentation\",\"radiogroup\"],namingMethods:[\"fieldsetLegendText\"]},figcaption:{allowedRoles:[\"group\",\"none\",\"presentation\"]},figure:{contentTypes:[\"flow\"],allowedRoles:!0,namingMethods:[\"figureText\",\"titleText\"]},footer:{contentTypes:[\"flow\"],allowedRoles:[\"group\",\"none\",\"presentation\",\"doc-footnote\"],shadowRoot:!0},form:{contentTypes:[\"flow\"],allowedRoles:[\"form\",\"search\",\"none\",\"presentation\"]},h1:{contentTypes:[\"heading\",\"flow\"],allowedRoles:[\"none\",\"presentation\",\"tab\",\"doc-subtitle\"],shadowRoot:!0,implicitAttrs:{\"aria-level\":\"1\"}},h2:{contentTypes:[\"heading\",\"flow\"],allowedRoles:[\"none\",\"presentation\",\"tab\",\"doc-subtitle\"],shadowRoot:!0,implicitAttrs:{\"aria-level\":\"2\"}},h3:{contentTypes:[\"heading\",\"flow\"],al\\\nlowedRoles:[\"none\",\"presentation\",\"tab\",\"doc-subtitle\"],shadowRoot:!0,implicitAttrs:{\"aria-level\":\"3\"}},h4:{contentTypes:[\"heading\",\"flow\"],allowedRoles:[\"none\",\"presentation\",\"tab\",\"doc-subtitle\"],shadowRoot:!0,implicitAttrs:{\"aria-level\":\"4\"}},h5:{contentTypes:[\"heading\",\"flow\"],allowedRoles:[\"none\",\"presentation\",\"tab\",\"doc-subtitle\"],shadowRoot:!0,implicitAttrs:{\"aria-level\":\"5\"}},h6:{contentTypes:[\"heading\",\"flow\"],allowedRoles:[\"none\",\"presentation\",\"tab\",\"doc-subtitle\"],shadowRoot:!0,implicitAttrs:{\"aria-level\":\"6\"}},head:{allowedRoles:!1,noAriaAttrs:!0},header:{contentTypes:[\"flow\"],allowedRoles:[\"group\",\"none\",\"presentation\",\"doc-footnote\"],shadowRoot:!0},hgroup:{contentTypes:[\"heading\",\"flow\"],allowedRoles:!0},hr:{contentTypes:[\"flow\"],allowedRoles:[\"none\",\"presentation\",\"doc-pagebreak\"],namingMethods:[\"titleText\",\"singleSpace\"]},html:{allowedRoles:!1,noAriaAttrs:!0},i:{contentTypes:[\"phrasing\",\"flow\"],allowedRoles:!0},iframe:{contentTypes:[\"interactive\",\"embedded\",\"phrasing\"\\\n,\"flow\"],allowedRoles:[\"application\",\"document\",\"img\",\"none\",\"presentation\"],chromiumRole:\"Iframe\"},img:{variant:{nonEmptyAlt:{matches:[{attributes:{alt:\"/.+/\"}},{hasAccessibleName:!0}],allowedRoles:[\"button\",\"checkbox\",\"link\",\"math\",\"menuitem\",\"menuitemcheckbox\",\"menuitemradio\",\"meter\",\"option\",\"progressbar\",\"radio\",\"scrollbar\",\"separator\",\"slider\",\"switch\",\"tab\",\"treeitem\",\"doc-cover\"]},usemap:{matches:\"[usemap]\",contentTypes:[\"interactive\",\"embedded\",\"flow\"]},default:{allowedRoles:[\"presentation\",\"none\"],contentTypes:[\"embedded\",\"flow\"]}},namingMethods:[\"altText\"]},input:{variant:{button:{matches:{properties:{type:\"button\"}},allowedRoles:[\"checkbox\",\"combobox\",\"link\",\"menuitem\",\"menuitemcheckbox\",\"menuitemradio\",\"option\",\"radio\",\"switch\",\"tab\"]},buttonType:{matches:{properties:{type:[\"button\",\"submit\",\"reset\"]}},namingMethods:[\"valueText\",\"titleText\",\"buttonDefaultText\"]},checkboxPressed:{matches:{properties:{type:\"checkbox\"},attributes:{\"aria-pressed\":\"/.*/\"}},allowedRoles:[\"button\\\n\",\"menuitemcheckbox\",\"option\",\"switch\"],implicitAttrs:{\"aria-checked\":\"false\"}},checkbox:{matches:{properties:{type:\"checkbox\"},attributes:{\"aria-pressed\":null}},allowedRoles:[\"menuitemcheckbox\",\"option\",\"switch\"],implicitAttrs:{\"aria-checked\":\"false\"}},noRoles:{matches:{properties:{type:[\"color\",\"date\",\"datetime-local\",\"file\",\"month\",\"number\",\"password\",\"range\",\"reset\",\"submit\",\"time\",\"week\"]}},allowedRoles:!1},hidden:{matches:{properties:{type:\"hidden\"}},contentTypes:[\"flow\"],allowedRoles:!1,noAriaAttrs:!0},image:{matches:{properties:{type:\"image\"}},allowedRoles:[\"link\",\"menuitem\",\"menuitemcheckbox\",\"menuitemradio\",\"radio\",\"switch\"],namingMethods:[\"altText\",\"valueText\",\"labelText\",\"titleText\",\"buttonDefaultText\"]},radio:{matches:{properties:{type:\"radio\"}},allowedRoles:[\"menuitemradio\"],implicitAttrs:{\"aria-checked\":\"false\"}},textWithList:{matches:{properties:{type:\"text\"},attributes:{list:\"/.*/\"}},allowedRoles:!1},default:{contentTypes:[\"interactive\",\"flow\"],allowedRoles:[\"combobox\"\\\n,\"searchbox\",\"spinbutton\"],implicitAttrs:{\"aria-valuenow\":\"\"},namingMethods:[\"labelText\",\"placeholderText\"]}}},ins:{contentTypes:[\"phrasing\",\"flow\"],allowedRoles:!0},kbd:{contentTypes:[\"phrasing\",\"flow\"],allowedRoles:!0},label:{contentTypes:[\"interactive\",\"phrasing\",\"flow\"],allowedRoles:!1,chromiumRole:\"Label\"},legend:{allowedRoles:!1},li:{allowedRoles:[\"menuitem\",\"menuitemcheckbox\",\"menuitemradio\",\"option\",\"none\",\"presentation\",\"radio\",\"separator\",\"tab\",\"treeitem\",\"doc-biblioentry\",\"doc-endnote\"],implicitAttrs:{\"aria-setsize\":\"1\",\"aria-posinset\":\"1\"}},link:{contentTypes:[\"phrasing\",\"flow\"],allowedRoles:!1,noAriaAttrs:!0},main:{contentTypes:[\"flow\"],allowedRoles:!1,shadowRoot:!0},map:{contentTypes:[\"phrasing\",\"flow\"],allowedRoles:!1,noAriaAttrs:!0},math:{contentTypes:[\"embedded\",\"phrasing\",\"flow\"],allowedRoles:!1},mark:{contentTypes:[\"phrasing\",\"flow\"],allowedRoles:!0},menu:{contentTypes:[\"flow\"],allowedRoles:[\"directory\",\"group\",\"listbox\",\"menu\",\"menubar\",\"none\",\"presentation\",\"radiog\\\nroup\",\"tablist\",\"toolbar\",\"tree\"]},meta:{variant:{itemprop:{matches:\"[itemprop]\",contentTypes:[\"phrasing\",\"flow\"]}},allowedRoles:!1,noAriaAttrs:!0},meter:{contentTypes:[\"phrasing\",\"flow\"],allowedRoles:!1,chromiumRole:\"progressbar\"},nav:{contentTypes:[\"sectioning\",\"flow\"],allowedRoles:[\"doc-index\",\"doc-pagelist\",\"doc-toc\",\"menu\",\"menubar\",\"none\",\"presentation\",\"tablist\"],shadowRoot:!0},noscript:{contentTypes:[\"phrasing\",\"flow\"],allowedRoles:!1,noAriaAttrs:!0},object:{variant:{usemap:{matches:\"[usemap]\",contentTypes:[\"interactive\",\"embedded\",\"phrasing\",\"flow\"]},default:{contentTypes:[\"embedded\",\"phrasing\",\"flow\"]}},allowedRoles:[\"application\",\"document\",\"img\"],chromiumRole:\"PluginObject\"},ol:{contentTypes:[\"flow\"],allowedRoles:[\"directory\",\"group\",\"listbox\",\"menu\",\"menubar\",\"none\",\"presentation\",\"radiogroup\",\"tablist\",\"toolbar\",\"tree\"]},optgroup:{allowedRoles:!1},option:{allowedRoles:!1,implicitAttrs:{\"aria-selected\":\"false\"}},output:{contentTypes:[\"phrasing\",\"flow\"],allowedRoles:!0,nami\\\nngMethods:[\"subtreeText\"]},p:{contentTypes:[\"flow\"],allowedRoles:!0,shadowRoot:!0},param:{allowedRoles:!1,noAriaAttrs:!0},picture:{contentTypes:[\"phrasing\",\"flow\"],allowedRoles:!1,noAriaAttrs:!0},pre:{contentTypes:[\"flow\"],allowedRoles:!0},progress:{contentTypes:[\"phrasing\",\"flow\"],allowedRoles:!1,implicitAttrs:{\"aria-valuemax\":\"100\",\"aria-valuemin\":\"0\",\"aria-valuenow\":\"0\"}},q:{contentTypes:[\"phrasing\",\"flow\"],allowedRoles:!0},rp:{allowedRoles:!0},rt:{allowedRoles:!0},ruby:{contentTypes:[\"phrasing\",\"flow\"],allowedRoles:!0},s:{contentTypes:[\"phrasing\",\"flow\"],allowedRoles:!0},samp:{contentTypes:[\"phrasing\",\"flow\"],allowedRoles:!0},script:{contentTypes:[\"phrasing\",\"flow\"],allowedRoles:!1,noAriaAttrs:!0},search:{contentTypes:[\"flow\"],allowedRoles:[\"form\",\"group\",\"none\",\"presentation\",\"region\",\"search\"]},section:{contentTypes:[\"sectioning\",\"flow\"],allowedRoles:[\"alert\",\"alertdialog\",\"application\",\"banner\",\"complementary\",\"contentinfo\",\"dialog\",\"document\",\"feed\",\"group\",\"log\",\"main\",\"marque\\\ne\",\"navigation\",\"none\",\"note\",\"presentation\",\"search\",\"status\",\"tabpanel\",\"doc-abstract\",\"doc-acknowledgments\",\"doc-afterword\",\"doc-appendix\",\"doc-bibliography\",\"doc-chapter\",\"doc-colophon\",\"doc-conclusion\",\"doc-credit\",\"doc-credits\",\"doc-dedication\",\"doc-endnotes\",\"doc-epigraph\",\"doc-epilogue\",\"doc-errata\",\"doc-example\",\"doc-foreword\",\"doc-glossary\",\"doc-index\",\"doc-introduction\",\"doc-notice\",\"doc-pagelist\",\"doc-part\",\"doc-preface\",\"doc-prologue\",\"doc-pullquote\",\"doc-qna\",\"doc-toc\"],shadowRoot:!0},select:{variant:{combobox:{matches:{attributes:{multiple:null,size:[null,\"1\"]}},allowedRoles:[\"menu\"]},default:{allowedRoles:!1}},contentTypes:[\"interactive\",\"phrasing\",\"flow\"],implicitAttrs:{\"aria-valuenow\":\"\"},namingMethods:[\"labelText\"]},slot:{contentTypes:[\"phrasing\",\"flow\"],allowedRoles:!1,noAriaAttrs:!0},small:{contentTypes:[\"phrasing\",\"flow\"],allowedRoles:!0},source:{allowedRoles:!1,noAriaAttrs:!0},span:{contentTypes:[\"phrasing\",\"flow\"],allowedRoles:!0,shadowRoot:!0},strong:{contentTy\\\npes:[\"phrasing\",\"flow\"],allowedRoles:!0},style:{allowedRoles:!1,noAriaAttrs:!0},svg:{contentTypes:[\"embedded\",\"phrasing\",\"flow\"],allowedRoles:!0,chromiumRole:\"SVGRoot\",namingMethods:[\"svgTitleText\"]},sub:{contentTypes:[\"phrasing\",\"flow\"],allowedRoles:!0},summary:{allowedRoles:!1,namingMethods:[\"subtreeText\"]},sup:{contentTypes:[\"phrasing\",\"flow\"],allowedRoles:!0},table:{contentTypes:[\"flow\"],allowedRoles:!0,namingMethods:[\"tableCaptionText\",\"tableSummaryText\"]},tbody:{allowedRoles:!0},template:{contentTypes:[\"phrasing\",\"flow\"],allowedRoles:!1,noAriaAttrs:!0},textarea:{contentTypes:[\"interactive\",\"phrasing\",\"flow\"],allowedRoles:!1,implicitAttrs:{\"aria-valuenow\":\"\",\"aria-multiline\":\"true\"},namingMethods:[\"labelText\",\"placeholderText\"]},tfoot:{allowedRoles:!0},thead:{allowedRoles:!0},time:{contentTypes:[\"phrasing\",\"flow\"],allowedRoles:!0},title:{allowedRoles:!1,noAriaAttrs:!0},td:{allowedRoles:!0},th:{allowedRoles:!0},tr:{allowedRoles:!0},track:{allowedRoles:!1,noAriaAttrs:!0},u:{contentT\\\nypes:[\"phrasing\",\"flow\"],allowedRoles:!0},ul:{contentTypes:[\"flow\"],allowedRoles:[\"directory\",\"group\",\"listbox\",\"menu\",\"menubar\",\"none\",\"presentation\",\"radiogroup\",\"tablist\",\"toolbar\",\"tree\"]},var:{contentTypes:[\"phrasing\",\"flow\"],allowedRoles:!0},video:{variant:{controls:{matches:\"[controls]\",contentTypes:[\"interactive\",\"embedded\",\"phrasing\",\"flow\"]},default:{contentTypes:[\"embedded\",\"phrasing\",\"flow\"]}},allowedRoles:[\"application\"],chromiumRole:\"video\"},wbr:{contentTypes:[\"phrasing\",\"flow\"],allowedRoles:[\"presentation\",\"none\"]}},ye={aliceblue:[240,248,255],antiquewhite:[250,235,215],aqua:[0,255,255],aquamarine:[127,255,212],azure:[240,255,255],beige:[245,245,220],bisque:[255,228,196],black:[0,0,0],blanchedalmond:[255,235,205],blue:[0,0,255],blueviolet:[138,43,226],brown:[165,42,42],burlywood:[222,184,135],cadetblue:[95,158,160],chartreuse:[127,255,0],chocolate:[210,105,30],coral:[255,127,80],cornflowerblue:[100,149,237],cornsilk:[255,248,220],crimson:[220,20,60],cyan:[0,255,255],dark\\\nblue:[0,0,139],darkcyan:[0,139,139],darkgoldenrod:[184,134,11],darkgray:[169,169,169],darkgreen:[0,100,0],darkgrey:[169,169,169],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkseagreen:[143,188,143],darkslateblue:[72,61,139],darkslategray:[47,79,79],darkslategrey:[47,79,79],darkturquoise:[0,206,209],darkviolet:[148,0,211],deeppink:[255,20,147],deepskyblue:[0,191,255],dimgray:[105,105,105],dimgrey:[105,105,105],dodgerblue:[30,144,255],firebrick:[178,34,34],floralwhite:[255,250,240],forestgreen:[34,139,34],fuchsia:[255,0,255],gainsboro:[220,220,220],ghostwhite:[248,248,255],gold:[255,215,0],goldenrod:[218,165,32],gray:[128,128,128],green:[0,128,0],greenyellow:[173,255,47],grey:[128,128,128],honeydew:[240,255,240],hotpink:[255,105,180],indianred:[205,92,92],indigo:[75,0,130],ivory:[255,255,240],khaki:[240,230,140],lavender:[230,230,250],lavenderblush:[255,240,245],lawn\\\ngreen:[124,252,0],lemonchiffon:[255,250,205],lightblue:[173,216,230],lightcoral:[240,128,128],lightcyan:[224,255,255],lightgoldenrodyellow:[250,250,210],lightgray:[211,211,211],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightsalmon:[255,160,122],lightseagreen:[32,178,170],lightskyblue:[135,206,250],lightslategray:[119,136,153],lightslategrey:[119,136,153],lightsteelblue:[176,196,222],lightyellow:[255,255,224],lime:[0,255,0],limegreen:[50,205,50],linen:[250,240,230],magenta:[255,0,255],maroon:[128,0,0],mediumaquamarine:[102,205,170],mediumblue:[0,0,205],mediumorchid:[186,85,211],mediumpurple:[147,112,219],mediumseagreen:[60,179,113],mediumslateblue:[123,104,238],mediumspringgreen:[0,250,154],mediumturquoise:[72,209,204],mediumvioletred:[199,21,133],midnightblue:[25,25,112],mintcream:[245,255,250],mistyrose:[255,228,225],moccasin:[255,228,181],navajowhite:[255,222,173],navy:[0,0,128],oldlace:[253,245,230],olive:[128,128,0],olivedrab:[107,142,35],orange:[255,\\\n165,0],orangered:[255,69,0],orchid:[218,112,214],palegoldenrod:[238,232,170],palegreen:[152,251,152],paleturquoise:[175,238,238],palevioletred:[219,112,147],papayawhip:[255,239,213],peachpuff:[255,218,185],peru:[205,133,63],pink:[255,192,203],plum:[221,160,221],powderblue:[176,224,230],purple:[128,0,128],rebeccapurple:[102,51,153],red:[255,0,0],rosybrown:[188,143,143],royalblue:[65,105,225],saddlebrown:[139,69,19],salmon:[250,128,114],sandybrown:[244,164,96],seagreen:[46,139,87],seashell:[255,245,238],sienna:[160,82,45],silver:[192,192,192],skyblue:[135,206,235],slateblue:[106,90,205],slategray:[112,128,144],slategrey:[112,128,144],snow:[255,250,250],springgreen:[0,255,127],steelblue:[70,130,180],tan:[210,180,140],teal:[0,128,128],thistle:[216,191,216],tomato:[255,99,71],turquoise:[64,224,208],violet:[238,130,238],wheat:[245,222,179],white:[255,255,255],whitesmoke:[245,245,245],yellow:[255,255,0],yellowgreen:[154,205,50]},{ariaAttrs:ps,ariaRoles:O({},fs,{\"doc-abstract\":{type:\"section\",\\\nallowedAttrs:[\"aria-expanded\"],superclassRole:[\"section\"]},\"doc-acknowledgments\":{type:\"landmark\",allowedAttrs:[\"aria-expanded\"],superclassRole:[\"landmark\"]},\"doc-afterword\":{type:\"landmark\",allowedAttrs:[\"aria-expanded\"],superclassRole:[\"landmark\"]},\"doc-appendix\":{type:\"landmark\",allowedAttrs:[\"aria-expanded\"],superclassRole:[\"landmark\"]},\"doc-backlink\":{type:\"link\",allowedAttrs:[\"aria-expanded\"],nameFromContent:!0,superclassRole:[\"link\"]},\"doc-biblioentry\":{type:\"listitem\",allowedAttrs:[\"aria-expanded\",\"aria-level\",\"aria-posinset\",\"aria-setsize\"],superclassRole:[\"listitem\"],deprecated:!0},\"doc-bibliography\":{type:\"landmark\",allowedAttrs:[\"aria-expanded\"],superclassRole:[\"landmark\"]},\"doc-biblioref\":{type:\"link\",allowedAttrs:[\"aria-expanded\"],nameFromContent:!0,superclassRole:[\"link\"]},\"doc-chapter\":{type:\"landmark\",allowedAttrs:[\"aria-expanded\"],superclassRole:[\"landmark\"]},\"doc-colophon\":{type:\"section\",allowedAttrs:[\"aria-expanded\"],superclassRole:[\"section\"]},\"doc-conclusion\":{ty\\\npe:\"landmark\",allowedAttrs:[\"aria-expanded\"],superclassRole:[\"landmark\"]},\"doc-cover\":{type:\"img\",allowedAttrs:[\"aria-expanded\"],superclassRole:[\"img\"]},\"doc-credit\":{type:\"section\",allowedAttrs:[\"aria-expanded\"],superclassRole:[\"section\"]},\"doc-credits\":{type:\"landmark\",allowedAttrs:[\"aria-expanded\"],superclassRole:[\"landmark\"]},\"doc-dedication\":{type:\"section\",allowedAttrs:[\"aria-expanded\"],superclassRole:[\"section\"]},\"doc-endnote\":{type:\"listitem\",allowedAttrs:[\"aria-expanded\",\"aria-level\",\"aria-posinset\",\"aria-setsize\"],superclassRole:[\"listitem\"],deprecated:!0},\"doc-endnotes\":{type:\"landmark\",allowedAttrs:[\"aria-expanded\"],superclassRole:[\"landmark\"]},\"doc-epigraph\":{type:\"section\",allowedAttrs:[\"aria-expanded\"],superclassRole:[\"section\"]},\"doc-epilogue\":{type:\"landmark\",allowedAttrs:[\"aria-expanded\"],superclassRole:[\"landmark\"]},\"doc-errata\":{type:\"landmark\",allowedAttrs:[\"aria-expanded\"],superclassRole:[\"landmark\"]},\"doc-example\":{type:\"section\",allowedAttrs:[\"aria-expanded\"],su\\\nperclassRole:[\"section\"]},\"doc-footnote\":{type:\"section\",allowedAttrs:[\"aria-expanded\"],superclassRole:[\"section\"]},\"doc-foreword\":{type:\"landmark\",allowedAttrs:[\"aria-expanded\"],superclassRole:[\"landmark\"]},\"doc-glossary\":{type:\"landmark\",allowedAttrs:[\"aria-expanded\"],superclassRole:[\"landmark\"]},\"doc-glossref\":{type:\"link\",allowedAttrs:[\"aria-expanded\"],nameFromContent:!0,superclassRole:[\"link\"]},\"doc-index\":{type:\"navigation\",allowedAttrs:[\"aria-expanded\"],superclassRole:[\"navigation\"]},\"doc-introduction\":{type:\"landmark\",allowedAttrs:[\"aria-expanded\"],superclassRole:[\"landmark\"]},\"doc-noteref\":{type:\"link\",allowedAttrs:[\"aria-expanded\"],nameFromContent:!0,superclassRole:[\"link\"]},\"doc-notice\":{type:\"note\",allowedAttrs:[\"aria-expanded\"],superclassRole:[\"note\"]},\"doc-pagebreak\":{type:\"separator\",allowedAttrs:[\"aria-expanded\",\"aria-orientation\"],superclassRole:[\"separator\"],childrenPresentational:!0},\"doc-pagelist\":{type:\"navigation\",allowedAttrs:[\"aria-expanded\"],superclassRole:[\"na\\\nvigation\"]},\"doc-part\":{type:\"landmark\",allowedAttrs:[\"aria-expanded\"],superclassRole:[\"landmark\"]},\"doc-preface\":{type:\"landmark\",allowedAttrs:[\"aria-expanded\"],superclassRole:[\"landmark\"]},\"doc-prologue\":{type:\"landmark\",allowedAttrs:[\"aria-expanded\"],superclassRole:[\"landmark\"]},\"doc-pullquote\":{type:\"none\",superclassRole:[\"none\"]},\"doc-qna\":{type:\"section\",allowedAttrs:[\"aria-expanded\"],superclassRole:[\"section\"]},\"doc-subtitle\":{type:\"sectionhead\",allowedAttrs:[\"aria-expanded\"],superclassRole:[\"sectionhead\"]},\"doc-tip\":{type:\"note\",allowedAttrs:[\"aria-expanded\"],superclassRole:[\"note\"]},\"doc-toc\":{type:\"navigation\",allowedAttrs:[\"aria-expanded\"],superclassRole:[\"navigation\"]}},{\"graphics-document\":{type:\"structure\",superclassRole:[\"document\"],accessibleNameRequired:!0},\"graphics-object\":{type:\"structure\",superclassRole:[\"group\"],nameFromContent:!0},\"graphics-symbol\":{type:\"structure\",superclassRole:[\"img\"],accessibleNameRequired:!0,childrenPresentational:!0}}),htmlElms:el,cssColor\\\ns:ye}),hs=O({},ms),gs=hs,vs=function(e){return!!(e=gs.ariaRoles[e])&&!!e.unsupported},bs=function(e){var t=(n=1<arguments.length&&void 0!==arguments[1]?arguments[1]:{}).allowAbstract,n=void 0!==(n=n.flagUnsupported)&&n,r=gs.ariaRoles[e];e=vs(e);return!(!r||n&&e||!t&&\"abstract\"===r.type)},ys=function(e){var t=1<arguments.length&&void 0!==arguments[1]?arguments[1]:{},n=t.fallback,r=t.abstracts,a=t.dpub;return 1===(e=e instanceof ua?e:_l(e)).props.nodeType&&(t=(e.attr(\"role\")||\"\").trim().toLowerCase(),(n?Yp(t):[t]).find((function(e){return!(!a&&\"doc-\"===e.substr(0,4))&&bs(e,{allowAbstract:r})})))||null},Ds=function(e){return Object.keys(gs.htmlElms).filter((function(t){return(t=gs.htmlElms[t]).contentTypes?t.contentTypes.includes(e):!!t.variant&&!(!t.variant.default||!t.variant.default.contentTypes)&&t.variant.default.contentTypes.includes(e)}))},ws=function(){return Sl.get(\"globalAriaAttrs\",(function(){return Object.keys(gs.ariaAttrs).filter((function(e){return gs.ariaAttrs[e].global}))}\\\n))},xs=cl((function(e){for(var t=[],n=e.rows,r=0,a=n.length;r<a;r++)for(var o=n[r].cells,i=(t[r]=t[r]||[],0),l=0,u=o.length;l<u;l++)for(var s=0;s<o[l].colSpan;s++){for(var c=o[l].getAttribute(\"rowspan\"),d=0===parseInt(c)||0===o[l].rowspan?n.length:o[l].rowSpan,p=0;p<d;p++){for(t[r+p]=t[r+p]||[];t[r+p][i];)i++;t[r+p][i]=o[l]}i++}return t})),Es=cl((function(e,t){var n,r;for(t=t||xs(jl(e,\"table\")),n=0;n<t.length;n++)if(t[n]&&-1!==(r=t[n].indexOf(e)))return{x:r,y:n}}));function As(e){var t,n=(e=Hf(e)).vNode,r=(e=e.domNode,n.attr(\"scope\")),a=ys(n);if([\"td\",\"th\"].includes(n.props.nodeName))return\"columnheader\"===a?\"col\":\"rowheader\"===a?\"row\":\"col\"===r||\"row\"===r?r:\"th\"===n.props.nodeName&&(n.actualNode?(a=xs(jl(e,\"table\")))[(t=Es(e,a)).y].every((function(e){return\"TH\"===e.nodeName.toUpperCase()}))?\"col\":a.map((function(e){return e[t.x]})).every((function(e){return e&&\"TH\"===e.nodeName.toUpperCase()}))?\"row\":\"auto\":\"auto\");throw new TypeError(\"Expected TD or TH element\")}var Fs=function(e){re\\\nturn-1!==[\"col\",\"auto\"].indexOf(As(e))},Cs=function(e){return[\"row\",\"auto\"].includes(As(e))};function ks(){return Sl.get(\"sectioningContentSelector\",(function(){return Ds(\"sectioning\").map((function(e){return\"\".concat(e,\":not([role])\")})).join(\", \")+\" , [role=article], [role=complementary], [role=navigation], [role=region]\"}))}function Rs(){return Sl.get(\"sectioningContentPlusMainSelector\",(function(){return ks()+\" , main:not([role]), [role=main]\"}))}var Ns=function(e){return e?e.replace(/\\\\r\\\\n/g,\"\\\\n\").replace(/\\\\u00A0/g,\" \").replace(/[\\\\s]{2,}/g,\" \").trim():\"\"};function Ts(e,t){return t=void 0!==(t=(1<arguments.length&&void 0!==t?t:{}).checkTitle)&&t,Ns(cs(e))||Ns(ds(e))||t&&1===(null==e?void 0:e.props.nodeType)&&Ns(e.attr(\"title\"))}var Ss={a:function(e){return e.hasAttr(\"href\")?\"link\":null},area:function(e){return e.hasAttr(\"href\")?\"link\":null},article:\"article\",aside:function(e){return Wd(e.parent,ks())&&!Ts(e,{checkTitle:!0})?null:\"complementary\"},body:\"document\",button:\"button\",datal\\\nist:\"listbox\",dd:\"definition\",dfn:\"term\",details:\"group\",dialog:\"dialog\",dt:\"term\",fieldset:\"group\",figure:\"figure\",footer:function(e){return Wd(e,Rs())?null:\"contentinfo\"},form:function(e){return Ts(e)?\"form\":null},h1:\"heading\",h2:\"heading\",h3:\"heading\",h4:\"heading\",h5:\"heading\",h6:\"heading\",header:function(e){return Wd(e,Rs())?null:\"banner\"},hr:\"separator\",img:function(e){var t=e.hasAttr(\"alt\")&&!e.attr(\"alt\"),n=ws().find((function(t){return e.hasAttr(t)}));return!t||n||rs(e)?\"img\":\"presentation\"},input:function(e){var t,n;switch(e.hasAttr(\"list\")&&(n=(t=us(e.actualNode,\"list\").filter((function(e){return!!e}))[0])&&\"datalist\"===t.nodeName.toLowerCase()),e.props.type){case\"checkbox\":return\"checkbox\";case\"number\":return\"spinbutton\";case\"radio\":return\"radio\";case\"range\":return\"slider\";case\"search\":return n?\"combobox\":\"searchbox\";case\"button\":case\"image\":case\"reset\":case\"submit\":return\"button\";case\"text\":case\"tel\":case\"url\":case\"email\":case\"\":return n?\"combobox\":\"textbox\";default:return\"\\\ntextbox\"}},li:\"listitem\",main:\"main\",math:\"math\",menu:\"list\",meter:\"meter\",nav:\"navigation\",ol:\"list\",optgroup:\"group\",option:\"option\",output:\"status\",progress:\"progressbar\",search:\"search\",section:function(e){return Ts(e)?\"region\":null},select:function(e){return e.hasAttr(\"multiple\")||1<parseInt(e.attr(\"size\"))?\"listbox\":\"combobox\"},summary:\"button\",table:\"table\",tbody:\"rowgroup\",td:function(e){return e=Wd(e,\"table\"),e=ys(e),[\"grid\",\"treegrid\"].includes(e)?\"gridcell\":\"cell\"},textarea:\"textbox\",tfoot:\"rowgroup\",th:function(e){return Fs(e)?\"columnheader\":Cs(e)?\"rowheader\":void 0},thead:\"rowgroup\",tr:\"row\",ul:\"list\"},_s=function(e,t){var n=a(t);if(Array.isArray(t)&&void 0!==e)return t.includes(e);if(\"function\"===n)return!!t(e);if(null!=e){if(t instanceof RegExp)return t.test(e);if(/^\\\\/.*\\\\/$/.test(t))return n=t.substring(1,t.length-1),new RegExp(n).test(e)}return t===e};function Os(e,t){return _s(!!kc(e),t)}var Ms=function(e,t){if(\"object\"!==a(t)||Array.isArray(t)||t instanceof RegExp)thr\\\now new Error(\"Expect matcher to be an object\");return Object.keys(t).every((function(n){return _s(e(n),t[n])}))};function Ps(e,t){return e=Hf(e).vNode,Ms((function(t){return e.attr(t)}),t)}function Is(e,t){return!!t(e)}function Bs(e,t){return _s(ys(e),t)}function js(e,t){return _s(Ws(e),t)}function Ls(e,t){return e=Hf(e).vNode,_s(e.props.nodeName,t)}function qs(e,t){return e=Hf(e).vNode,Ms((function(t){return e.props[t]}),t)}function zs(e,t){return _s(Xs(e),t)}var Vs={hasAccessibleName:Os,attributes:Ps,condition:Is,explicitRole:Bs,implicitRole:js,nodeName:Ls,properties:qs,semanticRole:zs},Gs=function e(t,n){return t=Hf(t).vNode,Array.isArray(n)?n.some((function(n){return e(t,n)})):\"string\"==typeof n?Ld(t,n):Object.keys(n).every((function(e){var r;if(Vs[e])return r=n[e],(0,Vs[e])(t,r);throw new Error('Unknown matcher type \"'.concat(e,'\"'))}))},$s=function(e,t){return Gs(e,t)},Hs=($s.hasAccessibleName=Os,$s.attributes=Ps,$s.condition=Is,$s.explicitRole=Bs,$s.fromDefinition=Gs,$s.fromFunc\\\ntion=Ms,$s.fromPrimative=_s,$s.implicitRole=js,$s.nodeName=Ls,$s.properties=qs,$s.semanticRole=zs,$s),Us=function(e){var t=(1<arguments.length&&void 0!==arguments[1]?arguments[1]:{}).noMatchAccessibleName,n=void 0!==t&&t,r=gs.htmlElms[e.props.nodeName];if(!r)return{};if(!r.variant)return r;var a,o,i=r.variant,l=k(r,d);for(a in i)if(i.hasOwnProperty(a)&&\"default\"!==a){for(var u=i[a],s=u.matches,c=k(u,p),f=Array.isArray(s)?s:[s],m=0;m<f.length&&n;m++)if(f[m].hasOwnProperty(\"hasAccessibleName\"))return r;if(Hs(e,s))for(var h in c)c.hasOwnProperty(h)&&(l[h]=c[h])}for(o in i.default)i.default.hasOwnProperty(o)&&void 0===l[o]&&(l[o]=i.default[o]);return l},Ws=function(e){var t=(1<arguments.length&&void 0!==arguments[1]?arguments[1]:{}).chromium,n=e instanceof ua?e:_l(e);if(e=n.actualNode,n)return e=n.props.nodeName,!(e=Ss[e])&&t?Us(n).chromiumRole||null:\"function\"==typeof e?e(n):e||null;throw new ReferenceError(\"Cannot get implicit role of a node outside the current scope.\")},Ys={td:[\"tr\"],th\\\n:[\"tr\"],tr:[\"thead\",\"tbody\",\"tfoot\",\"table\"],thead:[\"table\"],tbody:[\"table\"],tfoot:[\"table\"],li:[\"ol\",\"ul\"],dt:[\"dl\",\"div\"],dd:[\"dl\",\"div\"],div:[\"dl\"]};function Ks(e){return ws().some((function(t){return e.hasAttr(t)}))||rs(e)}var Xs=function(e){var t=1<arguments.length&&void 0!==arguments[1]?arguments[1]:{},n=t.noPresentational;e=function(e,t){var n,r=(t=1<arguments.length&&void 0!==t?t:{}).noImplicit;t=k(t,m);return 1!==(e=Hf(e).vNode).props.nodeType?null:!(n=ys(e,t))||[\"presentation\",\"none\"].includes(n)&&Ks(e)?r?null:function(e,t){var n=t.chromium;return t=k(t,f),(n=Ws(e,{chromium:n}))?function e(t,n){var r=Ys[t.props.nodeName];if(r){if(t.parent)return r.includes(t.parent.props.nodeName)?(r=ys(t.parent,n),[\"none\",\"presentation\"].includes(r)&&!Ks(t.parent)?r:r?null:e(t.parent,n)):null;if(t.actualNode)throw new ReferenceError(\"Cannot determine role presentational inheritance of a required parent outside the current scope.\")}return null}(e,t)||n:null}(e,t):n}(e,k(t,h));return n&&[\"pres\\\nentation\",\"none\"].includes(e)?null:e},Zs=[\"iframe\"],Js=function(e){var t=Hf(e).vNode;return 1!==t.props.nodeType||!e.hasAttr(\"title\")||!$s(t,Zs)&&[\"none\",\"presentation\"].includes(Xs(t))?\"\":t.attr(\"title\")},Qs=function(e){var t,n=(1<arguments.length&&void 0!==arguments[1]?arguments[1]:{}).strict;return 1===(e=e instanceof ua?e:_l(e)).props.nodeType&&(e=Xs(e),!(!(t=gs.ariaRoles[e])||!t.nameFromContent)||!n&&(!t||[\"presentation\",\"none\"].includes(e)))},ec=function(e){var t=e.actualNode,n=e.children;if(n)return e.hasAttr(\"aria-owns\")?(e=us(t,\"aria-owns\").filter((function(e){return!!e})).map((function(e){return o.utils.getNodeFromTree(e)})),[].concat(M(n),M(e))):M(n);throw new Error(\"getOwnedVirtual requires a virtual node\")},tc={accessibleNameFromFieldValue:[\"progressbar\"]};function nc(e){return e=Hf(e).vNode,rc(e)}var rc=cl((function(e,t){return!Yl(e)&&!Vu(e,{skipAncestors:!0,isAncestor:t})&&(e.actualNode&&\"area\"===e.props.nodeName?!Ql(e,rc):!nu(e,{skipAncestors:!0,isAncestor:t})&&(!e.pare\\\nnt||rc(e.parent,!0)))})),ac=function e(t,n,r){var a=Hf(t).vNode,o=n?nc:du,i=!t.actualNode||(t.actualNode,o(t));o=a.children.map((function(t){var a=(o=t.props).nodeType,o=o.nodeValue;if(3===a){if(o&&i)return o}else if(!r)return e(t,n)})).join(\"\");return Ns(o)},oc=[\"button\",\"checkbox\",\"color\",\"file\",\"hidden\",\"image\",\"password\",\"radio\",\"reset\",\"submit\"],ic=function(e){var t=(e=e instanceof ua?e:_l(e)).props.nodeName;return\"textarea\"===t||\"input\"===t&&!oc.includes((e.attr(\"type\")||\"\").toLowerCase())},lc=function(e){return\"select\"===(e=e instanceof ua?e:_l(e)).props.nodeName},uc=function(e){return\"textbox\"===ys(e)},sc=function(e){return\"listbox\"===ys(e)},cc=function(e){return\"combobox\"===ys(e)},dc=[\"progressbar\",\"scrollbar\",\"slider\",\"spinbutton\"],pc=function(e){return e=ys(e),dc.includes(e)},fc=[\"textbox\",\"progressbar\",\"scrollbar\",\"slider\",\"spinbutton\",\"combobox\",\"listbox\"],mc={nativeTextboxValue:function(e){return e=Hf(e).vNode,ic(e)&&e.props.value||\"\"},nativeSelectValue:function(e){if(e=H\\\nf(e).vNode,!lc(e))return\"\";var t=(e=fm(e,\"option\")).filter((function(e){return e.props.selected}));return t.length||t.push(e[0]),t.map((function(e){return ac(e)})).join(\" \")||\"\"},ariaTextboxValue:function(e){var t=(e=Hf(e)).vNode;e=e.domNode;return uc(t)?e&&nu(e)?e.textContent:ac(t,!0):\"\"},ariaListboxValue:hc,ariaComboboxValue:function(e,t){e=Hf(e).vNode;return cc(e)&&(e=ec(e).filter((function(e){return\"listbox\"===Xs(e)}))[0])?hc(e,t):\"\"},ariaRangeValue:function(e){e=Hf(e).vNode;return pc(e)&&e.hasAttr(\"aria-valuenow\")?(e=+e.attr(\"aria-valuenow\"),isNaN(e)?\"0\":String(e)):\"\"}};function hc(e,t){e=Hf(e).vNode;return sc(e)&&0!==(e=ec(e).filter((function(e){return\"option\"===Xs(e)&&\"true\"===e.attr(\"aria-selected\")}))).length?kc(e[0],t):\"\"}var gc=function(e){var t=1<arguments.length&&void 0!==arguments[1]?arguments[1]:{},n=e.actualNode,r=tc.accessibleNameFromFieldValue||[],a=Xs(e);return t.startNode===e||!fc.includes(a)||r.includes(a)?\"\":(r=Object.keys(mc).map((function(e){return mc[e]})).redu\\\nce((function(n,r){return n||r(e,t)}),\"\"),t.debug&&ia(r||\"{empty-value}\",n,t),r)},vc=Ds(\"phrasing\").concat([\"#text\"]),bc=function(e){var t=1<arguments.length&&void 0!==arguments[1]?arguments[1]:{},n=kc.alreadyProcessed;t.startNode=t.startNode||e;var r=(o=t).strict,a=o.inControlContext,o=o.inLabelledByContext,i=Xs(e),l=Us(e,{noMatchAccessibleName:!0}).contentTypes;return n(e,t)||1!==e.props.nodeType||null!=l&&l.includes(\"embedded\")||fc.includes(i)||!(t.subtreeDescendant||t.inLabelledByContext||Qs(e,{strict:r}))?\"\":(r||(t=O({subtreeDescendant:!a&&!o},t)),ec(e).reduce((function(e,n){var r=t,a=n.props.nodeName;return(n=kc(n,r))?(vc.includes(a)||(\" \"!==n[0]&&(n+=\" \"),e&&\" \"!==e[e.length-1]&&(n=\" \"+n)),e+n):e}),\"\"))},yc=function(e){var t=1<arguments.length&&void 0!==arguments[1]?arguments[1]:{},n=kc.alreadyProcessed;if(t.inControlContext||t.inLabelledByContext||n(e,t))return\"\";t.startNode||(t.startNode=e);var r,a=O({inControlContext:!0},t);n=(e=>{if(!e.attr(\"id\"))return[];if(e.actualNode)retu\\\nrn Il({elm:\"label\",attr:\"for\",value:e.attr(\"id\"),context:e.actualNode});throw new TypeError(\"Cannot resolve explicit label reference for non-DOM nodes\")})(e);return(t=Wd(e,\"label\"))?(r=[].concat(M(n),[t.actualNode])).sort($f):r=n,r.map((function(e){return ss(e,a)})).filter((function(e){return\"\"!==e})).join(\" \")},Dc={submit:\"Submit\",image:\"Submit\",reset:\"Reset\",button:\"\"};function wc(e,t){return t.attr(e)||\"\"}function xc(e,t,n){t=t.actualNode;var r=[e=e.toLowerCase(),t.nodeName.toLowerCase()].join(\",\");return(t=t.querySelector(r))&&t.nodeName.toLowerCase()===e?ss(t,n):\"\"}var Ec={valueText:function(e){return e.props.value||\"\"},buttonDefaultText:function(e){return Dc[e.props.type]||\"\"},tableCaptionText:xc.bind(null,\"caption\"),figureText:xc.bind(null,\"figcaption\"),svgTitleText:xc.bind(null,\"title\"),fieldsetLegendText:xc.bind(null,\"legend\"),altText:wc.bind(null,\"alt\"),tableSummaryText:wc.bind(null,\"summary\"),titleText:Js,subtreeText:bc,labelText:yc,singleSpace:function(){return\" \"},placehol\\\nderText:wc.bind(null,\"placeholder\")};function Ac(e){var t,n=1<arguments.length&&void 0!==arguments[1]?arguments[1]:{},r=e.actualNode;return 1!==e.props.nodeType||[\"presentation\",\"none\"].includes(Xs(e))?\"\":(t=(Us(e,{noMatchAccessibleName:!0}).namingMethods||[]).map((function(e){return Ec[e]})).reduce((function(t,r){return t||r(e,n)}),\"\"),n.debug&&o.log(t||\"{empty-value}\",r,n),t)}var Fc=function(e,t){var n=t.emoji,r=t.nonBmp,a=(t=t.punctuations,!1);return n&&(a=a||Ma().test(e)),r&&(a=a||/[\\\\u1D00-\\\\u1D7F\\\\u1D80-\\\\u1DBF\\\\u1DC0-\\\\u1DFF\\\\u20A0-\\\\u20CF\\\\u20D0-\\\\u20FF\\\\u2100-\\\\u214F\\\\u2150-\\\\u218F\\\\u2190-\\\\u21FF\\\\u2200-\\\\u22FF\\\\u2300-\\\\u23FF\\\\u2400-\\\\u243F\\\\u2440-\\\\u245F\\\\u2460-\\\\u24FF\\\\u2500-\\\\u257F\\\\u2580-\\\\u259F\\\\u25A0-\\\\u25FF\\\\u2600-\\\\u26FF\\\\u2700-\\\\u27BF\\\\uE000-\\\\uF8FF]/g.test(e)||/[\\\\uDB80-\\\\uDBBF][\\\\uDC00-\\\\uDFFF]/g.test(e)||/[\\\\xAD\\\\u0600-\\\\u0605\\\\u061C\\\\u06DD\\\\u070F\\\\u08E2\\\\u180E\\\\u200B-\\\\u200F\\\\u202A-\\\\u202E\\\\u2060-\\\\u2064\\\\u2066-\\\\u206F\\\\uFEFF\\\\uFFF9-\\\\uFFFB]|\\\\uD804[\\\\uDCBD\\\\uDCCD]|\\\\uD80D[\\\\uDC30-\\\\uDC38]|\\\\uD82F[\\\\uDCA0-\\\\uDCA3]|\\\\uD834[\\\\uDD73-\\\\uDD\\\n7A]|\\\\uDB40[\\\\uDC01\\\\uDC20-\\\\uDC7F]/g.test(e)),t?a||/[\\\\u2000-\\\\u206F\\\\u2E00-\\\\u2E7F\\\\\\\\'!\"#$%&\\\\xa3\\\\xa2\\\\xa5\\\\xa7\\\\u20ac()*+,\\\\-.\\\\/:;<=>?@\\\\[\\\\]^_\\`{|}~\\\\xb1]/g.test(e):a};function Cc(e){var n=1<arguments.length&&void 0!==arguments[1]?arguments[1]:.15,a=2<arguments.length&&void 0!==arguments[2]?arguments[2]:3,o=e.actualNode.nodeValue.trim();if(!Ns(o)||Fc(o,{emoji:!0,nonBmp:!0}))return!1;var i,l=Sl.get(\"canvasContext\",(function(){return r.createElement(\"canvas\").getContext(\"2d\",{willReadFrequently:!0})})),u=l.canvas;if((i=((i=Sl.get(\"fonts\",(function(){return{}})))[e=t.getComputedStyle(e.parent.actualNode).getPropertyValue(\"font-family\")]||(i[e]={occurrences:0,numLigatures:0}),i[e])).occurrences>=a){if(i.numLigatures/i.occurrences==1)return!0;if(0===i.numLigatures)return!1}i.occurrences++;var s=\"\".concat(a=30,\"px \").concat(e),c=(l.font=s,o.charAt(0)),d=l.measureText(c).width;if(0===d)return i.numLigatures++,!0;d<30&&(d*=p=30/d,s=\"\".concat(a*=p,\"px \").concat(e)),u.width=d,u.height=a,l.font=s,l.textAlign=\"\\\nleft\",l.textBaseline=\"top\",l.fillText(c,0,0);var p=new Uint32Array(l.getImageData(0,0,d,a).data.buffer);if(!p.some((function(e){return e})))return i.numLigatures++,!0;l.clearRect(0,0,d,a),l.fillText(o,0,0);var f=new Uint32Array(l.getImageData(0,0,d,a).data.buffer);e=p.reduce((function(e,t,n){return 0===t&&0===f[n]||0!==t&&0!==f[n]?e:++e}),0),u=o.split(\"\").reduce((function(e,t){return e+l.measureText(t).width}),0),s=l.measureText(o).width;return n<=e/p.length&&n<=1-s/u&&(i.numLigatures++,!0)}function kc(e){var t,n,r,a,i,l=((e,t)=>(t.startNode||(t=O({startNode:e},t)),1===e.props.nodeType&&t.inLabelledByContext&&void 0===t.includeHidden?O({includeHidden:!nc(e)},t):t))(e,1<arguments.length&&void 0!==arguments[1]?arguments[1]:{});return((e,t)=>e&&1===e.props.nodeType&&!t.includeHidden&&!nc(e))(e,l)||(t=e,n=(i=l).ignoreIconLigature,r=i.pixelThreshold,a=null!=(a=i.occurrenceThreshold)?a:i.occuranceThreshold,3===t.props.nodeType&&n&&Cc(t,r,a))?\"\":(i=[cs,ds,Ac,gc,bc,Rc,Js].reduce((function(t,n)\\\n{return\"\"!==(t=l.startNode===e?Ns(t):t)?t:n(e,l)}),\"\"),l.debug&&o.log(i||\"{empty-value}\",e.actualNode,l),i)}function Rc(e){return 3!==e.props.nodeType?\"\":e.props.nodeValue}kc.alreadyProcessed=function(e,t){return t.processed=t.processed||[],!!t.processed.includes(e)||(t.processed.push(e),!1)};var Nc=function(e,t){var n=t.emoji,r=t.nonBmp;t=t.punctuations;return n&&(e=e.replace(Ma(),\"\")),r&&(e=e.replace(/[\\\\u1D00-\\\\u1D7F\\\\u1D80-\\\\u1DBF\\\\u1DC0-\\\\u1DFF\\\\u20A0-\\\\u20CF\\\\u20D0-\\\\u20FF\\\\u2100-\\\\u214F\\\\u2150-\\\\u218F\\\\u2190-\\\\u21FF\\\\u2200-\\\\u22FF\\\\u2300-\\\\u23FF\\\\u2400-\\\\u243F\\\\u2440-\\\\u245F\\\\u2460-\\\\u24FF\\\\u2500-\\\\u257F\\\\u2580-\\\\u259F\\\\u25A0-\\\\u25FF\\\\u2600-\\\\u26FF\\\\u2700-\\\\u27BF\\\\uE000-\\\\uF8FF]/g,\"\").replace(/[\\\\uDB80-\\\\uDBBF][\\\\uDC00-\\\\uDFFF]/g,\"\").replace(/[\\\\xAD\\\\u0600-\\\\u0605\\\\u061C\\\\u06DD\\\\u070F\\\\u08E2\\\\u180E\\\\u200B-\\\\u200F\\\\u202A-\\\\u202E\\\\u2060-\\\\u2064\\\\u2066-\\\\u206F\\\\uFEFF\\\\uFFF9-\\\\uFFFB]|\\\\uD804[\\\\uDCBD\\\\uDCCD]|\\\\uD80D[\\\\uDC30-\\\\uDC38]|\\\\uD82F[\\\\uDCA0-\\\\uDCA3]|\\\\uD834[\\\\uDD73-\\\\uDD7A]|\\\\uDB40[\\\\uDC01\\\\uDC20-\\\\uDC7F]/g,\"\")),t?e.replace(/[\\\\u2000-\\\\u206F\\\\u2E00-\\\\u2E7\\\nF\\\\\\\\'!\"#$%&\\\\xa3\\\\xa2\\\\xa5\\\\xa7\\\\u20ac()*+,\\\\-.\\\\/:;<=>?@\\\\[\\\\]^_\\`{|}~\\\\xb1]/g,\"\"):e},Tc=function(e){var t;return 0===Ns(e).length||1===(t=e).length&&t.match(/\\\\D/)||[\"aa\",\"abc\"].includes(e.toLowerCase())||(e=>(e=Nc(e,{emoji:!0,nonBmp:!0,punctuations:!0}),!Ns(e)))(e)?0:1},Sc={stateTerms:[\"on\",\"off\"],standaloneTerms:[\"name\",\"honorific-prefix\",\"given-name\",\"additional-name\",\"family-name\",\"honorific-suffix\",\"nickname\",\"username\",\"new-password\",\"current-password\",\"organization-title\",\"organization\",\"street-address\",\"address-line1\",\"address-line2\",\"address-line3\",\"address-level4\",\"address-level3\",\"address-level2\",\"address-level1\",\"country\",\"country-name\",\"postal-code\",\"cc-name\",\"cc-given-name\",\"cc-additional-name\",\"cc-family-name\",\"cc-number\",\"cc-exp\",\"cc-exp-month\",\"cc-exp-year\",\"cc-csc\",\"cc-type\",\"transaction-currency\",\"transaction-amount\",\"language\",\"bday\",\"bday-day\",\"bday-month\",\"bday-year\",\"sex\",\"url\",\"photo\",\"one-time-code\"],qualifiers:[\"home\",\"work\",\"mobile\",\"fax\",\"pager\"],qualifiedTerms:[\"tel\",\\\n\"tel-country-code\",\"tel-national\",\"tel-area-code\",\"tel-local\",\"tel-local-prefix\",\"tel-local-suffix\",\"tel-extension\",\"email\",\"impp\"],locations:[\"billing\",\"shipping\"]},_c=function(e){var t=void 0!==(t=(l=1<arguments.length&&void 0!==arguments[1]?arguments[1]:{}).looseTyped)&&t,n=void 0===(n=l.stateTerms)?[]:n,r=void 0===(r=l.locations)?[]:r,a=void 0===(a=l.qualifiers)?[]:a,o=void 0===(o=l.standaloneTerms)?[]:o,i=void 0===(i=l.qualifiedTerms)?[]:i,l=void 0===(l=l.ignoredValues)?[]:l;return e=e.toLowerCase().trim(),!(!(n=n.concat(Sc.stateTerms)).includes(e)&&\"\"!==e)||(a=a.concat(Sc.qualifiers),r=r.concat(Sc.locations),o=o.concat(Sc.standaloneTerms),i=i.concat(Sc.qualifiedTerms),!(\"webauthn\"===(n=e.split(/\\\\s+/g))[n.length-1]&&(n.pop(),0===n.length)||!t&&(8<n[0].length&&\"section-\"===n[0].substr(0,8)&&n.shift(),r.includes(n[0])&&n.shift(),a.includes(n[0])&&(n.shift(),o=[]),1!==n.length))&&(l.includes(e=n[n.length-1])?void 0:o.includes(e)||i.includes(e)))},Oc=function(e){var t;return e.attr(\"a\\\nria-labelledby\")&&(t=us(e.actualNode,\"aria-labelledby\").map((function(e){return(e=_l(e))?ac(e):\"\"})).join(\" \").trim())?t:(t=(t=e.attr(\"aria-label\"))&&Ns(t))||null},Mc=function(e,t,n){return e=_l(e),ac(e,t,n)},Pc=function(e){if(t=Oc(e))return t;if(e.attr(\"id\")){if(!e.actualNode)throw new TypeError(\"Cannot resolve explicit label reference for non-DOM nodes\");var t,n=Aa(e.attr(\"id\"));if(t=(n=Pl(e.actualNode).querySelector('label[for=\"'+n+'\"]'))&&Mc(n,!0))return t}return(t=(n=Wd(e,\"label\"))&&ac(n,!0))||null},Ic=function(e){return e=_l(e),Pc(e)},Bc=[{matches:[{nodeName:\"textarea\"},{nodeName:\"input\",properties:{type:[\"text\",\"password\",\"search\",\"tel\",\"email\",\"url\"]}}],namingMethods:\"labelText\"},{matches:{nodeName:\"input\",properties:{type:[\"button\",\"submit\",\"reset\"]}},namingMethods:[\"valueText\",\"titleText\",\"buttonDefaultText\"]},{matches:{nodeName:\"input\",properties:{type:\"image\"}},namingMethods:[\"altText\",\"valueText\",\"labelText\",\"titleText\",\"buttonDefaultText\"]},{matches:\"button\",namingMethods\\\n:\"subtreeText\"},{matches:\"fieldset\",namingMethods:\"fieldsetLegendText\"},{matches:\"OUTPUT\",namingMethods:\"subtreeText\"},{matches:[{nodeName:\"select\"},{nodeName:\"input\",properties:{type:/^(?!text|password|search|tel|email|url|button|submit|reset)/}}],namingMethods:\"labelText\"},{matches:\"summary\",namingMethods:\"subtreeText\"},{matches:\"figure\",namingMethods:[\"figureText\",\"titleText\"]},{matches:\"img\",namingMethods:\"altText\"},{matches:\"table\",namingMethods:[\"tableCaptionText\",\"tableSummaryText\"]},{matches:[\"hr\",\"br\"],namingMethods:[\"titleText\",\"singleSpace\"]}],jc=function e(t){var n=du(t),r=[];return t.children.forEach((function(t){3===t.actualNode.nodeType?n&&r.push(t):r=r.concat(e(t))})),r},Lc=cl((function(e){var t=_l(e),n=t.boundingClientRect,a=[],o=zl(t);return e.childNodes.forEach((function(e){var t,i;3!==e.nodeType||\"\"===Ns(e.nodeValue)||((t=r.createRange()).selectNodeContents(e),e=Array.from(t.getClientRects()),i=n,e.some((function(e){return!mu(vu(e),i)})))||a.push.apply(a,M(qc(e,o)))\\\n})),a.length?a:qc([n],o)}));function qc(e,t){var n=[];return e.forEach((function(e){e.width<1||e.height<1||(e=t.reduce((function(e,t){return e&&gu(e,t.boundingClientRect)}),e))&&n.push(e)})),n}var zc=function(e){var t=ju(e);return t?Lc(e).map((function(e){return Qu(t,e)})):[]},Vc=[\"checkbox\",\"img\",\"meter\",\"progressbar\",\"scrollbar\",\"radio\",\"slider\",\"spinbutton\",\"textbox\"],Gc=function(e){var t=Hf(e).vNode;if(e=o.commons.aria.getExplicitRole(t))return-1!==Vc.indexOf(e);switch(t.props.nodeName){case\"img\":case\"iframe\":case\"object\":case\"video\":case\"audio\":case\"canvas\":case\"svg\":case\"math\":case\"button\":case\"select\":case\"textarea\":case\"keygen\":case\"progress\":case\"meter\":return!0;case\"input\":return\"hidden\"!==t.props.type;default:return!1}},$c=[\"head\",\"title\",\"template\",\"script\",\"style\",\"iframe\",\"object\",\"video\",\"audio\",\"noscript\"];function Hc(e){return!$c.includes(e.props.nodeName)&&e.children.some((function(e){return 3===(e=e.props).nodeType&&e.nodeValue.trim()}))}var Uc=function e(t,n,r){retu\\\nrn Hc(t)||Gc(t.actualNode)||!r&&!!Oc(t)||!n&&t.children.some((function(t){return 1===t.actualNode.nodeType&&e(t)}))},Wc=function(e,t,n){return e=_l(e),Uc(e,t,n)};function Yc(e){return!(void 0!==e.children&&!Hc(e))||(1===e.props.nodeType&&Gc(e)?!!o.commons.text.accessibleTextVirtual(e):e.children.some((function(e){return!e.attr(\"lang\")&&Yc(e)&&!nu(e)})))}var Kc=function(e){return-1<Zf(e.getAttribute(\"tabindex\"))&&rs(e)&&!ns(e)};function Xc(e,t){var n=(e=Hf(e)).vNode;e=e.domNode;return n?(void 0===n._isHiddenWithCSS&&(n._isHiddenWithCSS=Zc(e,t)),n._isHiddenWithCSS):Zc(e,t)}function Zc(e,n){if(9===e.nodeType)return!1;if(11===e.nodeType&&(e=e.host),[\"STYLE\",\"SCRIPT\"].includes(e.nodeName.toUpperCase()))return!1;var r,a=t.getComputedStyle(e,null);if(a)return\"none\"===a.getPropertyValue(\"display\")||(r=[\"hidden\",\"collapse\"],a=a.getPropertyValue(\"visibility\"),!(!r.includes(a)||n))||!!(r.includes(a)&&n&&r.includes(n))||!(!(n=ou(e))||r.includes(a))&&Xc(n,a);throw new Error(\"Style does not exist fo\\\nr the given element.\")}var Jc=Xc,Qc=function(e){return null!==(e=e.doctype)&&\"html\"===e.name&&!e.publicId&&!e.systemId},ed=function(e){(e instanceof ua||null!=(n=t)&&n.Node&&e instanceof t.Node)&&(e=o.commons.aria.getRole(e));var n=gs.ariaRoles[e];return(null==n?void 0:n.type)||null},td=[\"block\",\"list-item\",\"table\",\"flex\",\"grid\",\"inline-block\"];function nd(e){return e=t.getComputedStyle(e).getPropertyValue(\"display\"),td.includes(e)||\"table-\"===e.substr(0,6)}var rd=function(e,t){var n,r,a,o;return!nd(e)&&(n=(e=>{for(var t=ou(e);t&&!nd(t);)t=ou(t);return _l(t)})(e),a=r=\"\",o=0,function e(t,n){!1!==n(t.actualNode)&&t.children.forEach((function(t){return e(t,n)}))}(n,(function(t){if(2===o)return!1;if(3===t.nodeType&&(r+=t.nodeValue),1===t.nodeType){var n=(t.nodeName||\"\").toUpperCase();if(t===e&&(o=1),![\"BR\",\"HR\"].includes(n))return!(\"none\"===t.style.display||\"hidden\"===t.style.overflow||![\"\",null,\"none\"].includes(t.style.float)||![\"\",null,\"relative\"].includes(t.style.position))&&(\"widget\"==\\\n=ed(t)?(a+=t.textContent,!1):void 0);0===o?a=r=\"\":o=2}})),r=Ns(r),null!=t&&t.noLengthCompare?0!==r.length:(a=Ns(a),r.length>a.length))},ad=function(e){if(e=(e=e||{}).modalPercent||.75,Sl.get(\"isModalOpen\"))return Sl.get(\"isModalOpen\");if(rm(o._tree[0],\"dialog, [role=dialog], [aria-modal=true]\",du).length)return Sl.set(\"isModalOpen\",!0),!0;for(var n,a=uu(t),i=a.width*e,l=a.height*e,u=(e=(a.width-i)/2,(a.height-l)/2),s=[{x:e,y:u},{x:a.width-e,y:u},{x:a.width/2,y:a.height/2},{x:e,y:a.height-u},{x:a.width-e,y:a.height-u}].map((function(e){return Array.from(r.elementsFromPoint(e.x,e.y))})),c=0;c<s.length;c++)if(n=(()=>{var e=s[c].find((function(e){return e=t.getComputedStyle(e),parseInt(e.width,10)>=i&&parseInt(e.height,10)>=l&&\"none\"!==e.getPropertyValue(\"pointer-events\")&&(\"absolute\"===e.position||\"fixed\"===e.position)}));if(e&&s.every((function(t){return t.includes(e)})))return Sl.set(\"isModalOpen\",!0),{v:!0}})())return n.v;Sl.set(\"isModalOpen\",void 0)};function od(e){var t,n=1<arguments\\\n.length&&void 0!==arguments[1]?arguments[1]:2,r=e.ownerDocument.createRange(),a=(r.setStart(e,0),r.setEnd(e,e.childNodes.length),0),o=0,i=K(r.getClientRects());try{for(i.s();!(t=i.n()).done;){var l=t.value;if(!(l.height<=n))if(l.top+n<a)a=Math.max(a,l.bottom);else{if(0!==o)return!0;a=l.bottom,o++}}}catch(e){i.e(e)}finally{i.f()}return!1}var id=function(e){return e instanceof t.Node},ld=\"color.incompleteData\",ud={set:function(e,t){if(\"string\"!=typeof e)throw new Error(\"Incomplete data: key must be a string\");var n=Sl.get(ld,(function(){return{}}));return t&&(n[e]=t),n[e]},get:function(e){var t=Sl.get(ld);return null==t?void 0:t[e]},clear:function(){Sl.set(ld,{})}},sd=function(e,n){var r=e.nodeName.toUpperCase();return[\"IMG\",\"CANVAS\",\"OBJECT\",\"IFRAME\",\"VIDEO\",\"SVG\"].includes(r)?(ud.set(\"bgColor\",\"imgNode\"),!0):((e=\"none\"!==(r=(n=n||t.getComputedStyle(e)).getPropertyValue(\"background-image\")))&&(n=/gradient/.test(r),ud.set(\"bgColor\",n?\"bgGradient\":\"bgImage\")),e)},cd=/^#[0-9a-f]{3,8}$/i,dd\\\n=/hsl\\\\(\\\\s*([-\\\\d.]+)(rad|turn)/,pd=(te=new WeakMap,ne=new WeakMap,re=new WeakMap,ae=new WeakMap,oe=new WeakMap,ie=new WeakMap,le=new WeakSet,W((function e(t,n,r){var a,o,i,l=3<arguments.length&&void 0!==arguments[3]?arguments[3]:1;H(this,e),B(this,le),I(this,te,void 0),I(this,ne,void 0),I(this,re,void 0),I(this,ae,void 0),I(this,oe,void 0),I(this,ie,void 0),t instanceof pd?(a=t.r,o=t.g,i=t.b,this.r=a,this.g=o,this.b=i,this.alpha=t.alpha):(this.red=t,this.green=n,this.blue=r,this.alpha=l)}),[{key:\"r\",get:function(){return L(te,this)},set:function(e){q(te,this,e),q(ae,this,Math.round(255*hd(e,0,1)))}},{key:\"g\",get:function(){return L(ne,this)},set:function(e){q(ne,this,e),q(oe,this,Math.round(255*hd(e,0,1)))}},{key:\"b\",get:function(){return L(re,this)},set:function(e){q(re,this,e),q(ie,this,Math.round(255*hd(e,0,1)))}},{key:\"red\",get:function(){return L(ae,this)},set:function(e){q(te,this,e/255),q(ae,this,hd(e,0,255))}},{key:\"green\",get:function(){return L(oe,this)},set:function(e){q(ne,t\\\nhis,e/255),q(oe,this,hd(e,0,255))}},{key:\"blue\",get:function(){return L(ie,this)},set:function(e){q(re,this,e/255),q(ie,this,hd(e,0,255))}},{key:\"toHexString\",value:function(){var e=Math.round(this.red).toString(16),t=Math.round(this.green).toString(16),n=Math.round(this.blue).toString(16);return\"#\"+(15.5<this.red?e:\"0\"+e)+(15.5<this.green?t:\"0\"+t)+(15.5<this.blue?n:\"0\"+n)}},{key:\"toJSON\",value:function(){return{red:this.red,green:this.green,blue:this.blue,alpha:this.alpha}}},{key:\"parseString\",value:function(e){e=e.replace(dd,(function(e,t,n){var r=t+n;switch(n){case\"rad\":return e.replace(r,180*t/Math.PI);case\"turn\":return e.replace(r,360*t)}}));try{\"Prototype\"in t&&\"Version\"in t.Prototype&&(n=Array.from,Array.from=sl.default);var n,r=new rl(e).to(\"srgb\");n&&(Array.from=n,n=null),this.r=r.r,this.g=r.g,this.b=r.b,this.alpha=+r.alpha}catch(n){throw new Error('Unable to parse color \"'.concat(e,'\"'))}return this}},{key:\"parseRgbString\",value:function(e){this.parseString(e)}},{key:\"parseHe\\\nxString\",value:function(e){e.match(cd)&&![6,8].includes(e.length)&&this.parseString(e)}},{key:\"parseColorFnString\",value:function(e){this.parseString(e)}},{key:\"getRelativeLuminance\",value:function(){var e=this.r,t=this.g,n=this.b;return.2126*(e<=.03928?e/12.92:Math.pow((e+.055)/1.055,2.4))+.7152*(t<=.03928?t/12.92:Math.pow((t+.055)/1.055,2.4))+.0722*(n<=.03928?n/12.92:Math.pow((n+.055)/1.055,2.4))}},{key:\"getLuminosity\",value:function(){return.3*this.r+.59*this.g+.11*this.b}},{key:\"setLuminosity\",value:function(e){return e-=this.getLuminosity(),z(le,this,fd).call(this,e).clip()}},{key:\"getSaturation\",value:function(){return Math.max(this.r,this.g,this.b)-Math.min(this.r,this.g,this.b)}},{key:\"setSaturation\",value:function(e){var t=new pd(this),n=V([{name:\"r\",value:t.r},{name:\"g\",value:t.g},{name:\"b\",value:t.b}].sort((function(e,t){return e.value-t.value})),3),r=n[0],a=n[1];return(n=n[2]).value>r.value?(a.value=(a.value-r.value)*e/(n.value-r.value),n.value=e):a.value=n.value=0,r.value=\\\n0,t[n.name]=n.value,t[r.name]=r.value,t[a.name]=a.value,t}},{key:\"clip\",value:function(){var e=new pd(this),t=e.getLuminosity(),n=Math.min(e.r,e.g,e.b),r=Math.max(e.r,e.g,e.b);return n<0&&(e.r=t+(e.r-t)*t/(t-n),e.g=t+(e.g-t)*t/(t-n),e.b=t+(e.b-t)*t/(t-n)),1<r&&(e.r=t+(e.r-t)*(1-t)/(r-t),e.g=t+(e.g-t)*(1-t)/(r-t),e.b=t+(e.b-t)*(1-t)/(r-t)),e}}]));function fd(e){var t=new pd(this);return t.r+=e,t.g+=e,t.b+=e,t}var md=pd;function hd(e,t,n){return Math.min(Math.max(t,e),n)}var gd=function(e){var t=new md;return t.parseString(e.getPropertyValue(\"background-color\")),0!==t.alpha&&(e=e.getPropertyValue(\"opacity\"),t.alpha=t.alpha*e),t},vd=function(e){var n=t.getComputedStyle(e);return sd(e,n)||1===gd(n).alpha};function bd(e){var t;return!(!e.href||(t=Sl.get(\"firstPageLink\",yd))&&e.compareDocumentPosition(t.actualNode)!==e.DOCUMENT_POSITION_FOLLOWING)}function yd(){return(t.location.origin?fm(o._tree,'a[href]:not([href^=\"javascript:\"])').find((function(e){return!Ku(e.actualNode)})):fm(o._tree,'a\\\n:not([href^=\"#\"]):not([href^=\"/#\"]):not([href^=\"javascript:\"])')[0])||null}var Dd=/rect\\\\s*\\\\(([0-9]+)px,?\\\\s*([0-9]+)px,?\\\\s*([0-9]+)px,?\\\\s*([0-9]+)px\\\\s*\\\\)/,wd=/(\\\\w+)\\\\((\\\\d+)/;var xd=function e(n,r,a){if(!n)throw new TypeError(\"Cannot determine if element is visible for non-DOM nodes\");var i,l,u,s=n instanceof ua?n:_l(n),c=(n=s?s.actualNode:n,\"_isVisible\"+(r?\"ScreenReader\":\"\")),d=(p=null!=(p=t.Node)?p:{}).DOCUMENT_NODE,p=p.DOCUMENT_FRAGMENT_NODE,f=(s?s.props:n).nodeType,m=s?s.props.nodeName:n.nodeName.toLowerCase();return s&&void 0!==s[c]?s[c]:f===d||![\"style\",\"script\",\"noscript\",\"template\"].includes(m)&&(n&&f===p&&(n=n.host),(!r||\"true\"!==(s?s.attr(\"aria-hidden\"):n.getAttribute(\"aria-hidden\")))&&(n?null!==(d=t.getComputedStyle(n,null))&&(\"area\"===m?(i=r,l=a,!!(p=jl(f=n,\"map\"))&&!!(p=p.getAttribute(\"name\"))&&!(!(f=Pl(f))||9!==f.nodeType||!(u=fm(o._tree,'img[usemap=\"#'.concat(Aa(p),'\"]')))||!u.length)&&u.some((function(t){return e(t.actualNode,i,l)}))):\"none\"!==d.getPropertyValue(\"display\")\\\n&&(m=parseInt(d.getPropertyValue(\"height\")),f=parseInt(d.getPropertyValue(\"width\")),u=(p=Cf(n))&&0===m,p=p&&0===f,m=\"absolute\"===d.getPropertyValue(\"position\")&&(m<2||f<2)&&\"hidden\"===d.getPropertyValue(\"overflow\"),!(!r&&((e=>{var t=e.getPropertyValue(\"clip\").match(Dd),n=e.getPropertyValue(\"clip-path\").match(wd);if(t&&5===t.length&&(e=e.getPropertyValue(\"position\"),[\"fixed\",\"absolute\"].includes(e)))return t[3]-t[1]<=0&&t[2]-t[4]<=0;if(n){e=n[1];var r=parseInt(n[2],10);switch(e){case\"inset\":return 50<=r;case\"circle\":return 0===r}}})(d)||\"0\"===d.getPropertyValue(\"opacity\")||u||p||m)||!a&&(\"hidden\"===d.getPropertyValue(\"visibility\")||!r&&su(n))))&&(f=!1,(p=n.assignedSlot||n.parentNode)&&(f=e(p,r,!0)),s&&(s[c]=f),f)):(m=!0,(a=s.parent)&&(m=e(a,r,!0)),s&&(s[c]=m),m)))},Ed=function(e,n){for(var r=[\"fixed\",\"sticky\"],a=[],o=!1,i=0;i<e.length;++i){var l=e[i],u=(l===n&&(o=!0),t.getComputedStyle(l));o||-1===r.indexOf(u.position)?a.push(l):a=[]}return a};function Ad(e,n){var r=Fd(n);do{var a,o,i,l\\\n,u,s,c=Fd(e);if(c===r||c===n)return a=e,o=n,s=(u=t.getComputedStyle(o)).getPropertyValue(\"overflow\"),\"inline\"===u.getPropertyValue(\"display\")||(a=Array.from(a.getClientRects()),i=o.getBoundingClientRect(),l={left:i.left,top:i.top,width:i.width,height:i.height},([\"scroll\",\"auto\"].includes(s)||o instanceof t.HTMLHtmlElement)&&(l.width=o.scrollWidth,l.height=o.scrollHeight),1===a.length&&\"hidden\"===s&&\"nowrap\"===u.getPropertyValue(\"white-space\")&&(a[0]=l),a.some((function(e){return!(Math.ceil(e.left)<Math.floor(l.left)||Math.ceil(e.top)<Math.floor(l.top)||Math.floor(e.left+e.width)>Math.ceil(l.left+l.width)||Math.floor(e.top+e.height)>Math.ceil(l.top+l.height))})))}while(e=c);return!1}function Fd(e){for(var t=_l(e).parent;t;){if(Cf(t.actualNode))return t.actualNode;t=t.parent}}var Cd=function e(t,n){var a=2<arguments.length&&void 0!==arguments[2]?arguments[2]:r,o=3<arguments.length&&void 0!==arguments[3]?arguments[3]:0;if(999<o)throw new Error(\"Infinite loop detected\");return Array.from(a\\\n.elementsFromPoint(t,n)||[]).filter((function(e){return Pl(e)===a})).reduce((function(r,a){var i;return Wp(a)&&(i=e(t,n,a.shadowRoot,o+1),!(r=r.concat(i)).length||!Ad(r[0],a))||r.push(a),r}),[])},kd=function(e,t){var n,a;if(e.hasAttribute(t))return a=e.nodeName.toUpperCase(),n=e,[\"A\",\"AREA\"].includes(a)&&!e.ownerSVGElement||((n=r.createElement(\"a\")).href=e.getAttribute(t)),a=[\"https:\",\"ftps:\"].includes(n.protocol)?n.protocol.replace(/s:$/,\":\"):n.protocol,t=(e=(e=(t=e=/^\\\\//.test(n.pathname)?n.pathname:\"/\".concat(n.pathname)).split(\"/\").pop())&&-1!==e.indexOf(\".\")?{pathname:t.replace(e,\"\"),filename:/index./.test(e)?\"\":e}:{pathname:t,filename:\"\"}).pathname,e=e.filename,{protocol:a,hostname:n.hostname,port:(a=n.port,[\"443\",\"80\"].includes(a)?\"\":a),pathname:/\\\\/$/.test(t)?t:\"\".concat(t,\"/\"),search:(e=>{var t={};if(e&&e.length){var n=e.substring(1).split(\"&\");if(n&&n.length)for(var r=0;r<n.length;r++){var a=(o=V(n[r].split(\"=\"),2))[0],o=void 0===(o=o[1])?\"\":o;t[decodeURIComponent(a)]=decodeURI\\\nComponent(o)}}return t})(n.search),hash:(a=n.hash)&&(t=a.match(/#!?\\\\/?/g))&&\"#\"!==V(t,1)[0]?a:\"\",filename:e}},Rd=function(e,n){var r=n.getBoundingClientRect(),a=r.top,o=r.left,i=a-n.scrollTop,l=(a=a-n.scrollTop+n.scrollHeight,o-n.scrollLeft);o=o-n.scrollLeft+n.scrollWidth;return!(e.left>o&&e.left>r.right||e.top>a&&e.top>r.bottom||e.right<l&&e.right<r.left||e.bottom<i&&e.bottom<r.top)&&(o=t.getComputedStyle(n),!(e.left>r.right||e.top>r.bottom)||\"scroll\"===o.overflow||\"auto\"===o.overflow||n instanceof t.HTMLBodyElement||n instanceof t.HTMLHtmlElement)},Nd=0;function Td(e,t,n){var r;return H(this,Td),(r=R(this,Td)).shadowId=n,r.children=[],r.actualNode=e,(r.parent=t)||(Nd=0),r.nodeIndex=Nd++,r._isHidden=null,r._cache={},r._isXHTML=dl(e.ownerDocument),\"input\"===e.nodeName.toLowerCase()&&(n=e.getAttribute(\"type\"),n=r._isXHTML?n:(n||\"\").toLowerCase(),Fm().includes(n)||(n=\"text\"),r._type=n),Sl.get(\"nodeMap\")&&Sl.get(\"nodeMap\").set(e,r),r}S(Td,ua);var Sd=W(Td,[{key:\"props\",get:function(){var e\\\n,t,n,r;return this._cache.hasOwnProperty(\"props\")||(e=(r=this.actualNode).nodeType,t=r.nodeName,n=r.id,r=r.nodeValue,this._cache.props={nodeType:e,nodeName:this._isXHTML?t:t.toLowerCase(),id:n,type:this._type,nodeValue:r},1===e&&(this._cache.props.multiple=this.actualNode.multiple,this._cache.props.value=this.actualNode.value,this._cache.props.selected=this.actualNode.selected,this._cache.props.checked=this.actualNode.checked,this._cache.props.indeterminate=this.actualNode.indeterminate)),this._cache.props}},{key:\"attr\",value:function(e){return\"function\"!=typeof this.actualNode.getAttribute?null:this.actualNode.getAttribute(e)}},{key:\"hasAttr\",value:function(e){return\"function\"==typeof this.actualNode.hasAttribute&&this.actualNode.hasAttribute(e)}},{key:\"attrNames\",get:function(){var e;return this._cache.hasOwnProperty(\"attrNames\")||(e=(this.actualNode.attributes instanceof t.NamedNodeMap?this.actualNode:this.actualNode.cloneNode(!1)).attributes,this._cache.attrNames=Array.from(e).map(\\\n(function(e){return e.name}))),this._cache.attrNames}},{key:\"getComputedStylePropertyValue\",value:function(e){var n=\"computedStyle_\"+e;return this._cache.hasOwnProperty(n)||(this._cache.hasOwnProperty(\"computedStyle\")||(this._cache.computedStyle=t.getComputedStyle(this.actualNode)),this._cache[n]=this._cache.computedStyle.getPropertyValue(e)),this._cache[n]}},{key:\"isFocusable\",get:function(){return this._cache.hasOwnProperty(\"isFocusable\")||(this._cache.isFocusable=rs(this.actualNode)),this._cache.isFocusable}},{key:\"tabbableElements\",get:function(){return this._cache.hasOwnProperty(\"tabbableElements\")||(this._cache.tabbableElements=ts(this)),this._cache.tabbableElements}},{key:\"clientRects\",get:function(){return this._cache.hasOwnProperty(\"clientRects\")||(this._cache.clientRects=Array.from(this.actualNode.getClientRects()).filter((function(e){return 0<e.width}))),this._cache.clientRects}},{key:\"boundingClientRect\",get:function(){return this._cache.hasOwnProperty(\"boundingClientRect\")\\\n||(this._cache.boundingClientRect=this.actualNode.getBoundingClientRect()),this._cache.boundingClientRect}}]),_d=\"DqElm.RunOptions\";function Od(e){var n=e.outerHTML;return(n=n||\"function\"!=typeof t.XMLSerializer?n:(new t.XMLSerializer).serializeToString(e))||\"\"}var Md=cl((function(e,t,n){var r;return null==n&&(n={}),t=(t=null==t?null:t)||(null!=(r=Sl.get(_d))?r:{}),this.spec=n,e instanceof ua?(this._virtualNode=e,this._element=e.actualNode):(this._element=e,this._virtualNode=_l(e)),this.fromFrame=1<(null==(r=this.spec.selector)?void 0:r.length),this._includeElementInJson=t.elementRef,t.absolutePaths&&(this._options={toRoot:!0}),this.nodeIndexes=[],Array.isArray(this.spec.nodeIndexes)?this.nodeIndexes=this.spec.nodeIndexes:\"number\"==typeof(null==(n=this._virtualNode)?void 0:n.nodeIndex)&&(this.nodeIndexes=[this._virtualNode.nodeIndex]),this.source=null,o._audit.noHtml||(this.source=null!=(e=this.spec.source)?e:function(e){if(e){var t=Od(e),n=(_l(e)||new Sd(e)).props.nodeName;if(!(t.leng\\\nth<300)){var r=[];if(t=e.cloneNode(!1),e=Na(t),(t=Od(t)).length<300){var a,o=\"\",i=K(e);try{for(i.s();!(a=i.n()).done;){var l=a.value,u={name:l.name,value:l.value};o+=\" \".concat(u.name,'=\"').concat(u.value,'\"')}}catch(e){i.e(e)}finally{i.f()}return\"<\".concat(n).concat(o,\">\")}var s,c=\"<\".concat(n,\">\").length,d=K(e);try{for(d.s();!(s=d.n()).done;){var p=s.value,f=p.name,m=p.value;if(300<c)break;var h={name:f,value:m},g=h.value,v=20<(v=h.name).length?v.substring(0,20)+\"...\":v,b=(g=20<g.length?g.substring(0,20)+\"...\":g,\"\".concat(v,'=\"').concat(g,'\"'));c+=(\" \"+b).length,r.push(b)}}catch(e){d.e(e)}finally{d.f()}300<(t=\"<\".concat(n,\" \").concat(r.join(\" \"),\">\")).length?t=t.substring(0,300)+\" ...>\":r.length<e.length&&(t=t.substring(0,t.length-1)+\" ...>\")}return t}return\"\"}(this._element)),this})),Pd=(Md.prototype={get selector(){return this.spec.selector||[Fl(this.element,this._options)]},get ancestry(){return this.spec.ancestry||[Rl(this.element)]},get xpath(){return this.spec.xpath||[Nl(this.e\\\nlement)]},get element(){return this._element},toJSON:function(){var e={selector:this.selector,source:this.source,xpath:this.xpath,ancestry:this.ancestry,nodeIndexes:this.nodeIndexes,fromFrame:this.fromFrame};return this._includeElementInJson&&(e.element=this._element),e}},Md.fromFrame=function(e,t,n){return e=Md.mergeSpecs(e,n),new Md(n.element,t,e)},Md.mergeSpecs=function(e,t){return O({},e,{selector:[].concat(M(t.selector),M(e.selector)),ancestry:[].concat(M(t.ancestry),M(e.ancestry)),xpath:[].concat(M(t.xpath),M(e.xpath)),nodeIndexes:[].concat(M(t.nodeIndexes),M(e.nodeIndexes)),fromFrame:!0})},Md.setRunOptions=function(e){var t=e.elementRef;Sl.set(_d,{elementRef:t,absolutePaths:e.absolutePaths})},Md),Id=function(e,n,r,a){return{isAsync:!1,async:function(){return this.isAsync=!0,function(t){t instanceof Error==0?(e.result=t,r(e)):a(t)}},data:function(t){e.data=t},relatedNodes:function(n){t.Node&&(n=n instanceof t.Node||n instanceof ua?[n]:Ea(n),e.relatedNodes=[],n.forEach((function(n\\\n){(n=n instanceof ua?n.actualNode:n)instanceof t.Node&&(n=new Pd(n),e.relatedNodes.push(n))})))}}};function Bd(e){return function e(n,r){var o,i;if(null===n||\"object\"!==a(n))return n;if(null!=(o=t)&&o.Node&&n instanceof t.Node||null!=(o=t)&&o.HTMLCollection&&n instanceof t.HTMLCollection||\"nodeName\"in n&&\"nodeType\"in n&&\"ownerDocument\"in n)return n;if(r.has(n))return r.get(n);if(Array.isArray(n))return i=[],r.set(n,i),n.forEach((function(t){i.push(e(t,r))})),i;var l={};for(var u in r.set(n,l),n)l[u]=e(n[u],r);return l}(e,new Map)}(Yo=new _a.CssSelectorParser).registerSelectorPseudos(\"not\"),Yo.registerSelectorPseudos(\"is\"),Yo.registerNestingOperators(\">\"),Yo.registerAttrEqualityMods(\"^\",\"$\",\"*\",\"~\");var jd=Yo;function Ld(e,t){return Hd(t).some((function(t){return Ud(e,t)}))}function qd(e,t){return i=t,1===(o=e).props.nodeType&&(\"*\"===i.tag||o.props.nodeName===i.tag)&&(a=e,!(o=t).classes||o.classes.every((function(e){return a.hasClass(e.value)})))&&(r=e,!(i=t).attributes||i.attributes.ev\\\nery((function(e){var t=r.attr(e.key);return null!==t&&e.test(t)})))&&(o=e,!(i=t).id||o.props.id===i.id)&&(n=e,!((o=t).pseudos&&!o.pseudos.every((function(e){if(\"not\"===e.name)return!e.expressions.some((function(e){return Ud(n,e)}));if(\"is\"===e.name)return e.expressions.some((function(e){return Ud(n,e)}));throw new Error(\"the pseudo selector \"+e.name+\" has not yet been implemented\")}))));var n,r,a,o,i}zd=/(?=[\\\\-\\\\[\\\\]{}()*+?.\\\\\\\\\\\\^$|,#\\\\s])/g;var zd,Vd=function(e){return e.replace(zd,\"\\\\\\\\\")},Gd=/\\\\\\\\/g;function $d(e){return e.map((function(e){for(var t=[],n=e.rule;n;)t.push({tag:n.tagName?n.tagName.toLowerCase():\"*\",combinator:n.nestingOperator||\" \",id:n.id,attributes:(e=>{if(e)return e.map((function(e){var t,n,r=e.name.replace(Gd,\"\"),a=(e.value||\"\").replace(Gd,\"\");switch(e.operator){case\"^=\":n=new RegExp(\"^\"+Vd(a));break;case\"$=\":n=new RegExp(Vd(a)+\"$\");break;case\"~=\":n=new RegExp(\"(^|\\\\\\\\s)\"+Vd(a)+\"(\\\\\\\\s|$)\");break;case\"|=\":n=new RegExp(\"^\"+Vd(a)+\"(-|$)\");break;case\"=\":t=function(e){return a===e\\\n};break;case\"*=\":t=function(e){return e&&e.includes(a)};break;case\"!=\":t=function(e){return a!==e};break;default:t=function(e){return null!==e}}return\"\"===a&&/^[*$^]=$/.test(e.operator)&&(t=function(){return!1}),{key:r,value:a,type:void 0===e.value?\"attrExist\":\"attrValue\",test:t=t||function(e){return e&&n.test(e)}}}))})(n.attrs),classes:(e=>{if(e)return e.map((function(e){return{value:e=e.replace(Gd,\"\"),regexp:new RegExp(\"(^|\\\\\\\\s)\"+Vd(e)+\"(\\\\\\\\s|$)\")}}))})(n.classNames),pseudos:(e=>{if(e)return e.map((function(e){var t;return[\"is\",\"not\"].includes(e.name)&&(t=$d(t=(t=e.value).selectors||[t])),{name:e.name,expressions:t,value:e.value}}))})(n.pseudos)}),n=n.rule;return t}))}function Hd(e){return $d((e=jd.parse(e)).selectors||[e])}function Ud(e,t,n){return function e(t,n,r,a){if(!t)return!1;for(var o=Array.isArray(n)?n[r]:n,i=qd(t,o);!i&&a&&t.parent;)i=qd(t=t.parent,o);if(0<r){if(!1===[\" \",\">\"].includes(o.combinator))throw new Error(\"axe.utils.matchesExpression does not support the combinator\\\n: \"+o.combinator);i=i&&e(t.parent,n,r-1,\" \"===o.combinator)}return i}(e,t,t.length-1,n)}var Wd=function(e,t){for(;e;){if(Ld(e,t))return e;if(void 0===e.parent)throw new TypeError(\"Cannot resolve parent for non-DOM nodes\");e=e.parent}return null};function Yd(){}function Kd(e){if(\"function\"!=typeof e)throw new TypeError(\"Queue methods require functions as arguments\")}for(var Xd,Zd,Jd,Qd=function(){function e(e){t=e,setTimeout((function(){null!=t&&ia(\"Uncaught error (of queue)\",t)}),1)}var t,n=[],r=0,o=0,i=Yd,l=!1,u=e;function s(e){return i=Yd,u(e),n}function c(){for(var e=n.length;r<e;r++){var t=n[r];try{t.call(null,(e=>function(t){n[e]=t,--o||i===Yd||(l=!0,i(n))})(r),s)}catch(e){s(e)}}}var d={defer:function(e){var r;if(\"object\"===a(e)&&e.then&&e.catch&&(r=e,e=function(e,t){r.then(e).catch(t)}),Kd(e),void 0===t){if(l)throw new Error(\"Queue already completed\");return n.push(e),++o,c(),d}},then:function(e){if(Kd(e),i!==Yd)throw new Error(\"queue \\`then\\` already set\");return t||(i=e,o)||(l=!0\\\n,i(n)),d},catch:function(n){if(Kd(n),u!==e)throw new Error(\"queue \\`catch\\` already set\");return t?(n(t),t=null):u=n,d},abort:s};return d},ep=t.crypto||t.msCrypto,tp=(!Zd&&ep&&ep.getRandomValues&&(Xd=new Uint8Array(16),Zd=function(){return ep.getRandomValues(Xd),Xd}),Zd||(Jd=new Array(16),Zd=function(){for(var e,t=0;t<16;t++)0==(3&t)&&(e=4294967296*Math.random()),Jd[t]=e>>>((3&t)<<3)&255;return Jd}),\"function\"==typeof t.Buffer?t.Buffer:Array),np=[],rp={},ap=0;ap<256;ap++)np[ap]=(ap+256).toString(16).substr(1),rp[np[ap]]=ap;function op(e,t){return t=t||0,np[e[t++]]+np[e[t++]]+np[e[t++]]+np[e[t++]]+\"-\"+np[e[t++]]+np[e[t++]]+\"-\"+np[e[t++]]+np[e[t++]]+\"-\"+np[e[t++]]+np[e[t++]]+\"-\"+np[e[t++]]+np[e[t++]]+np[e[t++]]+np[e[t++]]+np[e[t++]]+np[e[+t]]}var ip=[1|(kn=Zd())[0],kn[1],kn[2],kn[3],kn[4],kn[5]],lp=16383&(kn[6]<<8|kn[7]),up=0,sp=0;function cp(e,t,n){var r=t&&n||0,a=t||[],o=(n=null!=(e=e||{}).clockseq?e.clockseq:lp,null!=e.msecs?e.msecs:(new Date).getTime()),i=null!=e.nsecs?e.nsecs:sp+1;if(\\\n(l=o-up+(i-sp)/1e4)<0&&null==e.clockseq&&(n=n+1&16383),1e4<=(i=(l<0||up<o)&&null==e.nsecs?0:i))throw new Error(\"uuid.v1(): Can't create more than 10M uuids/sec\");up=o,lp=n;for(var l=(1e4*(268435455&(o+=122192928e5))+(sp=i))%4294967296,u=(i=(a[r++]=l>>>24&255,a[r++]=l>>>16&255,a[r++]=l>>>8&255,a[r++]=255&l,o/4294967296*1e4&268435455),a[r++]=i>>>8&255,a[r++]=255&i,a[r++]=i>>>24&15|16,a[r++]=i>>>16&255,a[r++]=n>>>8|128,a[r++]=255&n,e.node||ip),s=0;s<6;s++)a[r+s]=u[s];return t||op(a)}function dp(e,t,n){var r=t&&n||0,a=(\"string\"==typeof e&&(t=\"binary\"==e?new tp(16):null,e=null),(e=e||{}).random||(e.rng||Zd)());if(a[6]=15&a[6]|64,a[8]=63&a[8]|128,t)for(var o=0;o<16;o++)t[r+o]=a[o];return t||op(a)}(ra=dp).v1=cp,ra.v4=dp,ra.parse=function(e,t,n){var r=t&&n||0,a=0;for(t=t||[],e.toLowerCase().replace(/[0-9a-f]{2}/g,(function(e){a<16&&(t[r+a++]=rp[e])}));a<16;)t[r+a++]=0;return t},ra.unparse=op,ra.BufferClass=tp,o._uuid=cp();var pp=dp,fp=Object.freeze([\"EvalError\",\"RangeError\",\"ReferenceError\",\"S\\\nyntaxError\",\"TypeError\",\"URIError\"]);function mp(){var e=\"axeAPI\",t=\"\";return(e=void 0!==o&&o._audit&&o._audit.application?o._audit.application:e)+\".\"+(void 0!==o?o.version:t)}function hp(e){vp(e),xa(t.parent===e,\"Source of the response must be the parent window.\")}function gp(e){vp(e),xa(e.parent===t,\"Respondable target must be a frame in the current window\")}function vp(e){xa(t!==e,\"Messages can not be sent to the same window.\")}var bp={},yp=[];function Dp(){var e=\"\".concat(dp(),\":\").concat(dp());return yp.includes(e)?Dp():(yp.push(e),e)}function wp(e,t,n,r){var a,i,l,u;return(n?hp:gp)(e),t.message instanceof Error&&!n?(o.log(t.message),!1):(i=(u=O({messageId:Dp()},t)).topic,l=u.message,i={channelId:u.channelId,topic:i,messageId:u.messageId,keepalive:!!u.keepalive,source:mp()},l instanceof Error?i.error={name:l.name,message:l.message,stack:l.stack}:i.payload=l,a=JSON.stringify(i),!(!(u=o._audit.allowedOrigins)||!u.length||(\"function\"==typeof r&&function(e,t,n){n=!(2<arguments.length&\\\n&void 0!==n)||n,xa(!bp[e],\"A replyHandler already exists for this message channel.\"),bp[e]={replyHandler:t,sendToParent:n}}(t.channelId,r,n),u.forEach((function(t){try{e.postMessage(a,t)}catch(n){if(n instanceof e.DOMException)throw new Error('allowedOrigins value \"'.concat(t,'\" is not a valid origin'));throw n}})),0)))}function xp(e,t,n){var r=!(2<arguments.length&&void 0!==n)||n;return function(n,a,o){wp(e,{channelId:t,message:n,keepalive:a},r,o)}}function Ep(e,n){var r,i,l,u=e.origin,s=e.data;e=e.source;try{var c=function(e){var n,r,o,i;try{n=JSON.parse(e)}catch(e){return}if(null!==(e=n)&&\"object\"===a(e)&&\"string\"==typeof e.channelId&&e.source===mp())return r=(e=n).topic,o=e.channelId,i=e.messageId,e=e.keepalive,{topic:r,message:\"object\"===a(n.error)?(e=>{var n=e.message||\"Unknown error occurred\",r=fp.includes(e.name)?e.name:\"Error\";return r=t[r]||Error,e.stack&&(n+=\"\\\\n\"+e.stack.replace(e.message,\"\")),new r(n)})(n.error):n.payload,messageId:i,channelId:o,keepalive:!!e}}(s)||{},d=c.c\\\nhannelId,p=c.message,f=c.messageId;if(i=u,((l=o._audit.allowedOrigins)&&l.includes(\"*\")||l.includes(i))&&(r=f,!yp.includes(r))&&(yp.push(r),1))if(p instanceof Error&&e.parent!==t)o.log(p);else try{if(c.topic){var m=xp(e,d);hp(e),n(c,m)}else{var h=e,g=(b=c).channelId,v=b.message,b=b.keepalive,y=(D=(e=>bp[e])(g)||{}).replyHandler,D=D.sendToParent;if(y){(D?hp:gp)(h),h=xp(h,g,D),!b&&g&&(e=>{delete bp[e]})(g);try{y(v,b,h)}catch(n){o.log(n),h(n,b)}}}}catch(n){var w=e,x=n,E=d;if(!w.parent!==t)o.log(x);else try{wp(w,{topic:null,channelId:E,message:x,messageId:Dp(),keepalive:!0},!0)}catch(n){return void o.log(n)}}}catch(n){o.log(n)}}var Ap,Fp,Cp={open:function(e){var n;if(\"function\"==typeof t.addEventListener)return t.addEventListener(\"message\",n=function(t){Ep(t,e)},!1),function(){t.removeEventListener(\"message\",n,!1)}},post:function(e,n,r){return\"function\"==typeof t.addEventListener&&wp(e,n,!1,r)}};function kp(e){e.updateMessenger(Cp)}var Rp={};function Np(e,t,n,r,a){return t={topic:t,message\\\n:n,channelId:\"\".concat(dp(),\":\").concat(dp()),keepalive:r},Fp(e,t,a)}function Tp(e,t){var n=e.topic,r=e.message;e=e.keepalive;if(n=Rp[n])try{n(r,e,t)}catch(n){o.log(n),t(n,e)}}function Sp(e,t,n,r){var a,o=e.contentWindow,i=null!=(i=null==(i=t.options)?void 0:i.pingWaitTime)?i:500;o?0===i?_p(e,t,n,r):(a=setTimeout((function(){a=setTimeout((function(){t.debug?r(Op(\"No response from frame\",e)):n(null)}),0)}),i),Np(o,\"axe.ping\",null,void 0,(function(){clearTimeout(a),_p(e,t,n,r)}))):(ia(\"Frame does not have a content window\",e),n(null))}function _p(e,t,n,r){var a=null!=(a=null==(a=t.options)?void 0:a.frameWaitTime)?a:6e4,o=e.contentWindow,i=setTimeout((function(){r(Op(\"Axe in frame timed out\",e))}),a);Np(o,\"axe.start\",t,void 0,(function(e){clearTimeout(i),(e instanceof Error==0?n:r)(e)}))}function Op(e,t){var n;return o._tree&&(n=Fl(t)),new Error(e+\": \"+(n||t))}Np.updateMessenger=function(e){var t=e.open;e=e.post,xa(\"function\"==typeof t,\"open callback must be a function\"),xa(\"function\"==ty\\\npeof e,\"post callback must be a function\"),Ap&&Ap(),t=t(Tp);Ap=t?(xa(\"function\"==typeof t,\"open callback must return a cleanup function\"),t):null,Fp=e},Np.subscribe=function(e,t){xa(\"function\"==typeof t,\"Subscriber callback must be a function\"),xa(!Rp[e],\"Topic \".concat(e,\" is already registered to.\")),Rp[e]=t},Np.isInFrame=function(){return!!(0<arguments.length&&void 0!==arguments[0]?arguments[0]:t).frameElement},kp(Np);var Mp=null,Pp={update:function(e){xa(\"object\"===a(e),\"serializer must be an object\"),Mp=e},toSpec:function(e){return Pp.dqElmToSpec(new Pd(e))},dqElmToSpec:function(e,t){var n,r,a,o,i;return e instanceof Pd==0?e:(t&&(r=(n=e).fromFrame,a=t.ancestry,o=t.xpath,i=!1!==t.selectors||r,(n=new Pd(n.element,t,{source:n.source,nodeIndexes:n.nodeIndexes,selector:i?n.selector:[\":root\"],ancestry:a?n.ancestry:[\":root\"],xpath:o?n.xpath:\"/\"})).fromFrame=r,e=n),\"function\"==typeof(null==(t=Mp)?void 0:t.toSpec)?Mp.toSpec(e):e.toJSON())},mergeSpecs:function(e,t){var n;return(\"function\"==\\\ntypeof(null==(n=Mp)?void 0:n.mergeSpecs)?Mp:Pd).mergeSpecs(e,t)},mapRawResults:function(e){return e.map((function(e){return O({},e,{nodes:Pp.mapRawNodeResults(e.nodes)})}))},mapRawNodeResults:function(e){return null==e?void 0:e.map((function(e){var t=e.node,n=k(e,g);n.node=Pp.dqElmToSpec(t);for(var r=0,a=[\"any\",\"all\",\"none\"];r<a.length;r++){var o=a[r];n[o]=n[o].map((function(e){var t=e.relatedNodes;return(e=k(e,v)).relatedNodes=t.map(Pp.dqElmToSpec),e}))}return n}))}},Ip=Pp,Bp=function(e){return[].concat(e.any||[]).concat(e.all||[]).concat(e.none||[])},jp=function(e,t,n){if(Array.isArray(e))return e.find((function(e){return null!==e&&\"object\"===a(e)&&Object.hasOwn(e,t)&&e[t]===n}))};function Lp(e,t){for(var n=0<arguments.length&&void 0!==e?e:[],r=1<arguments.length&&void 0!==t?t:[],a=Math.max(null==n?void 0:n.length,null==r?void 0:r.length),o=0;o<a;o++){var i=null==n?void 0:n[o],l=null==r?void 0:r[o];if(\"number\"!=typeof i||isNaN(i))return 0===o?1:-1;if(\"number\"!=typeof l||isNaN(l))retu\\\nrn 0===o?-1:1;if(i!==l)return i-l}return 0}var qp=function(e,t){var n=[];return e.forEach((function(e){var t,r=(r=e)&&r.results?Array.isArray(r.results)?r.results.length?r.results:null:[r.results]:null;r&&r.length&&(t=(e=>e.frameElement?Ip.toSpec(e.frameElement):e.frameSpec||null)(e),r.forEach((function(e){e.nodes&&t&&(a=e.nodes,r=t,a.forEach((function(e){e.node=Ip.mergeSpecs(e.node,r),Bp(e).forEach((function(e){e.relatedNodes=e.relatedNodes.map((function(e){return Ip.mergeSpecs(e,r)}))}))})));var r,a=jp(n,\"id\",e.id);a?(e.nodes.length&&((e,t)=>{for(var n=t[0].node,r=0;r<e.length;r++){var a,o=Lp((a=e[r].node).nodeIndexes,n.nodeIndexes);if(0<o||0===o&&n.selector.length<a.selector.length)return e.splice.apply(e,[r,0].concat(M(t)))}e.push.apply(e,M(t))})(a.nodes,e.nodes),e.error&&null==a.error&&(a.error=e.error)):n.push(e)})))})),n.forEach((function(e){e.nodes&&e.nodes.sort((function(e,t){return Lp(e.node.nodeIndexes,t.node.nodeIndexes)}))})),n};function zp(e,t,n,r,a,o){t=O({},t,{elementRe\\\nf:!1});var i=Qd();e.frames.forEach((function(e){var a=e.node,o=k(e,b);i.defer((function(e,i){Sp(a,{options:t,command:n,parameter:r,context:o},(function(t){return e(t?{results:t,frameElement:a}:null)}),i)}))})),i.then((function(e){a(qp(e,t))})).catch(o)}function Vp(e,t){if(!e.shadowId&&!t.shadowId&&e.actualNode&&\"function\"==typeof e.actualNode.contains)return e.actualNode.contains(t.actualNode);do{if(e===t)return!0;if(t.nodeIndex<e.nodeIndex)return!1}while(t=t.parent);return!1}var Gp,$p=function e(){for(var t={},n=arguments.length,r=new Array(n),o=0;o<n;o++)r[o]=arguments[o];return r.forEach((function(n){if(n&&\"object\"===a(n)&&!Array.isArray(n))for(var r=0,o=Object.keys(n);r<o.length;r++){var i=o[r];!t.hasOwnProperty(i)||\"object\"!==a(n[i])||Array.isArray(t[i])?t[i]=n[i]:t[i]=e(t[i],n[i])}})),t},Hp=function(e,t){Object.assign(e,t),Object.keys(t).filter((function(e){return\"function\"==typeof t[e]})).forEach((function(n){e[n]=null;try{e[n]=t[n](e)}catch(n){}}))},Up=[\"article\",\"aside\",\"block\\\nquote\",\"body\",\"div\",\"footer\",\"h1\",\"h2\",\"h3\",\"h4\",\"h5\",\"h6\",\"header\",\"main\",\"nav\",\"p\",\"section\",\"span\"],Wp=function(e){return!!(e.shadowRoot&&(e=e.nodeName.toLowerCase(),Up.includes(e)||/^[a-z][a-z0-9_.-]*-[a-z0-9_.-]*$/.test(e)))},Yp=function(e){return(e||\"\").trim().replace(/\\\\s{2,}/g,\" \").split(\" \")},Kp=\" [idsMap]\";function Xp(e,t,n){var r=e[0]._selectorMap;if(r){for(var a=e[0].shadowId,o=0;o<t.length;o++)if(1<t[o].length&&t[o].some(Zp))return;var i=new Set,l=(t.forEach((function(e){var t,n=((e,t,n)=>{var r=e[e.length-1],a=null,o=1<e.length||!!r.pseudos||!!r.classes;if(Zp(r))a=t[\"*\"];else{if(r.id){if(!t[Kp]||!Object.hasOwn(t[Kp],r.id)||null==(e=t[Kp][r.id])||!e.length)return;a=t[Kp][r.id].filter((function(e){return e.shadowId===n}))}if(r.tag&&\"*\"!==r.tag){if(null==(e=t[r.tag])||!e.length)return;e=t[r.tag];a=a?Jp(e,a):e}if(r.classes){if(null==(e=t[\"[class]\"])||!e.length)return;e=t[\"[class]\"],a=a?Jp(e,a):e}if(r.attributes)for(var i=0;i<r.attributes.length;i++){var l=r.attributes[i];if(\"a\\\nttrValue\"===l.type&&(o=!0),null==(u=t[\"[\".concat(l.key,\"]\")])||!u.length)return;var u=t[\"[\".concat(l.key,\"]\")];a=a?Jp(u,a):u}}return{nodes:a,isComplexSelector:o}})(e,r,a);null!=n&&null!=(t=n.nodes)&&t.forEach((function(t){n.isComplexSelector&&!Ud(t,e)||i.add(t)}))})),[]);return i.forEach((function(e){return l.push(e)})),(l=n?l.filter(n):l).sort((function(e,t){return e.nodeIndex-t.nodeIndex}))}}function Zp(e){return\"*\"===e.tag&&!e.attributes&&!e.id&&!e.classes}function Jp(e,t){return e.filter((function(e){return t.includes(e)}))}function Qp(e,t,n){Object.hasOwn(n,e)||(n[e]=[]),n[e].push(t)}function ef(e,t){1===e.props.nodeType&&(Qp(e.props.nodeName,e,t),Qp(\"*\",e,t),e.attrNames.forEach((function(n){\"id\"===n&&(t[Kp]=t[Kp]||{},Yp(e.attr(n)).forEach((function(n){Qp(n,e,t[Kp])}))),Qp(\"[\".concat(n,\"]\"),e,t)})))}function tf(){var e=0<arguments.length&&void 0!==arguments[0]?arguments[0]:r.documentElement,t=1<arguments.length?arguments[1]:void 0,n=(Gp=!1,{});return(e=(Sl.set(\"nodeMap\",new WeakMa\\\np),Sl.set(\"selectorMap\",n),af(e,t,null)))[0]._selectorMap=n,e[0]._hasShadowRoot=Gp,e}function nf(e,t,n){return ef(e=new Sd(e,t,n),Sl.get(\"selectorMap\")),e}function rf(e,t,n){var r=[];return e.forEach((function(e){(e=af(e,n,t))&&r.push.apply(r,M(e))})),r}function af(e,n,a){var o,i,l=(e=e.documentElement?e.documentElement:e).nodeName.toLowerCase();return Wp(e)?(Gp=!0,o=nf(e,a,n),n=\"a\"+Math.random().toString().substring(2),i=Array.from(e.shadowRoot.childNodes),o.children=rf(i,o,n),[o]):\"content\"===l&&\"function\"==typeof e.getDistributedNodes?rf(i=Array.from(e.getDistributedNodes()),a,n):\"slot\"===l&&\"function\"==typeof e.assignedNodes?((i=Array.from(e.assignedNodes())).length||(i=(e=>{var t=[];for(e=e.firstChild;e;)t.push(e),e=e.nextSibling;return t})(e)),t.getComputedStyle(e),rf(i,a,n)):e.nodeType===r.ELEMENT_NODE?(o=nf(e,a,n),i=Array.from(e.childNodes),o.children=rf(i,o,n),[o]):e.nodeType===r.TEXT_NODE?[nf(e,a)]:void 0}var of=function(e){return e?e.trim().split(\"-\")[0].toLowerCase():\"\"},lf\\\n=function(e){var t={};return t.none=e.none.concat(e.all),t.any=e.any,Object.keys(t).map((function(e){var n;return t[e].length&&(n=o._audit.data.failureSummaries[e])&&\"function\"==typeof n.failureMessage?n.failureMessage(t[e].map((function(e){return e.message||\"\"}))):void 0})).filter((function(e){return void 0!==e})).join(\"\\\\n\\\\n\")};function uf(){var e=o._audit.data.incompleteFallbackMessage;return\"string\"!=typeof(e=\"function\"==typeof e?e():e)?\"\":e}var sf=oa.resultGroups;function cf(e,t){var n=o.utils.aggregateResult(e);return sf.forEach((function(e){t.resultTypes&&!t.resultTypes.includes(e)&&(n[e]||[]).forEach((function(e){Array.isArray(e.nodes)&&0<e.nodes.length&&(e.nodes=[e.nodes[0]])})),n[e]=(n[e]||[]).map((function(e){return e=Object.assign({},e),Array.isArray(e.nodes)&&0<e.nodes.length&&(e.nodes=e.nodes.map((function(e){var n,r,o;return\"object\"===a(e.node)&&(n=df(e.node,t),Object.assign(e,n)),delete e.result,delete e.node,r=e,o=t,[\"any\",\"all\",\"none\"].forEach((function(e){Array.isArra\\\ny(r[e])&&r[e].filter((function(e){return Array.isArray(e.relatedNodes)})).forEach((function(e){e.relatedNodes=e.relatedNodes.map((function(e){return df(e,o)}))}))})),e}))),sf.forEach((function(t){return delete e[t]})),delete e.pageLevel,delete e.result,e}))})),n}function df(e,t){e=0<arguments.length&&void 0!==e?e:{},t=1<arguments.length?t:void 0,e=Ip.dqElmToSpec(e,t);var n,r={};return o._audit.noHtml?r.html=null:r.html=null!=(n=e.source)?n:\"Undefined\",t.elementRef&&!e.fromFrame&&(r.element=null!=(n=e.element)?n:null),!1===t.selectors&&!e.fromFrame||(r.target=null!=(n=e.selector)?n:[\":root\"]),t.ancestry&&(r.ancestry=null!=(n=e.ancestry)?n:[\":root\"]),t.xpath&&(r.xpath=null!=(n=e.xpath)?n:[\"/\"]),r}var pf=/\\\\$\\\\{\\\\s?data\\\\s?\\\\}/g;function ff(e,t){if(\"string\"==typeof t)return e.replace(pf,t);for(var n in t){var r;t.hasOwnProperty(n)&&(r=new RegExp(\"\\\\\\\\\\${\\\\\\\\s?data\\\\\\\\.\"+n+\"\\\\\\\\s?}\",\"g\"),n=void 0===t[n]?\"\":String(t[n]),e=e.replace(r,n))}return e}var mf=function e(t,n){var r;if(t)return Array.isArray(n)?\\\n(n.values=n.join(\", \"),\"string\"==typeof t.singular&&\"string\"==typeof t.plural?ff(1===n.length?t.singular:t.plural,n):ff(t,n)):\"string\"==typeof t?ff(t,n):\"string\"==typeof n?ff(t[n],n):(r=t.default||uf(),e(r=n&&n.messageKey&&t[n.messageKey]?t[n.messageKey]:r,n))},hf=function(e,t,n){var r=o._audit.data.checks[e];if(!r)throw new Error(\"Cannot get message for unknown check: \".concat(e,\".\"));if(r.messages[t])return mf(r.messages[t],n);throw new Error('Check \"'.concat(e,'\"\" does not have a \"').concat(t,'\" message.'))},gf=function(e,t,n){t=((n.rules&&n.rules[t]||{}).checks||{})[e.id];var r=(n.checks||{})[e.id],a=e.enabled;e=e.options;return r&&(r.hasOwnProperty(\"enabled\")&&(a=r.enabled),r.hasOwnProperty(\"options\"))&&(e=r.options),t&&(t.hasOwnProperty(\"enabled\")&&(a=t.enabled),t.hasOwnProperty(\"options\"))&&(e=t.options),{enabled:a,options:e,absolutePaths:n.absolutePaths}};function vf(){var e,n,r,i,l=0<arguments.length&&void 0!==arguments[0]?arguments[0]:null,u=1<arguments.length&&void 0!==argum\\\nents[1]?arguments[1]:t;return l&&\"object\"===a(l)?l:\"object\"!==a(u)?{}:{testEngine:{name:\"axe-core\",version:o.version},testRunner:{name:o._audit.brand},testEnvironment:(l=u).navigator&&\"object\"===a(l.navigator)?(e=l.navigator,n=l.innerHeight,r=l.innerWidth,l=(e=>(e=e.screen).orientation||e.msOrientation||e.mozOrientation)(l)||{},i=l.angle,l=l.type,{userAgent:e.userAgent,windowWidth:r,windowHeight:n,orientationAngle:i,orientationType:l}):{},timestamp:(new Date).toISOString(),url:null==(e=u.location)?void 0:e.href}}function bf(e,t){var n=t.focusable;t=t.page;return{node:e,include:[],exclude:[],initiator:!1,focusable:n&&(e=>null===(e=Zf(e.getAttribute(\"tabindex\")))||0<=e)(e),size:(e=>{var t=parseInt(e.getAttribute(\"width\"),10),n=parseInt(e.getAttribute(\"height\"),10);return(isNaN(t)||isNaN(n))&&(e=e.getBoundingClientRect(),t=isNaN(t)?e.width:t,n=isNaN(n)?e.height:n),{width:t,height:n}})(e),page:t}}function yf(e){var n=0<arguments.length&&void 0!==e?e:[],r=[];_f(n)||(n=[n]);for(var a=0;a<n.l\\\nength;a++){var o=(e=>{if(e instanceof t.Node)return e;if(\"string\"==typeof e)return[e];var n;if(Bf(e)?(n=e,Df(Array.isArray(n.fromFrames),\"fromFrames property must be an array\"),Df(n.fromFrames.every((function(e){return!Of(e,\"fromFrames\")})),\"Invalid context; fromFrames selector must be appended, rather than nested\"),Df(!Of(n,\"fromShadowDom\"),\"fromFrames and fromShadowDom cannot be used on the same object\"),e=e.fromFrames):jf(e)&&(e=[e]),Array.isArray(e)){var r,a=[],o=K(e);try{for(o.s();!(r=o.n()).done;){var i=r.value;if(jf(i)&&((e=>{Df(Array.isArray(e.fromShadowDom),\"fromShadowDom property must be an array\"),Df(e.fromShadowDom.every((function(e){return!Of(e,\"fromFrames\")})),\"shadow selector must be inside fromFrame instead\"),Df(e.fromShadowDom.every((function(e){return!Of(e,\"fromShadowDom\")})),\"fromShadowDom selector must be appended, rather than nested\")})(i),i=i.fromShadowDom),\"string\"!=typeof i&&!(e=>Array.isArray(e)&&e.every((function(e){return\"string\"==typeof e})))(i))return;a.pus\\\nh(i)}}catch(e){o.e(e)}finally{o.f()}return a}})(n[a]);o&&r.push(o)}return r}function Df(e,t){xa(e,\"Invalid context; \".concat(t,\"\\\\nSee: https://github.com/dequelabs/axe-core/blob/master/doc/context.md\"))}function wf(e,n){for(var r=[],a=0,o=e[n].length;a<o;a++){var i=e[n][a];i instanceof t.Node?i.documentElement instanceof t.Node?r.push(e.flatTree[0]):r.push(_l(i)):i&&i.length&&(1<i.length?((e,t,n)=>{e.frames=e.frames||[],Am(n.shift()).forEach((function(r){var a=e.frames.find((function(e){return e.node===r}));a||(a=bf(r,e),e.frames.push(a)),a[t].push(n)}))})(e,n,i):(i=Am(i[0]),r.push.apply(r,M(i.map((function(e){return _l(e)}))))))}return r.filter((function(e){return e}))}function xf(e,n){var o=this,i=(e=Bd(e),this.frames=[],this.page=\"boolean\"==typeof(null==(i=e)?void 0:i.page)?e.page:void 0,this.initiator=\"boolean\"!=typeof(null==(i=e)?void 0:i.initiator)||e.initiator,this.focusable=\"boolean\"!=typeof(null==(i=e)?void 0:i.focusable)||e.focusable,this.size=\"object\"===a(null==(i=e)?void 0:\\\ni.size)?e.size:{},e=(e=>{if(Pf(e)){var t=\" must be used inside include or exclude. It should not be on the same object.\";Df(!Of(e,\"fromFrames\"),\"fromFrames\"+t),Df(!Of(e,\"fromShadowDom\"),\"fromShadowDom\"+t)}else{if(!If(e))return{include:[r],exclude:[]};e={include:e,exclude:[]}}return 0===(t=yf(e.include)).length&&t.push(r),{include:t,exclude:e=yf(e.exclude)}})(e),this.flatTree=null!=n?n:tf((e=>{for(var n=e.include,a=(e=e.exclude,Array.from(n).concat(Array.from(e))),o=0;o<a.length;o++){var i=a[o];if(i instanceof t.Element)return i.ownerDocument.documentElement;if(i instanceof t.Document)return i.documentElement}return r.documentElement})(e)),this.exclude=e.exclude,this.include=e.include,this.include=wf(this,\"include\"),this.exclude=wf(this,\"exclude\"),bm(\"frame, iframe\",this).forEach((function(e){var t;zf(e,o)&&(t=o,nc(e=e.actualNode))&&!jp(t.frames,\"node\",e)&&t.frames.push(bf(e,t))})),void 0===this.page&&(this.page=(e=>1===(e=e.include).length&&e[0].actualNode===r.documentElement)(this),th\\\nis.frames.forEach((function(e){e.page=o.page}))),this);if(0===i.include.length&&0===i.frames.length)throw i=Np.isInFrame()?\"frame\":\"page\",new Error(\"No elements found for include in \"+i+\" Context\");Array.isArray(this.include)||(this.include=Array.from(this.include)),this.include.sort($f)}function Ef(e){return!1===(1<arguments.length&&void 0!==arguments[1]?arguments[1]:{}).iframes?[]:new xf(e).frames.map((function(e){var t=e.node;return(e=k(e,y)).initiator=!1,{frameSelector:Rl(t),frameContext:e}}))}function Af(e){var t=o._audit.rules.find((function(t){return t.id===e}));if(t)return t;throw new Error(\"Cannot find rule by id: \".concat(e))}function Ff(e,t){return e=e.getPropertyValue(t),[\"scroll\",\"auto\"].includes(e)}var Cf=cl((function(e){var n,r,a=1<arguments.length&&void 0!==arguments[1]?arguments[1]:0,o=e.scrollWidth>e.clientWidth+a;a=e.clientHeight+a<e.scrollHeight;if(o||a)return n=Ff(r=t.getComputedStyle(e),\"overflow-x\"),r=Ff(r,\"overflow-y\"),o&&n||a&&r?{elm:e,top:e.scrollTop,left:e.sc\\\nrollLeft}:void 0})),kf=function(){var e=0<arguments.length&&void 0!==arguments[0]?arguments[0]:t,n=e.document.documentElement;return[void 0!==e.pageXOffset?{elm:e,top:e.pageYOffset,left:e.pageXOffset}:{elm:n,top:n.scrollTop,left:n.scrollLeft}].concat(function e(t){return Array.from(t.children||t.childNodes||[]).reduce((function(t,n){var r=Cf(n);return r&&t.push(r),t.concat(e(n))}),[])}(r.body))};function Rf(){return Bd(gs)}var Nf,Tf=function(e){if(e)return function(t){var n=t.data,r=void 0!==(r=t.isCrossOrigin)&&r,a=t.shadowId,o=t.root,i=t.priority,l=(t=void 0!==(t=t.isLink)&&t,e.createElement(\"style\"));return t?(t=e.createTextNode('@import \"'.concat(n.href,'\"')),l.appendChild(t)):l.appendChild(e.createTextNode(n)),e.head.appendChild(l),{sheet:l.sheet,isCrossOrigin:r,shadowId:a,root:o,priority:i}};throw new Error(\"axe.utils.getStyleSheetFactory should be invoked with an argument\")},Sf=function(e){var t;return Nf&&Nf.parentNode?(void 0===Nf.styleSheet?Nf.appendChild(r.createTextNode(e))\\\n:Nf.styleSheet.cssText+=e,Nf):e?(t=r.head||r.getElementsByTagName(\"head\")[0],(Nf=r.createElement(\"style\")).type=\"text/css\",void 0===Nf.styleSheet?Nf.appendChild(r.createTextNode(e)):Nf.styleSheet.cssText=e,t.appendChild(Nf),Nf):void 0};function _f(e){return!!e&&\"object\"===a(e)&&\"number\"==typeof e.length&&e instanceof t.Node==0}function Of(e,t){return!(!e||\"object\"!==a(e))&&Object.prototype.hasOwnProperty.call(e,t)}function Mf(e){return Pf(e)||If(e)}function Pf(e){return[\"include\",\"exclude\"].some((function(t){return Of(e,t)&&If(e[t])}))}function If(e){return\"string\"==typeof e||e instanceof t.Node||Bf(e)||jf(e)||_f(e)}function Bf(e){return Of(e,\"fromFrames\")}function jf(e){return Of(e,\"fromShadowDom\")}var Lf=function e(n,r){var a,o=_l(n);return 9!==n.nodeType&&(11===n.nodeType&&(n=n.host),o&&null!==o._isHidden?o._isHidden:!(a=t.getComputedStyle(n,null))||!n.parentNode||\"none\"===a.getPropertyValue(\"display\")||!r&&\"hidden\"===a.getPropertyValue(\"visibility\")||\"true\"===n.getAttribute(\"aria-h\\\nidden\")||(r=e(n.assignedSlot||n.parentNode,!0),o&&(o._isHidden=r),r))},qf=function(e){var t=null!=(t=null==(t=e.props)?void 0:t.nodeName)?t:e.nodeName.toLowerCase();return\"http://www.w3.org/2000/svg\"!==e.namespaceURI&&!!gs.htmlElms[t]};function zf(e,t){var n=void 0===(n=t.include)?[]:n;t=void 0===(t=t.exclude)?[]:t,n=n.filter((function(t){return Vp(t,e)}));return 0!==n.length&&(0===(t=t.filter((function(t){return Vp(t,e)}))).length||(n=Vf(n),Vp(Vf(t),n)))}function Vf(e){var t,n,r=K(e);try{for(r.s();!(n=r.n()).done;){var a=n.value;t&&Vp(a,t)||(t=a)}}catch(e){r.e(e)}finally{r.f()}return t}function Gf(e,t){return e.length===t.length&&e.every((function(e,n){var r=t[n];return Array.isArray(e)?e.length===r.length&&e.every((function(e,t){return r[t]===e})):e===r}))}var $f=function(e,t){return(e=e.actualNode||e)===(t=t.actualNode||t)?0:4&e.compareDocumentPosition(t)?-1:1};function Hf(e){return e instanceof ua?{vNode:e,domNode:e.actualNode}:{vNode:_l(e),domNode:e}}var Uf,Wf,Yf=function(e,t,n,r)\\\n{var a,o=4<arguments.length&&void 0!==arguments[4]&&arguments[4],i=Array.from(e.cssRules);return i?(a=i.filter((function(e){return 3===e.type}))).length?(a=a.filter((function(e){return e.href})).map((function(e){return e.href})).filter((function(e){return!r.includes(e)})).map((function(e,a){a=[].concat(M(n),[a]);var o=/^https?:\\\\/\\\\/|^\\\\/\\\\//i.test(e);return Xf(e,t,a,r,o)})),(i=i.filter((function(e){return 3!==e.type}))).length&&a.push(Promise.resolve(t.convertDataToStylesheet({data:i.map((function(e){return e.cssText})).join(),isCrossOrigin:o,priority:n,root:t.rootNode,shadowId:t.shadowId}))),Promise.all(a)):Promise.resolve({isCrossOrigin:o,priority:n,root:t.rootNode,shadowId:t.shadowId,sheet:e}):Promise.resolve()},Kf=function(e,t,n,r){var a=4<arguments.length&&void 0!==arguments[4]&&arguments[4];return(e=>{try{return!(!e.cssRules&&e.href)}catch(e){return!1}})(e)?Yf(e,t,n,r,a):Xf(e.href,t,n,r,!0)},Xf=function(e,n,r,a,o){return a.push(e),new Promise((function(n,r){var a=new t.XMLHttpReques\\\nt;a.open(\"GET\",e),a.timeout=oa.preload.timeout,a.addEventListener(\"error\",r),a.addEventListener(\"timeout\",r),a.addEventListener(\"loadend\",(function(e){if(e.loaded&&a.responseText)return n(a.responseText);r(a.responseText)})),a.send()})).then((function(e){return e=n.convertDataToStylesheet({data:e,isCrossOrigin:o,priority:r,root:n.rootNode,shadowId:n.shadowId}),Kf(e.sheet,n,r,a,e.isCrossOrigin)}))},Zf=function(e){return\"string\"==typeof e&&(e=e.trim().match(/^([-+]?\\\\d+)/))?Number(e[1]):null};function Jf(){if(t.performance)return t.performance.now()}Uf=Jf(),Wf=!1;var Qf={start:function(){this.reset(),Wf=!0,this.mark(\"mark_axe_start\")},end:function(){this.mark(\"mark_axe_end\"),this.measure(\"axe\",\"mark_axe_start\",\"mark_axe_end\",!0),this.logMeasures(\"axe\"),this.clearMark(\"mark_axe_start\",\"mark_axe_end\"),Wf=!1},auditStart:function(){Wf||this.reset(),this.mark(\"mark_audit_start\")},auditEnd:function(){this.mark(\"mark_audit_end\"),this.measure(\"audit_start_to_end\",\"mark_audit_start\",\"mark_audit_en\\\nd\",!0),this.logMeasures(),this.clearMark(\"mark_audit_start\",\"mark_audit_end\")},mark:function(e){var n;null!=(n=t.performance)&&n.mark&&t.performance.mark(e)},measure:function(e,n,r){var a,o=3<arguments.length&&void 0!==arguments[3]&&arguments[3];if(null!=(a=t.performance)&&a.measure){try{t.performance.measure(e,n,r)}catch(e){this._log(e)}o||this.clearMark(n,r)}},logMeasures:function(e){function n(e){return Array.isArray(e)?e[e.length-1]:e}function r(e){o._log(\"Measure \"+e.name+\" took \"+e.duration+\"ms\")}var a,o=this;if(null!=(a=t.performance)&&a.getEntriesByType&&null!=(a=t.performance)&&a.getEntriesByName){var i=n(t.performance.getEntriesByName(\"mark_axe_start\"))||n(t.performance.getEntriesByName(\"mark_audit_start\"));if(i)for(var l=t.performance.getEntriesByType(\"measure\").filter((function(e){return e.startTime>=i.startTime})),u=0;u<l.length;++u){var s=l[u];if(s.name===e)return void r(s);e||r(s)}else this._log(\"Axe must be started before using performanceTimer\")}},timeElapsed:function(\\\n){return Jf()-Uf},clearMark:function(){var e;if(null!=(e=t.performance)&&e.clearMarks){for(var n=arguments.length,r=new Array(n),a=0;a<n;a++)r[a]=arguments[a];for(var o=0,i=r;o<i.length;o++){var l=i[o];t.performance.clearMarks(l)}}},reset:function(){Uf=Jf()},_log:function(e){ia(e)}};function em(){var e,t,n,a;return r.elementsFromPoint||r.msElementsFromPoint||((e=r.createElement(\"x\")).style.cssText=\"pointer-events:auto\",e=\"auto\"===e.style.pointerEvents,t=e?\"pointer-events\":\"visibility\",n=e?\"none\":\"hidden\",(a=r.createElement(\"style\")).innerHTML=e?\"* { pointer-events: all }\":\"* { visibility: visible }\",function(e,o){var i,l,u,s=[],c=[];for(r.head.appendChild(a);(i=r.elementFromPoint(e,o))&&-1===s.indexOf(i);)s.push(i),c.push({value:i.style.getPropertyValue(t),priority:i.style.getPropertyPriority(t)}),i.style.setProperty(t,n,\"important\");for(s.indexOf(r.documentElement)<s.length-1&&(s.splice(s.indexOf(r.documentElement),1),s.push(r.documentElement)),l=c.length;u=c[--l];)s[l].style.setPrope\\\nrty(t,u.value||\"\",u.priority);return r.head.removeChild(a),s})}\"function\"==typeof t.addEventListener&&(r.elementsFromPoint=em());var tm=function(e,t){return e.concat(t).filter((function(e,t,n){return n.indexOf(e)===t}))};function nm(e,t,n,r,a){return(a=a||{}).vNodes=e,a.vNodesIndex=0,a.anyLevel=t,a.thisLevel=n,a.parentShadowId=r,a}var rm=function(e,t,n){if(r=Xp(e=Array.isArray(e)?e:[e],t=Hd(t),n))return r;for(var r=e,a=(e=t,n),o=Sl.get(\"qsa.recycledLocalVariables\",(function(){return[]})),i=[],l=nm(Array.isArray(r)?r:[r],e,null,r[0].shadowId,o.pop()),u=[];l.vNodesIndex<l.vNodes.length;){for(var s,c=l.vNodes[l.vNodesIndex++],d=null,p=null,f=((null==(s=l.anyLevel)?void 0:s.length)||0)+((null==(s=l.thisLevel)?void 0:s.length)||0),m=!1,h=0;h<f;h++){var g=h<((null==(g=l.anyLevel)?void 0:g.length)||0)?l.anyLevel[h]:l.thisLevel[h-((null==(g=l.anyLevel)?void 0:g.length)||0)];if((!g[0].id||c.shadowId===l.parentShadowId)&&Ud(c,g[0]))if(1===g.length)m||a&&!a(c)||(u.push(c),m=!0);else{var v=g.slice\\\n(1);if(!1===[\" \",\">\"].includes(v[0].combinator))throw new Error(\"axe.utils.querySelectorAll does not support the combinator: \"+g[1].combinator);(\">\"===v[0].combinator?d=d||[]:p=p||[]).push(v)}g[0].id&&c.shadowId!==l.parentShadowId||null==(v=l.anyLevel)||!v.includes(g)||(p=p||[]).push(g)}for(c.children&&c.children.length&&(i.push(l),l=nm(c.children,p,d,c.shadowId,o.pop()));l.vNodesIndex===l.vNodes.length&&i.length;)o.push(l),l=i.pop()}return u},am=function(e){var t,n,a,i;e=void 0===(e=e.treeRoot)?o._tree[0]:e;return t=[],e=rm(e,\"*\",(function(e){return!t.includes(e.shadowId)&&(t.push(e.shadowId),!0)})).map((function(e){return{shadowId:e.shadowId,rootNode:Ml(e.actualNode)}})),(e=tm(e,[])).length?(n=r.implementation.createHTMLDocument(\"Dynamic document for loading cssom\"),n=Tf(n),a=n,i=[],e.forEach((function(e,t){var n=e.rootNode,r=((e,t,n)=>{t=11===e.nodeType&&t?((e,t)=>Array.from(e.children).filter(om).reduce((function(n,r){var a=r.nodeName.toUpperCase();r=\"STYLE\"===a?r.textContent:r;ret\\\nurn(r=t({data:r,isLink:\"LINK\"===a,root:e})).sheet&&n.push(r.sheet),n}),[]))(e,n):(e=>Array.from(e.styleSheets).filter((function(e){return!!e.media&&im(e.media.mediaText)})))(e);var r=[];return t.filter((function(e){if(e.href){if(r.includes(e.href))return!1;r.push(e.href)}return!0}))})(n,e=e.shadowId,a);if(!r)return Promise.all(i);var o=t+1,l={rootNode:n,shadowId:e,convertDataToStylesheet:a,rootIndex:o},u=[];t=Promise.all(r.map((function(e,t){return Kf(e,l,[o,t],u)})));i.push(t)})),Promise.all(i).then((function e(t){return t.reduce((function(t,n){return Array.isArray(n)?t.concat(e(n)):t.concat(n)}),[])}))):Promise.resolve()};function om(e){var t=e.nodeName.toUpperCase(),n=e.getAttribute(\"href\"),r=e.getAttribute(\"rel\");n=\"LINK\"===t&&n&&r&&e.rel.toUpperCase().includes(\"STYLESHEET\");return\"STYLE\"===t||n&&im(e.media)}function im(e){return!e||!e.toUpperCase().includes(\"PRINT\")}var lm=function(e){return e=void 0===(e=e.treeRoot)?o._tree[0]:e,e=rm(e,\"video[autoplay], audio[autoplay]\",(function\\\n(e){return(\"none\"!==(e=e.actualNode).preload||0!==e.readyState||e.networkState===e.NETWORK_LOADING)&&!(e.hasAttribute(\"paused\")||e.hasAttribute(\"muted\")||(e.hasAttribute(\"src\")?!e.getAttribute(\"src\"):Array.from(e.getElementsByTagName(\"source\")).filter((function(e){return!!e.getAttribute(\"src\")})).length<=0))})),Promise.all(e.map((function(e){var t;e=e.actualNode;return t=e,new Promise((function(e){0<t.readyState&&e(t),t.addEventListener(\"loadedmetadata\",(function n(){t.removeEventListener(\"loadedmetadata\",n),e(t)}))}))})))};function um(e){var t={cssom:am,media:lm};return sm(e)?new Promise((function(n,r){var a=cm(e),o=a.assets,i=setTimeout((function(){return r(new Error(\"Preload assets timed out.\"))}),a.timeout);Promise.all(o.map((function(n){return t[n](e).then((function(e){return F({},n,e)}))}))).then((function(e){e=e.reduce((function(e,t){return O({},e,t)}),{}),clearTimeout(i),n(e)})).catch((function(e){clearTimeout(i),r(e)}))})):Promise.resolve()}function sm(e){return!e||null==e.pre\\\nload||(\"boolean\"==typeof e.preload?e.preload:\"object\"===a(e=e.preload)&&Array.isArray(e.assets))}function cm(e){var t=(n=oa.preload).assets,n={assets:t,timeout:n.timeout};if(e.preload&&\"boolean\"!=typeof e.preload){if(!e.preload.assets.every((function(e){return t.includes(e.toLowerCase())})))throw new Error(\"Requested assets, not supported. Supported assets are: \".concat(t.join(\", \"),\".\"));n.assets=tm(e.preload.assets.map((function(e){return e.toLowerCase()})),[]),e.preload.timeout&&\"number\"==typeof e.preload.timeout&&!isNaN(e.preload.timeout)&&(n.timeout=e.preload.timeout)}return n}function dm(e){var t=o._audit.data.checks||{},n=o._audit.data.rules||{},r=jp(o._audit.rules,\"id\",e.id)||{},a=(e.tags=Bd(r.tags||[]),pm(t,!0,r)),i=pm(t,!1,r);e.nodes.forEach((function(e){e.any.forEach(a),e.all.forEach(a),e.none.forEach(i)})),Hp(e,Bd(n[e.id]||{}))}function pm(e,t,n){return function(r){var o,i=(o=e[r.id]||{}).messages||{};delete(o=Object.assign({},o)).messages,n.reviewOnFail||void 0!==r.result?\\\no.message=r.result===t?i.pass:i.fail:(\"object\"!==a(i.incomplete)||Array.isArray(r.data)||(o.message=((e,t)=>{function n(e){return e.incomplete&&e.incomplete.default?e.incomplete.default:uf()}if(!e||!e.missingData)return e&&e.messageKey?t.incomplete[e.messageKey]:n(t);try{var r=t.incomplete[e.missingData[0].reason];if(r)return r;throw new Error}catch(r){return\"string\"==typeof e.missingData?t.incomplete[e.missingData]:n(t)}})(r.data,i)),o.message||(o.message=i.incomplete)),\"function\"!=typeof o.message&&(o.message=mf(o.message,r.data)),Hp(r,o)}}var fm=function(e,t){return rm(e,t)};function mm(e,t){var n,r=o._audit&&o._audit.tagExclude?o._audit.tagExclude:[],a=t.hasOwnProperty(\"include\")||t.hasOwnProperty(\"exclude\")?(n=t.include||[],n=Array.isArray(n)?n:[n],a=t.exclude||[],(a=Array.isArray(a)?a:[a]).concat(r.filter((function(e){return-1===n.indexOf(e)})))):(n=Array.isArray(t)?t:[t],r.filter((function(e){return-1===n.indexOf(e)})));return!!(n.some((function(t){return-1!==e.tags.indexOf(t)})\\\n)||0===n.length&&!1!==e.enabled)&&a.every((function(t){return-1===e.tags.indexOf(t)}))}var hm=function(e,t,n){var r=n.runOnly||{};n=(n.rules||{})[e.id];return!(e.pageLevel&&!t.page)&&(\"rule\"===r.type?-1!==r.values.indexOf(e.id):n&&\"boolean\"==typeof n.enabled?n.enabled:\"tag\"===r.type&&r.values?mm(e,r.values):mm(e,[]))};function gm(e,t){var n,r,a;return t?(a=e.cloneNode(!1),n=Na(a),a=1===a.nodeType?(r=a.outerHTML,Sl.get(r,(function(){return vm(a,n,e,t)}))):vm(a,n,e,t),Array.from(e.childNodes).forEach((function(e){a.appendChild(gm(e,t))})),a):e}function vm(e,t,n,a){return t&&(e=r.createElement(e.nodeName),Array.from(t).forEach((function(t){var r,o,i;r=n,o=t.name,void 0!==(i=a)[o]&&(!0===i[o]||Ta(r,i[o]))||e.setAttribute(t.name,t.value)}))),e}function bm(e,t){var n=[];if(o._selectCache)for(var r=0,a=o._selectCache.length;r<a;r++){var i=o._selectCache[r];if(i.selector===e)return i.result}for(var l,u=t.include.reduce((function(e,t){return e.length&&Vp(e[e.length-1],t)||e.push(t),e}),[]),s=(l\\\n=t).exclude&&0!==l.exclude.length?function(e){return zf(e,l)}:null,c=0;c<u.length;c++){var d=u[c];n=((e,t)=>{if(0===e.length)return t;var n;e.length<t.length&&(n=e,e=t,t=n);for(var r=0,a=t.length;r<a;r++)e.includes(t[r])||e.push(t[r]);return e})(n,rm(d,e,s))}return o._selectCache&&o._selectCache.push({selector:e,result:n}),n}function ym(e){var t=1<arguments.length&&void 0!==arguments[1]?arguments[1]:0;if(\"object\"!==a(e)||null===e)return{message:String(e)};var n,r={},o=K(oa.serializableErrorProps);try{for(o.s();!(n=o.n()).done;){var i=n.value;[\"string\",\"number\",\"boolean\"].includes(a(e[i]))&&(r[i]=e[i])}}catch(e){o.e(e)}finally{o.f()}return e.cause&&(r.cause=t<10?ym(e.cause,t+1):\"...\"),r}function Dm(e){var t,n,r=e.error,a=e.ruleId,o=e.method;e=e.errorNode;return H(this,Dm),(n=R(this,Dm)).name=null!=(t=r.name)?t:\"RuleError\",n.message=r.message,n.stack=r.stack,r.cause&&(n.cause=ym(r.cause)),a&&(n.ruleId=a,n.message+=\" Skipping \".concat(n.ruleId,\" rule.\")),o&&(n.method=o),e&&(n.errorNode=e)\\\n,n}S(Dm,function(e){var t=\"function\"==typeof Map?new Map:void 0;return function(e){if(null===e||!(e=>{try{return-1!==Function.toString.call(e).indexOf(\"[native code]\")}catch(t){return\"function\"==typeof e}})(e))return e;if(\"function\"!=typeof e)throw new TypeError(\"Super expression must either be null or a function\");if(void 0!==t){if(t.has(e))return t.get(e);t.set(e,n)}function n(){return C(e,arguments,T(this).constructor)}return n.prototype=Object.create(e.prototype,{constructor:{value:n,enumerable:!1,writable:!0,configurable:!0}}),_(n,e)}(e)}(Error));var wm=W(Dm),xm=function(e){e.forEach((function(e){var n=e.elm,r=e.top;e=e.left;if(n===t)return n.scroll(e,r);n.scrollTop=r,n.scrollLeft=e}))};function Em(e){return function e(t,n){var r=t.shift();return n=r?n.querySelector(r):null,0===t.length?n:null!=n&&n.shadowRoot?e(t,n.shadowRoot):null}(Array.isArray(e)?M(e):[e],r)}function Am(e){var t=1<arguments.length&&void 0!==arguments[1]?arguments[1]:r,n=Array.isArray(e)?M(e):[e];return 0===e.l\\\nength?[]:function e(t,n){t=function(e){return $(e)||P(e)||X(e)||G()}(t);var r=t[0],a=t.slice(1);if(t=n.querySelectorAll(r),0===a.length)return Array.from(t);var o,i=[],l=K(t);try{for(l.s();!(o=l.n()).done;){var u=o.value;null!=u&&u.shadowRoot&&i.push.apply(i,M(e(a,u.shadowRoot)))}}catch(e){l.e(e)}finally{l.f()}return i}(n,t)}var Fm=function(){return[\"hidden\",\"text\",\"search\",\"tel\",\"url\",\"email\",\"password\",\"date\",\"month\",\"week\",\"time\",\"datetime-local\",\"number\",\"range\",\"color\",\"checkbox\",\"radio\",\"file\",\"submit\",\"image\",\"reset\",\"button\"]},Cm=[,[,[1,1,1,1,1,1,1,1,1,1,,1,1,1,1,1,1,1,,1,1,1,1,1,1,,1],[1,1,1,1,1,1,1,1,1,1,1,,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[,1,1,,1,1,1,,1,1,,1,1,1,1,,1,1,1,1,1,1,1,1,1,1,1],[,1,1,,1,1,1,1,1,1,1,,1,,1,1,1,1,1,1,1,1,,1,1,1,1],[1,1,1,1,1,1,,,,,,1,1,1,1,,,1,1,1,,1,,1,,1,1],[1,1,1,,1,1,,1,1,1,,1,,,1,1,1,,,1,1,1,,,,,1],[,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[,1,1,,,,,1,1,1,,1,1,1,1,1,1,,1,1,1],[,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,,,1,1,1],[,1,,,,,\\\n,1,,1,,,,,1,,1,,,,1,1,,1,,,1],[1,,1,1,1,1,1,1,1,1,1,1,1,1,,1,1,1,1,1,1,1,1,1,1,1,1],[,1,,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,,1,1,1,,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[,1,1,1,1,1,1,1,1,1,1,1,1,1,1,,,,1,1,1,1,,,1,,1],[,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[,1,,1,1,,,1,,,,,1,1,1,,1,,1,,1,,,,,,1],[1,,1,1,1,1,,,1,1,1,1,1,,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,,1,1,1,1,1,1,1,1,1,1,1,1,1],[,1,1,1,1,1,,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,,1,1,1,1],[1,,1,,1,,,,,1,,1,1,1,1,1,,,,1,1,1,1],[,1,1,1,1,1,,1,1,1,,1,,1,1,1,,,1,1,1,1,1,1,1,1],[,,1,,,1,,1,,,,1,1,1,,,,,,,,,,,1],[1,1,1,1,1,1,,1,1,1,,1,1,,1,1,1,1,1,1,1,1,,,1,1,1],[1,1,1,1,1,,,1,,,1,,,1,1,1,,,,,1,,,,,,1]],[,[1,1,1,1,1,1,1,1,1,1,1,,1,,1,1,1,,1,1,1,1,1,1,1,1,1],[,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,,1,1],[,1,1,1,1,1,1,1,\\\n1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,,1,,1,1,1,1,1,1,1,1,1,1,1,1],[,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,,1,1,1,1],[1,1,1,1,1,1,1,1,,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,,,1,1,1,1,1,1,1,1,1,,1,1,1,1,1,1,1],[,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[,1,1,1,1,,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,,,1,1,1,1,1,1,1,1,1,1,1,1,1,1,,1,1,1,1,1,1,1],[,1,1,,1,,,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[,1,1,1,1,,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[,1,1,1,1,1,1,1,1,1,1,1,,1,1,1,1,1,,1,1,1,1,1,1,1,1],[,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,,1\\\n,1,1,1,1,1,1],[,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,,1,1,1,1],[,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,,1,1,1,1,,1],[,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,,1,1,1,1,1],[,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]],[,[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,,1,1,1,1,1,1],[,1,1,1,1,1,,1,1,1,1,1,1,,1,1,,1,1,1,1,1,1,1,,1],[,1,,1,1,1,,1,1,,1,,1,1,1,1,1,1,1,1],[,1,,1,1,1,1,1,1,1,1,,,1,1,1,,,1,1,,,,,,1,1],[1,1,1,,,,,1,,,,1,1,,1,,,,,,1,,,,,1],[,1,,,1,,,1,,,,,,1],[,1,,1,,,,1,,,,1],[1,,1,1,1,,1,1,1,,1,1,1,1,1,1,1,1,1,,1,,,1,1,1,1],[,1,1,1,1,1,,,1,,,1,,1,1,,1,,1,,,,,1,,1],[,1,,,,1,,,1,1,,1,,1,1,1,1,,1,1,,,1,,,1],[,1,1,,,,,,1,,,,1,1,1,1,,1,1,1,1,1,1,,1,1,1],[,1,,1,1,1,,,1,1,1,1,1,1,,1,,,,,1,1,,1,,1],[,1,,1,,1,,1,,1,,1,1,1,1,1,,,1,1,1],[,1,1,1,,,,1,1,1,,1,1,,,1,1,,1,1,1,1,,1,1],[1,1,1,1,1,1,1,1,1,,1,1,1,1,1,1,1,1,,,1,1,1,1,1,1,1],[,1,1,1,,1,1,1,,1,,,,,1,1,1,,,1,,1,,,1,1],[,,,,1,,,,,,,,,,,,,,,,,1],[1,1,1,1,1,,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1\\\n,1,1,1,1,1,1,1,1,,1,1],[,1,,1,1,1,,1,1,,,,1,1,1,1,1,,,1,1,1,,,,,1],[1,1,1,1,,,,1,1,1,1,1,1,1,,1,1,1,1,1,1,1,1,1,1,1],[1,,,,,,,1,,,,,,,1],[,1,1,,1,1,,1,,,,,,,,,,,,,1],,[1,1,1,,,,,,,,,,,,,1],[,,,,,,,,1,,,1,,,1,1,,,,,1]],[,[1,1,,1,1,1,1,1,1,1,1,1,1,1,,1,1,1,1,1,,1,1,1,1,1,1],[,1,1,,1,1,1,1,,1,1,,1,1,1,1,1,1,1,,1,1,1,1,,1],[,,,1,,,,,,,,,,,,,,,1],[,1,,,1,1,,1,,1,1,,,,1,1,,,1,1,,,,1],[1,,,1,1,1,1,1,1,1,,1,1,1,1,,1,1,1,1,,,1,,,,1],,[,1,1,1,1,1,,1,1,1,,1,1,,1,1,,,1,1,1,1,,1,1,,1],[,1,,,1,,,1,,1,,,1,1,1,1,,,1,1,,1,1,1,1],[,1,1,1,1,,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,,1,1,1,1],[,1,1,1,1,1,1,,,1,1,1,1,1,1,1,,,1,,,1,,1],[,1,,,,,,,,,,1,1,,,,,,1,1,,,,,1],[,,,,,,,1,,,,1,,1,1],[,1,1,1,1,1,1,1,,,,1,1,1,1,1,,,1,1,,1,1,1,1,1],[,1,,,1,1,,1,,1,1,1,,,1,1,,,1,,1,1,1,1,,1],[,1,1,1,,1,1,,1,1,,1,1,,1,1,1,1,1,1,1,,1,1,1,1,1],[,,,,,,,,,,,,,,,,1],,[,1,1,1,1,1,,1,1,1,,,1,,1,1,,1,1,1,1,1,,1,,1],[,,1,,,1,,,1,1,,,1,,1,1,,1],[,1,1,,1,,,,1,1,,1,,1,1,1,1,,1,1,1,1,,,,1],[,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,,1,1,1,1,1,1],[\\\n1,1],[,1,,,,,,,,,,1,1,,,,,,1,1,,1,,1,,1,1],,[,1,1,,1,,,1,,1,,,,1,1,1,,,,,,1,,,,1],[1,1,,,1,1,,1,,,,,1,,1]],[,[,1],[,,,1,,,,1,,,,1,,,,1,,,1,,,1],[,,,,,,,,,,,,,,,,,,1,1,,,,,,1],,[1,,,,,1],[,1,,,,1,,,,1],[,1,,,,,,,,,,,1,,,1,,,,,,,,,1,1],[,,,,,,,,,,,,,,,,,,,,,1],[,,,,,,,,,,,,,,,,1,,,,1,,1],[,1],[,1,,1,,1,,1,,1,,1,1,1,,1,1,,1,,,,,,,1],[1,,,,,1,,,1,1,,1,,1,,1,1,,,,,1,,,1],[,1,1,,,1,,1,,1,,1,,1,1,1,1,,,1,,1,,1,1,1],[1,1,1,1,1,,1,,1,,,,1,1,1,1,,1,1,,,1,1,1,1],[1,,,,,,,,,,,,,,,,,,,,1],[,,,,,,,,,1],,[,1,,,,,,1,1,1,,1,,,,1,,,1,1,1,,,1],[1,,,,,1,,1,1,1,,1,1,1,1,1,,1,,1,,1,,,1,1],[1,,1,1,,,,,1,,,,,,1,1,,,1,1,1,1,,,1,,1],[1,,,,,,,,,,,,,,,,,1],[,,,,,1,,,1,,,,,,1],[,,,,,,,,,,,,,,,1],[,,,,,,,,,,,,,,,,,,,,1],[,1,,,,,,,,,,,,,,1],[,1,,,,1]],[,[1,1,1,,1,,1,1,1,1,1,1,1,1,1,,1,,1,,1,1,,,1,1,1],[,,,,,,,,,,,,1],[,,,,,,,,,,,,,,,,,,,1],,[,,,,,,,,,,,,,,,,,,1],[1,,,,,,,,,1,,,,1],[,,,,,,,,,,,,,,,,,,1],,[1,1,,,,1,1,,,,,,1,,,,1,,1,,1,1,,1],[1],[,,,,,,,,,,,1,,,,,,,,,,,1],[,1,,,,,,,1,1,,,1,,1,,,,1,,,,,,,1],[,,,,,,,,,,,\\\n,,,,,1,,,,,1],[,,1,,,,,1,,1],[1,,,,1,,,,,1,,,,1,1,,,,1,1,,,,,1],[,,,,,1],[,,,,,,,,,,,,,,,,,,,1],[1,,,1,1,,,,,,,1,,1,,1,1,1,1,1,1],[,,,,,1,,,,,,,1,,,,,,,1],,[,,1,1,1,1,1,,1,1,1,,,1,1,,,1,1,,1,1,1,,,1],[,,,,,,,,,,,,,,,,,,1],[,1,,,,1],,[1]],[,[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,,1,1,1,1,1,1],[,,,1,1,1,1,,,,,,1,,1,,,,1,,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,,1,1,1,1,1,,,1],[,1,1,1,1,,1,1,1,1,1,1,1,1,,,,1,,1,,,1,1,1,1,1],[,,,,,,,,,,,1,,,,,,,,,1,,,,1],[,1,1,,1,1,,1,,,,1,1,,1,1,,,1,,1,1,,1],[,1,,1,,1,,,1,,,1,1,,1,1,,,1,1,1],[,1,1,1,1,1,,1,1,,,,1,1,1,1,1,1,1,1,1,1,,1,1,1,1],[,,,,,,,,,1,,1,,1,1,,,,1,,,1],[,1,,,1,1,,,,,,,,,1,1,1,,,,,1],[1,,,1,1,,,,1,1,1,1,1,,,1,,,1,,,1,,1,,1],[,1,1,,1,1,,1,1,,,,1,1,1,,,1,1,,,1,1,1,1,1,1],[1,1,1,1,1,1,,1,1,1,1,1,1,1,1,1,,1,1,,1,1,,1,,,1],[,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,,1,1,1,1],[,1,,,,1,,,,,,,,,1],[,1,,,,,,,,1,,,,,1,,,,1,,,1],[,1,1,1,1,,,1,1,1,1,1,,1,,1,,1,1,1,1,1,1,1,1,1,1],[,,,,,1,,1,,,,,1,1\\\n,1,1,1,,,1,,,,1],[,1,,,,,,,,1,,,,,,,,,,,,1],[1,1,1,1,1,1,1,1,1,1,,1,1,1,1,1,1,1,1,1,1,1,1,1,1,,1],[1,1,,1,,1,1,,,,1,,1,1,1,1,1,,1,1,,,,,,1],[,1,1,1,1,1,1,1,,1,1,,,1,1,,,,1,,1,1,,1,1],[,,,,,,,,,,,,,,,,,,,,,,,,1],[,1,1,,1,1,1,1,,1,,,1,1,1,1,,,1,,,,,,,1],[,1,,,,,,,,1,,,,,1]],[,[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,,,1,1,1,1,1],[,1,1,,,,,,,,,,,,1,1,,,,,,1],[,1,,,,,,,1],[,,,,,,,,,,,,,,1,,,,,1,,,,,,1],[1,1,,,1,,,1,1,1,,,,1],,[,,,,,,,,,,,,,1,,,,,,,,,,1],[,,,,,,,,,1,,,,,,,,,1,,,,,,,1],[1,1,1,,1,,1,1,1,1,1,1,1,1,,1,,,1,,1,,,1,1],[,,,,,,,,,1],[,1,,,,1,,,,,,1,,,1,,,,,1],[,1,1,,1,1,,,,,,,,,,,,,,,1,1],[,1,1,1,1,1,1,1,1,1,1,1,1,1,1,,1,1,1,1,1,1,1,1,1,1,1],[,1,,,1,1,,1,1,1,1,,,,1,1,,,,1,,1],[1,1,1,1,1,1,,,1,1,1,1,1,1,,1,1,,1,1,1,,1,1,,1,1],[,,,,,,,,,,,,,,,1,,,,1],,[1,1,,1,,1,,,,,,1,,1,,1,1,,1,,1,1,,1,1,,1],[,,1,,,,,,1,,,,1,,1,,,,,1],[1,,,,,,,,,1,,,,,,1,,,,1,,1,,,1],[1,,1,1,1,1,1,1,1,1,1,1,1,1,,1,1,1,1,1,1,1,1,1,1,1,1],[,,,1,,1,,,,,,1,,,1,,,,,,,,1],[,1,,1,,,,,,,,,,,,1],,[1,1,,,,,,,,,,,,,,,,,,,,,,1,\\\n1],[1]],[,[1,,,,,,,,,1,,,,,1,,1,,1],[,1,1,,1,1,,1,1,1,,,1,1,1,,,,1,,,1,,,,1],[,1,,,,,,,1,,,,1,,,,,,1],[1,1,1,1,1,1,,,,1,,,,,,,,,1,1,1,1],[1],[,1,1,,,1,1,,,,,1,,1,,,,,,,,1,,,,1],[1,,1,,,1,,1,,,,,1,1,1,1,,,,1,,,,1],[,,1,,,,,,,1,,,,,,,1,,,,,,,1],[1,,,,,,,,,,,,,,1,,,,1],[,,,1,,1,,,,,1,,,,1,1,,,,1],[1,,,,,1,,,,1,,1,1,,,1,1,,1,1,1,,1,1,1,,1],[,1,1,,,,,1,,1,,1,1,1,,1,1,,,1,,1,1,1],[,1,,,,1,,,,1,,,1,,1,1,,,1,1,,,,,,1],[1,,1,1,,1,,1,1,,1,,1,1,1,1,1,,,1,1,,,,,,1],[1,,,,,,,,,,,,,,,,,,1,,,1,,1],[,,,,,,,,,1,,,,,,1],[,,,,,,,,,,,,,,,,,,,,,1,,1],[,1,,,,1,,,1,1,,1,,,1,1,,,1,,,1,,,1,1],[1,1,,1,1,1,,1,1,1,,1,,1,1,1,,,1,,1,1],[1,,1,1,1,1,,,,1,,1,1,1,,1,,,1,1,1,,1,1,1,1,1],[1,,,,,,,,,,,,,1],[,,1,,,,,,,,,,,,,,,,,,,,1],[1,,,,,,,,,,,1,,1,,1,,,,1],[,,,1,,,,,,,,,1],[,1,,,,,,,,,,,,,,1,,,,,,,,,1],[,,,,,,,,1,1,,,,,,,,,1,,,,,,,,1]],[,[1,1,1,1,1,1,1,,1,,1,1,1,1,1,1,,1,1,1,1,1,,,1,1,1],[,,,,,1,,,,1,1,1,,,1,1,,,1,,1,1,,1],[,,,,,,,,,,,,,,,,,,,1,1],[,1,,,,,,1,,,,,,,,,,,,,1],[,,1,,,1,,1,1,1,,1,1,,1,,,,1,,1,1],,[,,1,,,1,,\\\n,,,,1,,,,1],[,,,,,,,,,1,,,,,,,,,,1],[1,1,1,1,1,1,,1,1,1,,,1,1,,1,,1,,,1,1,1,,,1],[,,,,,1,,,,,,,,,,,,,1],[,1,,,,,,,,,,,,1,,1,1,,1,,,1],[,,,,,1,,,,,,,,,,,,,,1],[,1,1,1,1,,,,,1,,,1,,1,,,,1,1,,,,1,1],[,1,,,1,,,1,,1,1,,1,,,,,,,1],[,,1,,1,,,1,,,,,,,,,,,1,1,,,,1],[,1,,,,,,,,,,,,,,,,,1,,,,,,1],[,,,,,,,,,,,,,,,,,,1],[,1,1,,,,,,,,,,,,,,,,1,,1,1],[,,,,,,,,,,,,1],,[,1,1,1,1,,,,1,1,,1,1,1,1,1,1,,1,1,1,1,,1,,1],[1,,,,1,,,,,,,,,,1],[1,,,,,,,,,1],,[,1,,,,1,,,,,,,,,,,,,,,,,,,,1]],[,[1,1,1,1,1,1,1,1,1,1,1,1,,1,,1,1,1,1,,,,1,1,1,1],[,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[,1,,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,,1,1,1,1,1,1,1],[,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[,1,1,1,1,1,1,1,1,1,1,1,1,,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,,1,1,,1,1,1,,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,\\\n,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,,1,1,1,1,1,1,1,1,1,1,,,1,1,1,,1,1,1,1,1,1,1,1],[,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,,1,1,1,1,1,1,1,1,1,,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[,1,1,1,1,1,1,,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]],[,[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,,1,1,1,1,,1,,1,1,1,1],[1,1,1,1,,1,1,1,,1,1,1,1,1,1,1,,1,1,1,1,1,1,1,1,1,1],[,\\\n,,1,1,1,1,,1,,,,1,1,,,1,1,,1],[,1,1,,1,,,1,1,1,1,1,1,1,1,1,1,1],[,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[,1,,,,,,,,,,,,,1],[1,1,1,,,,,1,1,1,,1,1,1,1,,,1,1,,1,1,,,,,1],[,1,,,,,,,1,1,,,1,1,1,,1,,,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,,,1,1,1,1,1,,1,1,1,1,1,1],[,1,,,,1,,,,1,,,1,,,,1,,,,,,,1,1],[,1,1,1,1,1,,,1,1,1,,1,1,1,1,,,1,1,1,1,,,,1],[,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,,1,,1,,,1],[,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,,,1,1,1,1,1,1],[1,1,1,,1,,,1,1,1,1,,1,1,1,1,,,,1,,1,,1,,,1],[1,1,1,1,,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[,1,,,,1,,,,,,,,,1,1,,,,,,,,,1],,[,1,,1,,1,,1,,1,,1,1,1,1,1,,,1,,1,,1,,,,1],[,1,,,1,1,,1,1,1,,,1,1,1,1,1,,1,1,1,,1,,,1],[1,,,1,,,,1,1,1,,,,,1,1,,,,1,,1],[1,1,,1,1,1,1,,,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,,1,1],[1,1,,,,,,,,1,,1,,,,,,,,1,,1],[,1,,,,1,,1,1,,,,1,1,,1,,,,1,1,1,,1],,[,1,,,,,,1,,,,,,,1],[,,,,,,,,1,,,,1,,1,,,,,,,,,,,,1]],[,[,1,1,,1,1,1,1,,1,1,1,,1,1,,1,1,,1,1,1,1,1,1,,1],[,1,1,1,1,1,1,,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[,1,1,1,1,1,1,1,1,1,\\\n1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[,1,1,1,1,1,1,1,1,1,1,1,1,1,1,,1,1,1,1,1,1,1,1,1,1,1],[,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,,1,1],[,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,,1,1,1,1],[,1,1,1,1,1,,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,,1,1,1,1,1,1,1,1,1,1,1,1,,1,1,1,1,,1],[,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,,1,1,1,1,1,1,1,1,1,,1,,1,1,1,1,1,1,1,1,1,1,1,1],[,1,1,1,1,1,,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[,1,1,1,,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[,1,1,1,1,1,,1,1,1,1,1,1,1,1,1,1,1,1,1,\\\n1,1,1,,1,1,1],[,1,1,,1,1,1,1,1,1,,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[,1,1,1,1,1,,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]],[,[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,,,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,,1,1,1,1,1,1,1,1,1,1,1,1,1],[,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,,,1,,1],[1,1,1,1,1,,1,1,1,1,1,1,1,1,1,,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,,1,1,1,,1,1,1,1,1,1,1,1,1,1],[,1,,,1,,,,,,,,1,,,,,,1,,,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[,1,1,1,1,1,1,1,1,1,,1,,1,1,1,1,1,1,,1,1,1,1,1,1,1],[,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,,1,1,1,1,1,1,1,1,1,1],[,1,1,,1,,,,1,1,1,,1,1,1,1,,,1,1,1,1,,,1,1,1],[,1,1,1,1,1,1,1,1,1,1,1,,1,1,1,1,1,1,1,1,1,1,1,1,,1],[1,1,,1,,1,,1,,1,1,1,1,1,1,1,,1,1,,,1,1,1,1,1,1],[,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,,1,1,1,1,1,1,1,1,1,\\\n1,1],[1,1,,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,,1,1,1,1,1,,1,1],[,1,1,,,,,1,1,1,,,1,,1,1,,,,1,,1,,,1,1],[,,,,,,,1,,,,1,1,1,1,1,,1,,,,,,,,1],[1,1,1,1,,1,1,1,,1,,1,1,1,1,,1,,1,,1,1,,,1,,1],[,1,1,1,1,1,1,1,1,1,,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[,,,,1,1,,1,,1,1,1,,1,,1,1,,1,1,,1,,1,1,1,1],[,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,,,,,,,,1,,,,,1,,1],[,1,1,1,,1,,1,,1,,,,1,,1,,,1,,,,,,1,1],[,1,,,1,1,,1,,1,,1,1,1,1,1,,1,1,,,1,,,1],[1,,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[,1,1,,1,,,,,1,,1,,1,,,,,,1,,1,,,,1,1]],[,[,1,,1,,,,,,,,,,,,,,,1,,,,1],[,,,,,,,,,1,,1,1,1,,1,,,1,,1,1],[1,1,,,,,,,1,,,,,,,1,,,,,,1],[,1,,,,,,,,,,1,,,,,,,,,1,1],,[,,,,,,,,,,,,,,,1,,,,1,,1],[,,1,1,,1,,1,,,,,,,,1,,,,,,1],[,,,,,,,,,,,,,,,,,,,,1,1],[,1,,,,,,,,,,,,,1],[1,,1,1,,,,1,,,,,,,,,1,,,1,,,1,1],[,1,1,,1,1,,1,1,1,1,1,1,1,1,1,,,1,1,,1,1,,1],[,1,,,1,1,,,,,,1,,1,,1,,,1,,1,1],[1,1,1,1,,1,,1,,1,,1,1,,1,1,1,1,1,,1,1,1,1,1],[,1,1,,,1,,1,,1,1,1,,,1,1,1,,1,1,1,1,,1,1],[,,,,1,,,1,,,,,,,1,,,,1,1],[,1,,,,,,,,,,1,,1,,\\\n1,,,,,1,,,,,1],,[1,1,,1,,1,,1,1,,,,,,1,1,,,1,1,1,1,1,1,1,1,1],[1,1,,1,,,,,,1,,,,,,1,1,,,,1,1,,,1],[,1,1,,1,1,,,,1,,1,1,1,1,1,,1,1,1,1,1,,1,1,1,1],[,1,1,,,1,,,,1,,,,1,1],[,,,,1],[,,,,,,,,,1,,,1],,[,,1,,1,,,,,,,,,1,,,,,,,,,,,,1],[,,,,,,,,,,,,,1]],[,[1,1,1,1,1,1,1,1,1,1,,1,1,1,,1,1,1,1,1,1,1,1,1,1,1,1],[,,1,1,,1,1,1,1,1,,,1,1,1,1,1,,1,1,1,1,1,,,1,1],[,1,1,1,1,1,1,1,1,1,1,1,1,1,1,,1,,1,,,,,1],[,1,,1,,,,,,1,,,,,1,1,,,,,1,1],[,1,1,,1,1,1,1,1,1,1,1,1,1,,1,1,1,,1,,,1,,1,1,1],[,1,,,,1,,,,,,,1],[,1,,,1,,,1,,1,,1,1,,1,,,,,1,,1,,,,1,1],[,1,,,1,,,1,1,1,,1,1,1,1,1,,1,1,,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,,1,1,1,1,1,,1,1,1,1,1,1,1,1,1],[,,,,,,,,,,,,,,,,,,,,1],[,1,1,1,,,,1,1,,,,,,1,1,1,,1,1,1,1],[1,1,1,1,1,1,1,1,1,,1,1,1,,1,1,1,1,1,1,1,1,1,1,,1,1],[,1,1,1,1,1,1,,1,1,1,1,1,1,1,1,,1,1,1,1,1,,1,1,1,1],[,1,1,1,1,1,,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[,,,1,1,1,1,1,1,1,,1,,1,1,1,1,1,,1,1,,1,1,1,1,1],[,1,,,,1,,,,1,,1,1,1,1,1,1,1,1,1,1,1],[,1,,,,1,,,,,,,,1,,,,,,,,,,1],[,1,1,1,1,1,1,1,1,1,,1,1,1,1,1,1,1,1,1\\\n,1,1,,1,1,1,1],[1,1,,1,1,1,,1,1,1,,,1,1,1,1,1,1,1,1,1,1,,1,,1],[1,1,,,,,,,1,1,,,,,1,1,1,1,1,,1,1,1,1,,1],[,1,1,1,1,1,1,1,,1,1,1,,1,,1,1,1,1,,1,1,,1,1,1,1],,[,1,1,,,,,1,,1,,,,1,1,1,,,1,,,,,1],[,,,,,,,,,,,,,1],[,,,,,1,,,,,,,,1,1,,,,,1,,1,,,1,1],[,,,,,,,,,,,,,,1]],[,[,1],,,,,,,,,,,,,,,,,,,,[1,1,1,1,1,,1,1,1,1,,1,1,1,1,,1,1,1,1,,,1,1,1,1,1],[,1,,1,,1,,,1,1,1,,1,1,1,1,1,,,1,,,,1,,1,1],[,1,,1,,1,,,1,,,,,1,,,,,,1,1],[,1,,1,,,,,1,,,,1,,1,1,1,1,1,1,1,1,,1],[,1,,,,,,,,,,,,,,,1]],[,[,1,1,1,1,,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[,,1,,,,,,,,,1,1,,,,1],[,,,,,,1],[,,1],[,1,1,,,1,,1,,1,1,,1,1,1,,,,1,1,1,,,,,1],,[,1,,,,1,,,,,,1,,,1,,,,1,1,,1],[,,,,,,,1,,,,,,,,,1],[,1,,,,1,1,,,,,,1,1,1,,,,1,,1,1],[,,,,,,,1,,1,,,,,,,,,,1],[,1,1,,,,,,1,1,,,,1,,,,,,,1,,,1],,[1,1,1,1,1,1,1,1,1,1,,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,,,1,,,1,,,,,1,,1,,1,,1,,,,,1],[1,1,1,1,1,1,1,1,,,,,1,1,,1,1,,1,,,1,,1],[,,,,,,,,,,,,,,1,,,,,,1],,[,,,,,,,,,1,,,,,,1,,,,,1],[,,1,,,,,,,1,,,1,1],[,,,1,,,,,1,,,,,1,,,,,,1,,,,1],[1,,1,1,,1,\\\n1,1,1,1,,1,,,,1,1,1,,,1,1,,,,1,1],,[1,1,,,,,,,,,,1,,1,,1,,,1],[,,,,1,,,,,,,,,,,,,,,,,,,1],[,,,,,,,,,,,,,,1,,,,,1,,1],[,,,,,,,,1]],[,[1,1,1,1,1,1,1,,1,1,1,1,1,1,,1,1,1,1,1,1,1,1,1,1,1,1],[,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,,,1,1,1,1,1,,1,1,,1,1,1,1,,1,1,1,1,1,1],[1,1,1,1,,1,1,1,1,,1,1,1,1,1,1,1,1,1,1,1,1,1,,1,,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,,1,1],[,,1,,,1,,,,,,,,1,,,,,,1,,,,1],[1,1,1,1,1,1,,1,1,1,1,1,1,1,1,1,1,,1,1,1,1,,1,1,1,1],[1,1,1,1,1,1,,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,,1,1,1,1,1,1,1,1,1,1,,1,1,1,1,1,1,1,1,1,1,1,1],[,1,1,,1,1,,1,,,,1,1,1,1,1,1,,1,1,1,1,,1],[1,1,1,1,1,1,1,1,1,1,1,1,,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,,1,1,1,1,1,1,1,1,,1,1,1,,1,1,1,1,1,1,,1,1,1,1],[1,1,1,1,1,,1,1,1,1,1,1,1,1,1,,1,1,1,1,1,1,1,1,1,1,1],[1,,1,1,,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,,1,1,1,1,1,1],[1,1,1,1,1,1,,1,1,1,1,1,1,,1,1,1,1,1,1,,1,1,1,1,1,1],[,,1,1,1,1,,1,,1,,1,1,1,1,1,1,1,1,1,1,1,1,,1,1],[1,1,,,,,,,1,,1,1,,1,1,1,,1,1,1,1,1],[1,1,1,1,,1,1,1,1,\\\n1,,1,1,1,1,1,,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,,1,1,1],[1,1,1,,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,,1],[1,1,1,1,,1,,1,,1,1,1,1,1,,,,1,1,1,1,,1,1,1,1,1],[1,1,1,1,,1,,,,,,1,,1,,,,,1,1,,,,,1],[1,,1,1,,,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[,,1,1,,1,,1,,,,1,1,1,1,1,,,1,1,,1,,1],[,1,1,1,1,,,,,1,,1,1,1,1,1,,,1,1,,,,1,1,1],[,1,1,1,1,1,,1,,,,,1,,1,,1,,,1,,,1,1,,1]],[,[1,1,1,1,1,1,1,1,,1,1,1,1,,1,1,1,1,1,1,,1,1,1,1,1,1],[,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[,1,1,1,1,1,1,1,1,1,,1,1,1,1,1,1,1,,1,1,1,,1,1,1,1],[,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,,1,1,1,1,1,1,,1,1],[1,1,1,1,1,1,1,1,1,1,,1,,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[,,,,,,,,,1,,,,,1,1,,,1,,1],[1,1,1,1,1,1,1,1,1,1,1,,,,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,,,1,1,1,1,,1,1,,1,1,1,1,,1,1,1,1,1,1,1,1,1,1,1],[1,1,,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,,1,1,1,1,1,1,1,1],[,1,,,,,,1,,1,1,,1,1,1,1,1,,,1,,1,,1],[1,1,1,,1,1,1,1,,,,1,1,1,1,,1,1,1,1,1,1,1,1,1,,1],[1,1,1,1,1,,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[,1\\\n,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,,1,1],[1,1,1,1,1,1,1,1,1,1,,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,,1,1,1,1,1,1,1,1,1,,1,1,,1,1,1,1,1,,1,1,1,1,1,1],[,1,,1,,1,1,1,,1,1,1,1,1,1,1,1,1,1,,1,1,1,1,1,1,1],[,,1,,,,,,,,,,1,1,1,1,1,1,1,,1,1,,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,,,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,,1,1],[,1,1,1,1,1,1,1,1,1,1,,1,1,1,1,1,1,,1,1,1,1,1,1,1,1],[,1,,,1,1,,,,,,1,1,1,1,1,,,,1,1,1,,1,1,1],[1,1,1,1,1,1,1,1,1,,,,1,1,1,1,1,1,1,,1,1,,1,1,1],[,1,1,1,,1,,1,1,1,1,,,1,1,1,,1,1,1,1,1,,,1,1],[1,1,,,,1,,,1,1,1,,1,,1,,1,,1,1,1,1,1,,1,,1],[,1,,,,,,,1,,1,,1,1,1,1,,,,,,,,,1]],[,[,,,,,,,,,,,,,1,1,,,,1],[,1,,,,,,,,1,,,1,,,,,,1,,,1,,,,1],,[,1,,,,1,,1,,1,1,,1,1,,,,,,,,1],[,,,,,,,,,,,,,,,,,,,1],[,,,,,,,,,1],[1,1,1,,,1,,,,,,,,,1,1,,,,,,,,,,1],[,1,,,,,,,,,,,,,1],[,,,,,,,,,,,,,,,,,,,1,,,1],[,,,,,,,,,1],[1,1,,,,,,1,1,1,,1,1,,,,1,1,,1,,1,1,1,,1],[,1,1,1,,1,1,,,1,,1,1,1,1,,,,,,,1,,1],[,1,1,1,1,,,1,,\\\n1,,,,1,1,1,1,,1,1,,1],[,1,,,1,1,,1,,,,1,,1,1,,1,,1,,,1,,,1,,1],[,,,,,,,,,,,1],[,,,,,,,,,1,,,,,,,,,,,,,1],,[1,1,1,1,,1,1,1,1,1,1,1,1,1,1,1,1,,1,,1,1,1,1,1,1,1],[,1,,,,,,,1,1,,1,,,,,1,,,1,,1],[,1,,,,1,,,1,,,,,,,,1,,1,,,1],[,,,,,,,,,,,,,1,1,,,,1,,,1],[,,,,,1,,,1,,,,1],[,1],,[,1],[1,,,,,,,,,,,,,,1,,,,,1]],[,[,1,,,,1,1,1,1,1,1,,1,1,1,1,1,,1,1,,1,1,,,1],[,,1,,,,,,,,,1],,,[1,,,1,1,,,,,,,,1,1,,1,1,,1],,[,,,,,,,,,,,,,,,,,,1,,1],,[1,,,1,1,,1,1,,,,,1,,1,,,,,1,1,,1],,[,1,,,,,,,,1,1,1,1,1,,1,1,,,,1,1],[,,,,,,,,,,,,,,,,1,,,1],[,1,1,1,1,1,1,1,1,1,1,1,1,1,,,1,1,1,1,,1,1,1,1,1,1],[,,,,,,,,,,,1,,1,,,1],[1,,,,,,,,,,,,,,,,,,1,,1],,,[,1,,,,,,,,,,,,,,1,,,,1,1],[,,,,,,,,,1,,,1,,,,,,,,,,1],[,,,,,,,,,,,,,,,1],[,,,,,,,,,,,,,1,1,,,,,,1],,[,1]],[,[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[,1,1,,,1,1,,1,1,1,1,1,1,,,1,1,1,1,1,,1,1],[,1,,,,,,,,1],[,,,,1,,,1,,,1,1,,,,,,,,,,1,,,,1],[,1,,1,1,,,1,1,1,,,,1,1,1,1,,1,1,1,1,,1],[,,,,,,,1],[,1,1,,,,,1,,1,,,,,,1,,,,,,1,,1,,1],[,1,,,,,,1,,,,1,,,,,,,,,,1],[,,1,1,,\\\n1,1,1,1,1,1,1,1,1,1,,,,1,,1,1,1,1,,1],[,1,,,,,,,,1],[,1,1,,1,,,,,,,,1,,,,,,1,,,1,,1,,1],[,1,,1,,1,,1,1,1,,1,1,1,,1,,,1,1,,1,1,1,1,1],[,1,1,1,1,1,,,1,1,,,,1,1,1,,,,1,1,,,1,1],[,,1,1,1,1,,1,,1,,1,,1,1,1,1,,,,,1,,1,,1],[1,1,1,1,1,1,1,1,,1,,1,,1,1,1,,,1,1,,,,1,,1],[,,,1],,[,1,1,,1,,,1,1,1,,1,1,1,1,1,1,,1,1,,1,1,1,1,1,1],[,1,,,,,,1,,1,,1,,,,,,,1,1,,1,1],[,,,,,,1,,1,1,,1,,1,,,,,,,,,,1],[,1,1,,1,,,,1,,,,1,1,1,,,,1,,1,1,1,,1,1],,[,1,1,,,,,,,,,,,,,1,,,1,,,,,1],[,1,,,,,,,,,,,,,,,,,,,,,,1],[,1,1,,,,,,,1,,,,1,,,,,1,,,,,,,1]],[,[,1,1,1,1,1,,1,,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,,1],[,1,1,1,1,1,,1,,1,1,,,1,1,1,1,,1,,,,,1,1,1],[,,1,1,,1,,1,1,,,,1,1,1,1,,,1,,1,1,1,1,,1],[,1,,1,,,,,,,,1,,1,,1,,,,,,,,,,1],[,,1,,1,,,1,,,,,1,1,,,1,,1,1,1,1],[,1],[,1,1,,1,,1,1,,1,,,1,1,1,,,,1,,,1,,1],[1,1,,1,1,1,,,,,,,,,,,,,1,,1,1,1],[,1,1,,,,,,,1,,,1,,1,,1,,1,1,,,1,,,1],[,,1,,,,,,,,,,,,,,,,,,1],[,1,1,1,1,1,1,1,1,1,1,1,1,,1,1,1,1,1,1,1,1,1,1,1,1,1],[,1,1,1,1,1,,1,,1,,,,,1,1,1,,,1,,1,,,,1],[,1,1,1,1,1,1,1,1,,1,1,1,1,1,1,1,1,1,1,\\\n1,1,1,1,1,1,1],[,1,1,,1,,,1,1,1,,1,,1,1,1,,,1,1,1,1,,,,1,1],[,,,1,1,,,1,,1,,1,,1,1,1,1,,1,,,,,1],[,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[,1,,,,,,,,,,,,,,,,,,,1],[,1,1,,1,1,,1,,1,,,,1,1,,,1,1,,1,1,,1],[,1,1,1,1,1,,,1,1,1,,1,1,1,1,1,1,1,1,,1,1,,,1],[,1,1,1,1,1,,1,1,1,1,,1,1,1,1,1,1,1,1,1,1,1,1,,1,1],[,1,1,,1,,,1,,,1,,1,1,1,1,1,,1,,1,1],[,,,,,1,,,,1,,,,,1,1,,,,1],[,1,,1,1,1,,1,,,1,1,1,,,1,,,1,,1,,,1],[,,1,,,,,,,,,1,,1,,,,,1,,1],[,1,1,,,,,,,,1,1,1,,,,,,,,1,,,,,1],[,,,,,,,,1,,,,,1,,,1]],[,[,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[,1,1,,1,1,,,1,1,1,1,1,1,1,1,,,,,,,,,1,1],[,,,,,,,,1,,,,1,,1,,1],[,1,,,1,1,,1,,,,1,,,,,,,,1],[,1,,1,,1,,,,1,1,,1,,1,,,,1,1,1,1,1,,,1],,[,1,,,,,,,,1,,,1,1,,,1,,1,1,,1,,1],[,1,,,1,,,,,,,,1,,,,,,,1],[1,1,,,,,1,1,1,1,1,1,1,1,1,,1,1,1,1,1,1,1,,1,1,1],,[,1,,,,,,1,,1,,1,1,1,1,1,,,1,,1,1,,,,1],[,1,1,,,1,,1,,1,,,1,1,1,1,,,1,,,1,,,,1],[,1,1,1,1,1,,1,1,1,,1,1,1,1,1,1,1,1,1,1,,,,1,,1],[,1,,,1,1,,1,1,,,1,1,,1,1,,1,,1,,1],[1,,1,,,,,1,,1,,1,1,1,1,,,,,\\\n1,1,,,,1,1],[,1,1,,,,,1,1,,,1,,1,1,1,1,,,,,,,,,,1],,[,1,1,,,1,,,,1,,1,1,1,1,1,,,,1,,,,1,,1],[,,,1,1,,,1,,,,,1,,1,1,1,,1,1,,,,,,1],[,1,,,,,,,,,,,1,,,,1,,,,,,,1,,1],[,1,1,1,1,1,1,1,,1,1,1,1,1,1,,1,1,1,,1,1,,1,1,1,1],[,1,,,,,,,,,,,,,,,,,,,1],[,1,,,,,,1,,,,,1,,1,,,1,1,,1,1,,1],[,1,,,,,,1,,,,,1,1,,,,,,,,1,,,,1],[,,,,,,,,,,,,,,,,,,1,,,1,,,,,1],[,,,,,,,1,,,,1]],[,[1,1,1,1,1,1,1,1,1,1,1,1,1,1,,1,1,1,1,1,1,1,1,1,1,1,1],[,1,,1,,1,,,,,,,1,,,,,,,,1,,,1],[,1,,,,,,,1],[,,,,,,,,,,1],[,1,,,,,,1,1,,,,,,1],,[,1,1,,,,,,1,,,,,1,1,,,,1],[1,,1,,1,,,,,1,,,,,1,,,,,,,,,1,1],[,1,1,,,,,,,,,1,1,1,1,,,,1,,,,,1,,,1],,[,1,1,,1,,,1,1,,,1,,,1,1,1,,1,,1,1,1,,,,1],[,,,,,1,,,,,1,,,1,1,,,1,,1,,,,1],[,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[,1,,,1,1,,1,,,,1,,,,,,,,1],[,,,1,,,,,1,,,,,1,,1,,1,1,1],[,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[,,,,,1],[,1,,,,,,1,,,,,,,1,1,1,,,1],[,1,,,,,,,,,,1,1,1,,,,,1,,,1],[,,,,,1,,1,,,,,1,1,1,,1,1,,1,1,1,,,1,1],[1,1,,,,,,,1,,,,,1,1,,,,,,,,,,,1],,[,1],[,,,,,,,,,,,,,,\\\n,,,,,,,,,,1],[,,1,,,,,1,,,1,,,,1,,1],[,1,,,,,,,,,1]]];function km(e){e=Array.isArray(e)?e:Cm;var t=[];return e.forEach((function(e,n){var r=String.fromCharCode(n+96).replace(\"\\`\",\"\");Array.isArray(e)?t=t.concat(km(e).map((function(e){return r+e}))):t.push(r)})),t}var Rm=function(e){for(var t=Cm;e.length<3;)e+=\"\\`\";for(var n=0;n<=e.length-1;n++)if(!(t=t[e.charCodeAt(n)-96]))return!1;return!0};S(Nm,ua),Ri=W(Nm,[{key:\"props\",get:function(){return this._props}},{key:\"attr\",value:function(e){return null!=(e=this._attrs[e])?e:null}},{key:\"hasAttr\",value:function(e){return void 0!==this._attrs[e]}},{key:\"attrNames\",get:function(){return Object.keys(this._attrs)}}]);function Nm(e){var t,n,r;return H(this,Nm),(t=R(this,Nm))._props=(e=>{var t=null!=(t=e.nodeName)?t:_m[e.nodeType],n=null!=(n=null!=(n=e.nodeType)?n:Sm[e.nodeName])?n:1,r=(xa(\"number\"==typeof n,\"nodeType has to be a number, got '\".concat(n,\"'\")),xa(\"string\"==typeof t,\"nodeName has to be a string, got '\".concat(t,\"'\")),t=t.toLowerCase(\\\n),null);return\"input\"===t&&(r=(e.type||e.attributes&&e.attributes.type||\"\").toLowerCase(),Fm().includes(r)||(r=\"text\")),e=O({},e,{nodeType:n,nodeName:t}),r&&(e.type=r),delete e.attributes,Object.freeze(e)})(e),t._attrs=(e=e.attributes,n=void 0===e?{}:e,r={htmlFor:\"for\",className:\"class\"},Object.keys(n).reduce((function(e,t){var o=n[t];return xa(\"object\"!==a(o)||null===o,\"expects attributes not to be an object, '\".concat(t,\"' was\")),void 0!==o&&(e[r[t]||t]=null!==o?String(o):null),e}),{})),t}var Tm,Sm={\"#cdata-section\":2,\"#text\":3,\"#comment\":8,\"#document\":9,\"#document-fragment\":11},_m={},Om=(Object.keys(Sm).forEach((function(e){_m[Sm[e]]=e})),Ri),Mm=function(e,t){if(e=e||function(){},t=t||o.log,!o._audit)throw new Error(\"No audit configured\");var n=o.utils.queue(),a=[],i=(Object.keys(o.plugins).forEach((function(e){n.defer((function(t){function n(e){a.push(e),t()}try{o.plugins[e].cleanup(t,n)}catch(e){n(e)}}))})),o.utils.getFlattenedTree(r.body));o.utils.querySelectorAll(i,\"iframe, fram\\\ne\").forEach((function(e){n.defer((function(t,n){return o.utils.sendCommandToFrame(e.actualNode,{command:\"cleanup-plugin\"},t,n)}))})),n.then((function(n){0===a.length?e(n):t(a)})).catch(t)},Pm={};function Im(e){return Pm.hasOwnProperty(e)}function Bm(e){return\"string\"==typeof e&&Pm[e]?Pm[e]:\"function\"==typeof e?e:Tm}var jm={},Lm=(ce(jm,{getAllCells:function(){return Lm},getCellPosition:function(){return Es},getHeaders:function(){return zm},getScope:function(){return As},isColumnHeader:function(){return Fs},isDataCell:function(){return Vm},isDataTable:function(){return Gm},isHeader:function(){return $m},isRowHeader:function(){return Cs},toArray:function(){return xs},toGrid:function(){return xs},traverse:function(){return Hm}}),function(e){for(var t,n,r=[],a=0,o=e.rows.length;a<o;a++)for(t=0,n=e.rows[a].cells.length;t<n;t++)r.push(e.rows[a].cells[t]);return r});function qm(e,t,n){for(var r,a=\"row\"===e?\"_rowHeaders\":\"_colHeaders\",i=\"row\"===e?Cs:Fs,l=(s=n[t.y][t.x]).colSpan-1,u=s.getAttribu\\\nte(\"rowspan\"),s=(u=0===parseInt(u)||0===s.rowspan?n.length:s.rowSpan,t.y+(u-1)),c=t.x+l,d=\"row\"===e?t.y:0,p=\"row\"===e?0:t.x,f=[],m=s;d<=m&&!r;m--)for(var h=c;p<=h;h--){var g=n[m]?n[m][h]:void 0;if(g){var v=o.utils.getNodeFromTree(g);if(v[a]){r=v[a];break}f.push(g)}}return r=(r||[]).concat(f.filter(i)),f.forEach((function(e){o.utils.getNodeFromTree(e)[a]=r})),r}var zm=function(e,t){if(e.getAttribute(\"headers\")){var n=us(e,\"headers\");if(n.filter((function(e){return e})).length)return n}return t=t||xs(jl(e,\"table\")),e=qm(\"row\",n=Es(e,t),t),n=qm(\"col\",n,t),[].concat(e,n).reverse()},Vm=function(e){var t;return!(!e.children.length&&!e.textContent.trim())&&((t=ys(e))?[\"cell\",\"gridcell\"].includes(t):\"TD\"===e.nodeName.toUpperCase())},Gm=function(e){var n=ys(e);if((\"presentation\"===n||\"none\"===n)&&!rs(e))return!1;if(\"true\"===e.getAttribute(\"contenteditable\")||jl(e,'[contenteditable=\"true\"]'))return!0;if(\"grid\"===n||\"treegrid\"===n||\"table\"===n)return!0;if(\"landmark\"===ed(n))return!0;if(\"0\"===e.ge\\\ntAttribute(\"datatable\"))return!1;if(e.getAttribute(\"summary\"))return!0;if(e.tHead||e.tFoot||e.caption)return!0;for(var r=0,a=e.children.length;r<a;r++)if(\"COLGROUP\"===e.children[r].nodeName.toUpperCase())return!0;for(var o,i,l,u=0,s=e.rows.length,c=!1,d=0;d<s;d++)for(var p,f=0,m=(p=e.rows[d]).cells.length;f<m;f++){if(\"TH\"===(o=p.cells[f]).nodeName.toUpperCase())return!0;if(c||o.offsetWidth===o.clientWidth&&o.offsetHeight===o.clientHeight||(c=!0),o.getAttribute(\"scope\")||o.getAttribute(\"headers\")||o.getAttribute(\"abbr\"))return!0;if([\"columnheader\",\"rowheader\"].includes(ys(o)))return!0;if(1===o.children.length&&\"ABBR\"===o.children[0].nodeName.toUpperCase())return!0;u++}if(e.getElementsByTagName(\"table\").length)return!1;if(s<2)return!1;if(1===(n=e.rows[Math.ceil(s/2)]).cells.length&&1===n.cells[0].colSpan)return!1;if(5<=n.cells.length)return!0;if(c)return!0;for(var h=0;h<s;h++){if(p=e.rows[h],i&&i!==t.getComputedStyle(p).getPropertyValue(\"background-color\"))return!0;if(i=t.getComputedStyl\\\ne(p).getPropertyValue(\"background-color\"),l&&l!==t.getComputedStyle(p).getPropertyValue(\"background-image\"))return!0;l=t.getComputedStyle(p).getPropertyValue(\"background-image\")}return 20<=s||!(lu(e).width>.95*uu(t).width||u<10||e.querySelector(\"object, embed, iframe, applet\"))},$m=function(e){return!(!Fs(e)&&!Cs(e))||!!e.getAttribute(\"id\")&&(e=Aa(e.getAttribute(\"id\")),!!r.querySelector('[headers~=\"'.concat(e,'\"]')))},Hm=function(e,t,n,r){if(Array.isArray(t)&&(r=n,n=t,t={x:0,y:0}),\"string\"==typeof e)switch(e){case\"left\":e={x:-1,y:0};break;case\"up\":e={x:0,y:-1};break;case\"right\":e={x:1,y:0};break;case\"down\":e={x:0,y:1}}return function e(t,n,r,a){var o,i=r[n.y]?r[n.y][n.x]:void 0;return i?\"function\"==typeof a&&!0===(o=a(i,n,r))?[i]:((o=e(t,{x:n.x+t.x,y:n.y+t.y},r,a)).unshift(i),o):[]}(e,{x:t.x+e.x,y:t.y+e.y},n,r)},Um={},Wm=(ce(Um,{allowedAttr:function(){return Wm},arialabelText:function(){return ds},arialabelledbyText:function(){return cs},getAccessibleRefs:function(){return Km},getEleme\\\nntUnallowedRoles:function(){return Qm},getExplicitRole:function(){return ys},getImplicitRole:function(){return Ws},getOwnedVirtual:function(){return ec},getRole:function(){return Xs},getRoleType:function(){return ed},getRolesByType:function(){return th},getRolesWithNameFromContents:function(){return oh},implicitNodes:function(){return lh},implicitRole:function(){return Ws},isAccessibleRef:function(){return uh},isAriaRoleAllowedOnElement:function(){return Xm},isComboboxPopup:function(){return sh},isUnsupportedRole:function(){return vs},isValidRole:function(){return bs},label:function(){return dh},labelVirtual:function(){return Oc},lookupTable:function(){return ih},namedFromContents:function(){return Qs},requiredAttr:function(){return ph},requiredContext:function(){return fh},requiredOwned:function(){return mh},validateAttr:function(){return gh},validateAttrValue:function(){return hh}}),function(e){e=gs.ariaRoles[e];var t=M(ws());return e&&(e.allowedAttrs&&t.push.apply(t,M(e.allowedAttrs\\\n)),e.requiredAttrs)&&t.push.apply(t,M(e.requiredAttrs)),t}),Ym=/^idrefs?$/,Km=function(e){e=e.actualNode||e;var t=(t=Pl(e)).documentElement||t,n=Sl.get(\"idRefsByRoot\",(function(){return new Map})),r=n.get(t);return r||(r=new Map,n.set(t,r),function e(t,n,r){if(t.hasAttribute){var a;\"LABEL\"===t.nodeName.toUpperCase()&&t.hasAttribute(\"for\")&&(a=t.getAttribute(\"for\"),n.has(a)?n.get(a).push(t):n.set(a,[t]));for(var o=0;o<r.length;++o){var i=Ns(t.getAttribute(r[o])||\"\");if(i){var l,u=K(Yp(i));try{for(u.s();!(l=u.n()).done;){var s=l.value;n.has(s)?n.get(s).push(t):n.set(s,[t])}}catch(e){u.e(e)}finally{u.f()}}}}for(var c=0;c<t.childNodes.length;c++)1===t.childNodes[c].nodeType&&e(t.childNodes[c],n,r)}(t,r,Object.keys(gs.ariaAttrs).filter((function(e){return e=gs.ariaAttrs[e].type,Ym.test(e)})))),null!=(n=r.get(e.id))?n:[]},Xm=function(e,t){e=e instanceof ua?e:_l(e);var n=Ws(e);e=Us(e);return Array.isArray(e.allowedRoles)?e.allowedRoles.includes(t):t!==n&&!!e.allowedRoles},Zm=[\"doc-backlink\",\"\\\ndoc-biblioentry\",\"doc-biblioref\",\"doc-cover\",\"doc-endnote\",\"doc-glossref\",\"doc-noteref\"],Jm={header:\"banner\",footer:\"contentinfo\"},Qm=function(e){var t,n,r=!(1<arguments.length&&void 0!==arguments[1])||arguments[1],a=Hf(e).vNode;return qf(a)?(e=a.props.nodeName,t=Ws(a)||Jm[e],e=[],((n=a)?(n.hasAttr(\"role\")&&(n=Yp(n.attr(\"role\").toLowerCase()),e=e.concat(n)),e.filter((function(e){return bs(e)}))):e).filter((function(e){var n=a,o=t;return!(r&&e===o||(!Zm.includes(e)||ed(e)===o)&&Xm(n,e))}))):[]},eh=function(e){return Object.keys(gs.ariaRoles).filter((function(t){return gs.ariaRoles[t].type===e}))},th=function(e){return eh(e)},nh=function(){return Sl.get(\"ariaRolesNameFromContent\",(function(){return Object.keys(gs.ariaRoles).filter((function(e){return gs.ariaRoles[e].nameFromContent}))}))};function rh(e){return null===e}function ah(e){return null!==e}var oh=function(){return nh()},ih=((Ti={attributes:{\"aria-activedescendant\":{type:\"idref\",allowEmpty:!0,unsupported:!1},\"aria-atomic\":{type:\\\n\"boolean\",values:[\"true\",\"false\"],unsupported:!1},\"aria-autocomplete\":{type:\"nmtoken\",values:[\"inline\",\"list\",\"both\",\"none\"],unsupported:!1},\"aria-busy\":{type:\"boolean\",values:[\"true\",\"false\"],unsupported:!1},\"aria-checked\":{type:\"nmtoken\",values:[\"true\",\"false\",\"mixed\",\"undefined\"],unsupported:!1},\"aria-colcount\":{type:\"int\",unsupported:!1},\"aria-colindex\":{type:\"int\",unsupported:!1},\"aria-colspan\":{type:\"int\",unsupported:!1},\"aria-controls\":{type:\"idrefs\",allowEmpty:!0,unsupported:!1},\"aria-current\":{type:\"nmtoken\",allowEmpty:!0,values:[\"page\",\"step\",\"location\",\"date\",\"time\",\"true\",\"false\"],unsupported:!1},\"aria-describedby\":{type:\"idrefs\",allowEmpty:!0,unsupported:!1},\"aria-describedat\":{unsupported:!0,unstandardized:!0},\"aria-details\":{type:\"idref\",allowEmpty:!0,unsupported:!1},\"aria-disabled\":{type:\"boolean\",values:[\"true\",\"false\"],unsupported:!1},\"aria-dropeffect\":{type:\"nmtokens\",values:[\"copy\",\"move\",\"reference\",\"execute\",\"popup\",\"none\"],unsupported:!1},\"aria-errormessage\":{typ\\\ne:\"idref\",allowEmpty:!0,unsupported:!1},\"aria-expanded\":{type:\"nmtoken\",values:[\"true\",\"false\",\"undefined\"],unsupported:!1},\"aria-flowto\":{type:\"idrefs\",allowEmpty:!0,unsupported:!1},\"aria-grabbed\":{type:\"nmtoken\",values:[\"true\",\"false\",\"undefined\"],unsupported:!1},\"aria-haspopup\":{type:\"nmtoken\",allowEmpty:!0,values:[\"true\",\"false\",\"menu\",\"listbox\",\"tree\",\"grid\",\"dialog\"],unsupported:!1},\"aria-hidden\":{type:\"boolean\",values:[\"true\",\"false\"],unsupported:!1},\"aria-invalid\":{type:\"nmtoken\",allowEmpty:!0,values:[\"true\",\"false\",\"spelling\",\"grammar\"],unsupported:!1},\"aria-keyshortcuts\":{type:\"string\",allowEmpty:!0,unsupported:!1},\"aria-label\":{type:\"string\",allowEmpty:!0,unsupported:!1},\"aria-labelledby\":{type:\"idrefs\",allowEmpty:!0,unsupported:!1},\"aria-level\":{type:\"int\",unsupported:!1},\"aria-live\":{type:\"nmtoken\",values:[\"off\",\"polite\",\"assertive\"],unsupported:!1},\"aria-modal\":{type:\"boolean\",values:[\"true\",\"false\"],unsupported:!1},\"aria-multiline\":{type:\"boolean\",values:[\"true\",\"false\"]\\\n,unsupported:!1},\"aria-multiselectable\":{type:\"boolean\",values:[\"true\",\"false\"],unsupported:!1},\"aria-orientation\":{type:\"nmtoken\",values:[\"horizontal\",\"vertical\"],unsupported:!1},\"aria-owns\":{type:\"idrefs\",allowEmpty:!0,unsupported:!1},\"aria-placeholder\":{type:\"string\",allowEmpty:!0,unsupported:!1},\"aria-posinset\":{type:\"int\",unsupported:!1},\"aria-pressed\":{type:\"nmtoken\",values:[\"true\",\"false\",\"mixed\",\"undefined\"],unsupported:!1},\"aria-readonly\":{type:\"boolean\",values:[\"true\",\"false\"],unsupported:!1},\"aria-relevant\":{type:\"nmtokens\",values:[\"additions\",\"removals\",\"text\",\"all\"],unsupported:!1},\"aria-required\":{type:\"boolean\",values:[\"true\",\"false\"],unsupported:!1},\"aria-roledescription\":{type:\"string\",allowEmpty:!0,unsupported:!1},\"aria-rowcount\":{type:\"int\",unsupported:!1},\"aria-rowindex\":{type:\"int\",unsupported:!1},\"aria-rowspan\":{type:\"int\",unsupported:!1},\"aria-selected\":{type:\"nmtoken\",values:[\"true\",\"false\",\"undefined\"],unsupported:!1},\"aria-setsize\":{type:\"int\",unsupported:!1},\\\n\"aria-sort\":{type:\"nmtoken\",values:[\"ascending\",\"descending\",\"other\",\"none\"],unsupported:!1},\"aria-valuemax\":{type:\"decimal\",unsupported:!1},\"aria-valuemin\":{type:\"decimal\",unsupported:!1},\"aria-valuenow\":{type:\"decimal\",unsupported:!1},\"aria-valuetext\":{type:\"string\",unsupported:!1}},globalAttributes:[\"aria-atomic\",\"aria-busy\",\"aria-controls\",\"aria-current\",\"aria-describedby\",\"aria-details\",\"aria-disabled\",\"aria-dropeffect\",\"aria-flowto\",\"aria-grabbed\",\"aria-haspopup\",\"aria-hidden\",\"aria-invalid\",\"aria-keyshortcuts\",\"aria-label\",\"aria-labelledby\",\"aria-live\",\"aria-owns\",\"aria-relevant\",\"aria-roledescription\"]}).role={alert:{type:\"widget\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\"],context:null,unsupported:!1,allowedElements:[\"section\"]},alertdialog:{type:\"widget\",attributes:{allowed:[\"aria-expanded\",\"aria-modal\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\"],context:null,unsupported:!1,allowedElements:[\"dialog\",\"section\"]},applicatio\\\nn:{type:\"landmark\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\",\"aria-activedescendant\"]},owned:null,nameFrom:[\"author\"],context:null,unsupported:!1,allowedElements:[\"article\",\"audio\",\"embed\",\"iframe\",\"object\",\"section\",\"svg\",\"video\"]},article:{type:\"structure\",attributes:{allowed:[\"aria-expanded\",\"aria-posinset\",\"aria-setsize\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:[\"article\"],unsupported:!1},banner:{type:\"landmark\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:[\"header\"],unsupported:!1,allowedElements:[\"section\"]},button:{type:\"widget\",attributes:{allowed:[\"aria-expanded\",\"aria-pressed\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:null,implicit:[\"button\",'input[type=\"button\"]','input[type=\"image\"]','input[type=\"reset\"]','input[type=\"submit\"]',\"summary\"],unsupported:!1,allowedElements:[{nodeName:\"a\",attributes:{href:ah}}]},cell:{type:\"structure\",\\\nattributes:{allowed:[\"aria-colindex\",\"aria-colspan\",\"aria-rowindex\",\"aria-rowspan\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:[\"row\"],implicit:[\"td\",\"th\"],unsupported:!1},checkbox:{type:\"widget\",attributes:{allowed:[\"aria-checked\",\"aria-required\",\"aria-readonly\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:null,implicit:['input[type=\"checkbox\"]'],unsupported:!1,allowedElements:[\"button\"]},columnheader:{type:\"structure\",attributes:{allowed:[\"aria-colindex\",\"aria-colspan\",\"aria-expanded\",\"aria-rowindex\",\"aria-rowspan\",\"aria-required\",\"aria-readonly\",\"aria-selected\",\"aria-sort\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:[\"row\"],implicit:[\"th\"],unsupported:!1},combobox:{type:\"composite\",attributes:{allowed:[\"aria-autocomplete\",\"aria-required\",\"aria-activedescendant\",\"aria-orientation\",\"aria-errormessage\"],required:[\"aria-expanded\"]},owned:{all:[\"listbox\",\"tree\",\"grid\",\"dialog\",\"textbox\"]},nameFrom:[\"author\\\n\"],context:null,unsupported:!1,allowedElements:[{nodeName:\"input\",properties:{type:[\"text\",\"search\",\"tel\",\"url\",\"email\"]}}]},command:{nameFrom:[\"author\"],type:\"abstract\",unsupported:!1},complementary:{type:\"landmark\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:[\"aside\"],unsupported:!1,allowedElements:[\"section\"]},composite:{nameFrom:[\"author\"],type:\"abstract\",unsupported:!1},contentinfo:{type:\"landmark\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:[\"footer\"],unsupported:!1,allowedElements:[\"section\"]},definition:{type:\"structure\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:[\"dd\",\"dfn\"],unsupported:!1},dialog:{type:\"widget\",attributes:{allowed:[\"aria-expanded\",\"aria-modal\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:[\"dialog\"],unsupported:!1,allowedElements\\\n:[\"section\"]},directory:{type:\"structure\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:null,unsupported:!1,allowedElements:[\"ol\",\"ul\"]},document:{type:\"structure\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:[\"body\"],unsupported:!1,allowedElements:[\"article\",\"embed\",\"iframe\",\"object\",\"section\",\"svg\"]},\"doc-abstract\":{type:\"section\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\"],context:null,unsupported:!1,allowedElements:[\"section\"]},\"doc-acknowledgments\":{type:\"landmark\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\"],context:null,unsupported:!1,allowedElements:[\"section\"]},\"doc-afterword\":{type:\"landmark\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\"],context:null,unsupported:!1,allowedElements:[\"section\"]},\"doc-appendix\":{type:\"\\\nlandmark\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\"],context:null,unsupported:!1,allowedElements:[\"section\"]},\"doc-backlink\":{type:\"link\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:null,unsupported:!1,allowedElements:[{nodeName:\"a\",attributes:{href:ah}}]},\"doc-biblioentry\":{type:\"listitem\",attributes:{allowed:[\"aria-expanded\",\"aria-level\",\"aria-posinset\",\"aria-setsize\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\"],context:[\"doc-bibliography\"],unsupported:!1,allowedElements:[\"li\"]},\"doc-bibliography\":{type:\"landmark\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:{one:[\"doc-biblioentry\"]},nameFrom:[\"author\"],context:null,unsupported:!1,allowedElements:[\"section\"]},\"doc-biblioref\":{type:\"link\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:null,unsupported:!1,allowedElements:[{nodeName:\"a\",a\\\nttributes:{href:ah}}]},\"doc-chapter\":{type:\"landmark\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:null,namefrom:[\"author\"],context:null,unsupported:!1,allowedElements:[\"section\"]},\"doc-colophon\":{type:\"section\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:null,namefrom:[\"author\"],context:null,unsupported:!1,allowedElements:[\"section\"]},\"doc-conclusion\":{type:\"landmark\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:null,namefrom:[\"author\"],context:null,unsupported:!1,allowedElements:[\"section\"]},\"doc-cover\":{type:\"img\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:null,namefrom:[\"author\"],context:null,unsupported:!1},\"doc-credit\":{type:\"section\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:null,namefrom:[\"author\"],context:null,unsupported:!1,allowedElements:[\"section\"]},\"doc-credits\":{type:\"landmark\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:null,namefrom:[\"author\"],\\\ncontext:null,unsupported:!1,allowedElements:[\"section\"]},\"doc-dedication\":{type:\"section\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:null,namefrom:[\"author\"],context:null,unsupported:!1,allowedElements:[\"section\"]},\"doc-endnote\":{type:\"listitem\",attributes:{allowed:[\"aria-expanded\",\"aria-level\",\"aria-posinset\",\"aria-setsize\",\"aria-errormessage\"]},owned:null,namefrom:[\"author\"],context:[\"doc-endnotes\"],unsupported:!1,allowedElements:[\"li\"]},\"doc-endnotes\":{type:\"landmark\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:{one:[\"doc-endnote\"]},namefrom:[\"author\"],context:null,unsupported:!1,allowedElements:[\"section\"]},\"doc-epigraph\":{type:\"section\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:null,namefrom:[\"author\"],context:null,unsupported:!1},\"doc-epilogue\":{type:\"landmark\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:null,namefrom:[\"author\"],context:null,unsupported:!1,allowedElements:[\"section\"]},\"doc-erra\\\nta\":{type:\"landmark\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:null,namefrom:[\"author\"],context:null,unsupported:!1,allowedElements:[\"section\"]},\"doc-example\":{type:\"section\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:null,namefrom:[\"author\"],context:null,unsupported:!1,allowedElements:[\"aside\",\"section\"]},\"doc-footnote\":{type:\"section\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:null,namefrom:[\"author\"],context:null,unsupported:!1,allowedElements:[\"aside\",\"footer\",\"header\"]},\"doc-foreword\":{type:\"landmark\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:null,namefrom:[\"author\"],context:null,unsupported:!1,allowedElements:[\"section\"]},\"doc-glossary\":{type:\"landmark\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:[\"term\",\"definition\"],namefrom:[\"author\"],context:null,unsupported:!1,allowedElements:[\"dl\"]},\"doc-glossref\":{type:\"link\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\\\n\"]},owned:null,namefrom:[\"author\",\"contents\"],context:null,unsupported:!1,allowedElements:[{nodeName:\"a\",attributes:{href:ah}}]},\"doc-index\":{type:\"navigation\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:null,namefrom:[\"author\"],context:null,unsupported:!1,allowedElements:[\"nav\",\"section\"]},\"doc-introduction\":{type:\"landmark\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:null,namefrom:[\"author\"],context:null,unsupported:!1,allowedElements:[\"section\"]},\"doc-noteref\":{type:\"link\",attributes:{allowed:[\"aria-expanded\"]},owned:null,namefrom:[\"author\",\"contents\"],context:null,unsupported:!1,allowedElements:[{nodeName:\"a\",attributes:{href:ah}}]},\"doc-notice\":{type:\"note\",attributes:{allowed:[\"aria-expanded\"]},owned:null,namefrom:[\"author\"],context:null,unsupported:!1,allowedElements:[\"section\"]},\"doc-pagebreak\":{type:\"separator\",attributes:{allowed:[\"aria-expanded\"]},owned:null,namefrom:[\"author\"],context:null,unsupported:!1,allowedElements:[\"hr\"]},\"doc\\\n-pagelist\":{type:\"navigation\",attributes:{allowed:[\"aria-expanded\"]},owned:null,namefrom:[\"author\"],context:null,unsupported:!1,allowedElements:[\"nav\",\"section\"]},\"doc-part\":{type:\"landmark\",attributes:{allowed:[\"aria-expanded\"]},owned:null,namefrom:[\"author\"],context:null,unsupported:!1,allowedElements:[\"section\"]},\"doc-preface\":{type:\"landmark\",attributes:{allowed:[\"aria-expanded\"]},owned:null,namefrom:[\"author\"],context:null,unsupported:!1,allowedElements:[\"section\"]},\"doc-prologue\":{type:\"landmark\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:null,namefrom:[\"author\"],context:null,unsupported:!1,allowedElements:[\"section\"]},\"doc-pullquote\":{type:\"none\",attributes:{allowed:[\"aria-expanded\"]},owned:null,namefrom:[\"author\"],context:null,unsupported:!1,allowedElements:[\"aside\",\"section\"]},\"doc-qna\":{type:\"section\",attributes:{allowed:[\"aria-expanded\"]},owned:null,namefrom:[\"author\"],context:null,unsupported:!1,allowedElements:[\"section\"]},\"doc-subtitle\":{type:\"sectio\\\nnhead\",attributes:{allowed:[\"aria-expanded\"]},owned:null,namefrom:[\"author\"],context:null,unsupported:!1,allowedElements:{nodeName:[\"h1\",\"h2\",\"h3\",\"h4\",\"h5\",\"h6\"]}},\"doc-tip\":{type:\"note\",attributes:{allowed:[\"aria-expanded\"]},owned:null,namefrom:[\"author\"],context:null,unsupported:!1,allowedElements:[\"aside\"]},\"doc-toc\":{type:\"navigation\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:null,namefrom:[\"author\"],context:null,unsupported:!1,allowedElements:[\"nav\",\"section\"]},feed:{type:\"structure\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:{one:[\"article\"]},nameFrom:[\"author\"],context:null,unsupported:!1,allowedElements:[\"article\",\"aside\",\"section\"]},figure:{type:\"structure\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:null,implicit:[\"figure\"],unsupported:!1},form:{type:\"landmark\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\"],context:null,impl\\\nicit:[\"form\"],unsupported:!1},grid:{type:\"composite\",attributes:{allowed:[\"aria-activedescendant\",\"aria-expanded\",\"aria-colcount\",\"aria-level\",\"aria-multiselectable\",\"aria-readonly\",\"aria-rowcount\",\"aria-errormessage\"]},owned:{one:[\"rowgroup\",\"row\"]},nameFrom:[\"author\"],context:null,implicit:[\"table\"],unsupported:!1},gridcell:{type:\"widget\",attributes:{allowed:[\"aria-colindex\",\"aria-colspan\",\"aria-expanded\",\"aria-rowindex\",\"aria-rowspan\",\"aria-selected\",\"aria-readonly\",\"aria-required\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:[\"row\"],implicit:[\"td\",\"th\"],unsupported:!1},group:{type:\"structure\",attributes:{allowed:[\"aria-activedescendant\",\"aria-expanded\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:[\"details\",\"optgroup\"],unsupported:!1,allowedElements:[\"dl\",\"figcaption\",\"fieldset\",\"figure\",\"footer\",\"header\",\"ol\",\"ul\"]},heading:{type:\"structure\",attributes:{required:[\"aria-level\"],allowed:[\"aria-expanded\",\"aria-errormessage\"]},o\\\nwned:null,nameFrom:[\"author\",\"contents\"],context:null,implicit:[\"h1\",\"h2\",\"h3\",\"h4\",\"h5\",\"h6\"],unsupported:!1},img:{type:\"structure\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:[\"img\"],unsupported:!1,allowedElements:[\"embed\",\"iframe\",\"object\",\"svg\"]},input:{nameFrom:[\"author\"],type:\"abstract\",unsupported:!1},landmark:{nameFrom:[\"author\"],type:\"abstract\",unsupported:!1},link:{type:\"widget\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:null,implicit:[\"a[href]\",\"area[href]\"],unsupported:!1,allowedElements:[\"button\",{nodeName:\"input\",properties:{type:[\"image\",\"button\"]}}]},list:{type:\"structure\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:{all:[\"listitem\"]},nameFrom:[\"author\"],context:null,implicit:[\"ol\",\"ul\",\"dl\"],unsupported:!1},listbox:{type:\"composite\",attributes:{allowed:[\"aria-activedescendant\",\"aria-multiselectable\",\"aria-readonly\",\"\\\naria-required\",\"aria-expanded\",\"aria-orientation\",\"aria-errormessage\"]},owned:{all:[\"option\"]},nameFrom:[\"author\"],context:null,implicit:[\"select\"],unsupported:!1,allowedElements:[\"ol\",\"ul\"]},listitem:{type:\"structure\",attributes:{allowed:[\"aria-level\",\"aria-posinset\",\"aria-setsize\",\"aria-expanded\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:[\"list\"],implicit:[\"li\",\"dt\"],unsupported:!1},log:{type:\"widget\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\"],context:null,unsupported:!1,allowedElements:[\"section\"]},main:{type:\"landmark\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:[\"main\"],unsupported:!1,allowedElements:[\"article\",\"section\"]},marquee:{type:\"widget\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\"],context:null,unsupported:!1,allowedElements:[\"section\"]},math:{type:\"structure\",attributes:{allowed:[\"aria\\\n-expanded\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:[\"math\"],unsupported:!1},menu:{type:\"composite\",attributes:{allowed:[\"aria-activedescendant\",\"aria-expanded\",\"aria-orientation\",\"aria-errormessage\"]},owned:{one:[\"menuitem\",\"menuitemradio\",\"menuitemcheckbox\"]},nameFrom:[\"author\"],context:null,implicit:['menu[type=\"context\"]'],unsupported:!1,allowedElements:[\"ol\",\"ul\"]},menubar:{type:\"composite\",attributes:{allowed:[\"aria-activedescendant\",\"aria-expanded\",\"aria-orientation\",\"aria-errormessage\"]},owned:{one:[\"menuitem\",\"menuitemradio\",\"menuitemcheckbox\"]},nameFrom:[\"author\"],context:null,unsupported:!1,allowedElements:[\"ol\",\"ul\"]},menuitem:{type:\"widget\",attributes:{allowed:[\"aria-posinset\",\"aria-setsize\",\"aria-expanded\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:[\"menu\",\"menubar\"],implicit:['menuitem[type=\"command\"]'],unsupported:!1,allowedElements:[\"button\",\"li\",{nodeName:\"iput\",properties:{type:[\"image\",\"button\"]}},{nodeN\\\name:\"a\",attributes:{href:ah}}]},menuitemcheckbox:{type:\"widget\",attributes:{allowed:[\"aria-checked\",\"aria-posinset\",\"aria-setsize\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:[\"menu\",\"menubar\"],implicit:['menuitem[type=\"checkbox\"]'],unsupported:!1,allowedElements:[{nodeName:[\"button\",\"li\"]},{nodeName:\"input\",properties:{type:[\"checkbox\",\"image\",\"button\"]}},{nodeName:\"a\",attributes:{href:ah}}]},menuitemradio:{type:\"widget\",attributes:{allowed:[\"aria-checked\",\"aria-selected\",\"aria-posinset\",\"aria-setsize\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:[\"menu\",\"menubar\"],implicit:['menuitem[type=\"radio\"]'],unsupported:!1,allowedElements:[{nodeName:[\"button\",\"li\"]},{nodeName:\"input\",properties:{type:[\"image\",\"button\",\"radio\"]}},{nodeName:\"a\",attributes:{href:ah}}]},navigation:{type:\"landmark\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:[\"nav\"],unsupported:!1,allowedEleme\\\nnts:[\"section\"]},none:{type:\"structure\",attributes:null,owned:null,nameFrom:[\"author\"],context:null,unsupported:!1,allowedElements:[{nodeName:[\"article\",\"aside\",\"dl\",\"embed\",\"figcaption\",\"fieldset\",\"figure\",\"footer\",\"form\",\"h1\",\"h2\",\"h3\",\"h4\",\"h5\",\"h6\",\"header\",\"hr\",\"iframe\",\"li\",\"ol\",\"section\",\"ul\"]},{nodeName:\"img\",attributes:{alt:ah}}]},note:{type:\"structure\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\"],context:null,unsupported:!1,allowedElements:[\"aside\"]},option:{type:\"widget\",attributes:{allowed:[\"aria-selected\",\"aria-posinset\",\"aria-setsize\",\"aria-checked\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:[\"listbox\"],implicit:[\"option\"],unsupported:!1,allowedElements:[{nodeName:[\"button\",\"li\"]},{nodeName:\"input\",properties:{type:[\"checkbox\",\"button\"]}},{nodeName:\"a\",attributes:{href:ah}}]},presentation:{type:\"structure\",attributes:null,owned:null,nameFrom:[\"author\"],context:null,unsupported:!1,allowedElements:[{n\\\nodeName:[\"article\",\"aside\",\"dl\",\"embed\",\"figcaption\",\"fieldset\",\"figure\",\"footer\",\"form\",\"h1\",\"h2\",\"h3\",\"h4\",\"h5\",\"h6\",\"header\",\"hr\",\"iframe\",\"li\",\"ol\",\"section\",\"ul\"]},{nodeName:\"img\",attributes:{alt:ah}}]},progressbar:{type:\"widget\",attributes:{allowed:[\"aria-valuetext\",\"aria-valuenow\",\"aria-valuemax\",\"aria-valuemin\",\"aria-expanded\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:[\"progress\"],unsupported:!1},radio:{type:\"widget\",attributes:{allowed:[\"aria-selected\",\"aria-posinset\",\"aria-setsize\",\"aria-required\",\"aria-errormessage\",\"aria-checked\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:null,implicit:['input[type=\"radio\"]'],unsupported:!1,allowedElements:[{nodeName:[\"button\",\"li\"]},{nodeName:\"input\",properties:{type:[\"image\",\"button\"]}}]},radiogroup:{type:\"composite\",attributes:{allowed:[\"aria-activedescendant\",\"aria-required\",\"aria-expanded\",\"aria-readonly\",\"aria-errormessage\",\"aria-orientation\"]},owned:{all:[\"radio\"]},nameFrom:[\"author\"],context\\\n:null,unsupported:!1,allowedElements:{nodeName:[\"ol\",\"ul\",\"fieldset\"]}},range:{nameFrom:[\"author\"],type:\"abstract\",unsupported:!1},region:{type:\"landmark\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:[\"section[aria-label]\",\"section[aria-labelledby]\",\"section[title]\"],unsupported:!1,allowedElements:{nodeName:[\"article\",\"aside\"]}},roletype:{type:\"abstract\",unsupported:!1},row:{type:\"structure\",attributes:{allowed:[\"aria-activedescendant\",\"aria-colindex\",\"aria-expanded\",\"aria-level\",\"aria-selected\",\"aria-rowindex\",\"aria-errormessage\"]},owned:{one:[\"cell\",\"columnheader\",\"rowheader\",\"gridcell\"]},nameFrom:[\"author\",\"contents\"],context:[\"rowgroup\",\"grid\",\"treegrid\",\"table\"],implicit:[\"tr\"],unsupported:!1},rowgroup:{type:\"structure\",attributes:{allowed:[\"aria-activedescendant\",\"aria-expanded\",\"aria-errormessage\"]},owned:{all:[\"row\"]},nameFrom:[\"author\",\"contents\"],context:[\"grid\",\"table\",\"treegrid\"],implicit:[\"tbody\",\"thead\",\"t\\\nfoot\"],unsupported:!1},rowheader:{type:\"structure\",attributes:{allowed:[\"aria-colindex\",\"aria-colspan\",\"aria-expanded\",\"aria-rowindex\",\"aria-rowspan\",\"aria-required\",\"aria-readonly\",\"aria-selected\",\"aria-sort\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:[\"row\"],implicit:[\"th\"],unsupported:!1},scrollbar:{type:\"widget\",attributes:{required:[\"aria-controls\",\"aria-valuenow\"],allowed:[\"aria-valuetext\",\"aria-orientation\",\"aria-errormessage\",\"aria-valuemax\",\"aria-valuemin\"]},owned:null,nameFrom:[\"author\"],context:null,unsupported:!1},search:{type:\"landmark\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\"],context:null,unsupported:!1,allowedElements:{nodeName:[\"aside\",\"form\",\"section\"]}},searchbox:{type:\"widget\",attributes:{allowed:[\"aria-activedescendant\",\"aria-autocomplete\",\"aria-multiline\",\"aria-readonly\",\"aria-required\",\"aria-placeholder\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:['input[t\\\nype=\"search\"]'],unsupported:!1,allowedElements:{nodeName:\"input\",properties:{type:\"text\"}}},section:{nameFrom:[\"author\",\"contents\"],type:\"abstract\",unsupported:!1},sectionhead:{nameFrom:[\"author\",\"contents\"],type:\"abstract\",unsupported:!1},select:{nameFrom:[\"author\"],type:\"abstract\",unsupported:!1},separator:{type:\"structure\",attributes:{allowed:[\"aria-expanded\",\"aria-orientation\",\"aria-valuenow\",\"aria-valuemax\",\"aria-valuemin\",\"aria-valuetext\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:[\"hr\"],unsupported:!1,allowedElements:[\"li\"]},slider:{type:\"widget\",attributes:{allowed:[\"aria-valuetext\",\"aria-orientation\",\"aria-readonly\",\"aria-errormessage\",\"aria-valuemax\",\"aria-valuemin\"],required:[\"aria-valuenow\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:['input[type=\"range\"]'],unsupported:!1},spinbutton:{type:\"widget\",attributes:{allowed:[\"aria-valuetext\",\"aria-required\",\"aria-readonly\",\"aria-errormessage\",\"aria-valuemax\",\"aria-valuemin\"],required:[\"a\\\nria-valuenow\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:['input[type=\"number\"]'],unsupported:!1,allowedElements:{nodeName:\"input\",properties:{type:[\"text\",\"tel\"]}}},status:{type:\"widget\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:[\"output\"],unsupported:!1,allowedElements:[\"section\"]},structure:{type:\"abstract\",unsupported:!1},switch:{type:\"widget\",attributes:{allowed:[\"aria-errormessage\"],required:[\"aria-checked\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:null,unsupported:!1,allowedElements:[\"button\",{nodeName:\"input\",properties:{type:[\"checkbox\",\"image\",\"button\"]}},{nodeName:\"a\",attributes:{href:ah}}]},tab:{type:\"widget\",attributes:{allowed:[\"aria-selected\",\"aria-expanded\",\"aria-setsize\",\"aria-posinset\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:[\"tablist\"],unsupported:!1,allowedElements:[{nodeName:[\"button\",\"h1\",\"h2\",\"h3\",\"h4\",\"h5\",\"h6\",\"li\"]},{nodeName:\"input\",prop\\\nerties:{type:\"button\"}},{nodeName:\"a\",attributes:{href:ah}}]},table:{type:\"structure\",attributes:{allowed:[\"aria-colcount\",\"aria-rowcount\",\"aria-errormessage\"]},owned:{one:[\"rowgroup\",\"row\"]},nameFrom:[\"author\",\"contents\"],context:null,implicit:[\"table\"],unsupported:!1},tablist:{type:\"composite\",attributes:{allowed:[\"aria-activedescendant\",\"aria-expanded\",\"aria-level\",\"aria-multiselectable\",\"aria-orientation\",\"aria-errormessage\"]},owned:{all:[\"tab\"]},nameFrom:[\"author\"],context:null,unsupported:!1,allowedElements:[\"ol\",\"ul\"]},tabpanel:{type:\"widget\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\"],context:null,unsupported:!1,allowedElements:[\"section\"]},term:{type:\"structure\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:null,implicit:[\"dt\"],unsupported:!1},textbox:{type:\"widget\",attributes:{allowed:[\"aria-activedescendant\",\"aria-autocomplete\",\"aria-multiline\",\"aria-readonly\",\"aria-r\\\nequired\",\"aria-placeholder\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:['input[type=\"text\"]','input[type=\"email\"]','input[type=\"password\"]','input[type=\"tel\"]','input[type=\"url\"]',\"input:not([type])\",\"textarea\"],unsupported:!1},timer:{type:\"widget\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\"],context:null,unsupported:!1},toolbar:{type:\"structure\",attributes:{allowed:[\"aria-activedescendant\",\"aria-expanded\",\"aria-orientation\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\"],context:null,implicit:['menu[type=\"toolbar\"]'],unsupported:!1,allowedElements:[\"ol\",\"ul\"]},tooltip:{type:\"structure\",attributes:{allowed:[\"aria-expanded\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:null,unsupported:!1},tree:{type:\"composite\",attributes:{allowed:[\"aria-activedescendant\",\"aria-multiselectable\",\"aria-required\",\"aria-expanded\",\"aria-orientation\",\"aria-errormessage\"]},owned:{all:[\"treeitem\"]},nameF\\\nrom:[\"author\"],context:null,unsupported:!1,allowedElements:[\"ol\",\"ul\"]},treegrid:{type:\"composite\",attributes:{allowed:[\"aria-activedescendant\",\"aria-colcount\",\"aria-expanded\",\"aria-level\",\"aria-multiselectable\",\"aria-readonly\",\"aria-required\",\"aria-rowcount\",\"aria-orientation\",\"aria-errormessage\"]},owned:{one:[\"rowgroup\",\"row\"]},nameFrom:[\"author\"],context:null,unsupported:!1},treeitem:{type:\"widget\",attributes:{allowed:[\"aria-checked\",\"aria-selected\",\"aria-expanded\",\"aria-level\",\"aria-posinset\",\"aria-setsize\",\"aria-errormessage\"]},owned:null,nameFrom:[\"author\",\"contents\"],context:[\"group\",\"tree\"],unsupported:!1,allowedElements:[\"li\",{nodeName:\"a\",attributes:{href:ah}}]},widget:{type:\"abstract\",unsupported:!1},window:{nameFrom:[\"author\"],type:\"abstract\",unsupported:!1}},Ti.implicitHtmlRole=Ss,Ti.elementsAllowedNoRole=[{nodeName:[\"base\",\"body\",\"caption\",\"col\",\"colgroup\",\"datalist\",\"dd\",\"details\",\"dt\",\"head\",\"html\",\"keygen\",\"label\",\"legend\",\"main\",\"map\",\"math\",\"meta\",\"meter\",\"noscript\",\\\n\"optgroup\",\"param\",\"picture\",\"progress\",\"script\",\"source\",\"style\",\"template\",\"textarea\",\"title\",\"track\"]},{nodeName:\"area\",attributes:{href:ah}},{nodeName:\"input\",properties:{type:[\"color\",\"data\",\"datatime\",\"file\",\"hidden\",\"month\",\"number\",\"password\",\"range\",\"reset\",\"submit\",\"time\",\"week\"]}},{nodeName:\"link\",attributes:{href:ah}},{nodeName:\"menu\",attributes:{type:\"context\"}},{nodeName:\"menuitem\",attributes:{type:[\"command\",\"checkbox\",\"radio\"]}},{nodeName:\"select\",condition:function(e){return e instanceof o.AbstractVirtualNode||(e=o.utils.getNodeFromTree(e)),1<Number(e.attr(\"size\"))},properties:{multiple:!0}},{nodeName:[\"clippath\",\"cursor\",\"defs\",\"desc\",\"feblend\",\"fecolormatrix\",\"fecomponenttransfer\",\"fecomposite\",\"feconvolvematrix\",\"fediffuselighting\",\"fedisplacementmap\",\"fedistantlight\",\"fedropshadow\",\"feflood\",\"fefunca\",\"fefuncb\",\"fefuncg\",\"fefuncr\",\"fegaussianblur\",\"feimage\",\"femerge\",\"femergenode\",\"femorphology\",\"feoffset\",\"fepointlight\",\"fespecularlighting\",\"fespotlight\",\"fetile\",\\\n\"feturbulence\",\"filter\",\"hatch\",\"hatchpath\",\"lineargradient\",\"marker\",\"mask\",\"meshgradient\",\"meshpatch\",\"meshrow\",\"metadata\",\"mpath\",\"pattern\",\"radialgradient\",\"solidcolor\",\"stop\",\"switch\",\"view\"]}],Ti.elementsAllowedAnyRole=[{nodeName:\"a\",attributes:{href:rh}},{nodeName:\"img\",attributes:{alt:rh}},{nodeName:[\"abbr\",\"address\",\"canvas\",\"div\",\"p\",\"pre\",\"blockquote\",\"ins\",\"del\",\"output\",\"span\",\"table\",\"tbody\",\"thead\",\"tfoot\",\"td\",\"em\",\"strong\",\"small\",\"s\",\"cite\",\"q\",\"dfn\",\"abbr\",\"time\",\"code\",\"var\",\"samp\",\"kbd\",\"sub\",\"sup\",\"i\",\"b\",\"u\",\"mark\",\"ruby\",\"rt\",\"rp\",\"bdi\",\"bdo\",\"br\",\"wbr\",\"th\",\"tr\"]}],Ti.evaluateRoleForElement={A:function(e){var t=e.node;return\"http://www.w3.org/2000/svg\"===t.namespaceURI||!t.href.length||e.out},AREA:function(e){return!e.node.href},BUTTON:function(e){var t=e.node,n=e.role;e=e.out;return\"menu\"===t.getAttribute(\"type\")?\"menuitem\"===n:e},IMG:function(e){var t=e.node,n=e.role,r=e.out;switch(t.alt){case null:return r;case\"\":return\"presentation\"===n||\"none\"===n;default:\\\nreturn\"presentation\"!==n&&\"none\"!==n}},INPUT:function(e){var t=e.node,n=e.role,r=e.out;switch(t.type){case\"button\":case\"image\":return r;case\"checkbox\":return!(\"button\"!==n||!t.hasAttribute(\"aria-pressed\"))||r;case\"radio\":return\"menuitemradio\"===n;case\"text\":return\"combobox\"===n||\"searchbox\"===n||\"spinbutton\"===n;case\"tel\":return\"combobox\"===n||\"spinbutton\"===n;case\"url\":case\"search\":case\"email\":return\"combobox\"===n;default:return!1}},LI:function(e){var t=e.node;e=e.out;return!o.utils.matchesSelector(t,\"ol li, ul li\")||e},MENU:function(e){return\"context\"!==e.node.getAttribute(\"type\")},OPTION:function(e){return e=e.node,!o.utils.matchesSelector(e,\"select > option, datalist > option, optgroup > option\")},SELECT:function(e){var t=e.node;return!t.multiple&&t.size<=1&&\"menu\"===e.role},SVG:function(e){var t=e.node;return!(!t.parentNode||\"http://www.w3.org/2000/svg\"!==t.parentNode.namespaceURI)||e.out}},Ti.rolesOfType={widget:[\"button\",\"checkbox\",\"dialog\",\"gridcell\",\"link\",\"log\",\"marquee\",\"men\\\nuitem\",\"menuitemcheckbox\",\"menuitemradio\",\"option\",\"progressbar\",\"radio\",\"scrollbar\",\"searchbox\",\"slider\",\"spinbutton\",\"status\",\"switch\",\"tab\",\"tabpanel\",\"textbox\",\"timer\",\"tooltip\",\"tree\",\"treeitem\"]},Ti),lh=function(e){var t=null;return(e=ih.role[e])&&e.implicit?Bd(e.implicit):t},uh=function(e){return!!Km(e).length};function sh(e){var t=(1<arguments.length&&void 0!==arguments[1]?arguments[1]:{}).popupRoles,n=Xs(e);if(!(t=null!=t?t:ps[\"aria-haspopup\"].values).includes(n))return!1;if(t=(e=>{for(;e=e.parent;)if(null!==Xs(e,{noPresentational:!0}))return e;return null})(e),ch(t))return!0;if(!(n=e.props.id))return!1;if(e.actualNode)return t=Ml(e.actualNode).querySelectorAll('[aria-owns~=\"'.concat(n,'\"][role~=\"combobox\"]:not(select),\\\\n     [aria-controls~=\"').concat(n,'\"][role~=\"combobox\"]:not(select)')),Array.from(t).some(ch);throw new Error(\"Unable to determine combobox popup without an actualNode\")}var ch=function(e){return e&&\"combobox\"===Xs(e)},dh=function(e){return e=_l(e),Oc(e)},ph=f\\\nunction(e){return(e=gs.ariaRoles[e])&&Array.isArray(e.requiredAttrs)?M(e.requiredAttrs):[]},fh=function(e){return(e=gs.ariaRoles[e])&&Array.isArray(e.requiredContext)?M(e.requiredContext):null},mh=function(e){return(e=gs.ariaRoles[e])&&Array.isArray(e.requiredOwned)?M(e.requiredOwned):null},hh=function(e,t){var n,r=(e=e instanceof ua?e:_l(e)).attr(t),a=gs.ariaAttrs[t];if(!a)return!0;if(a.allowEmpty&&(!r||\"\"===r.trim()))return!0;switch(a.type){case\"boolean\":return[\"true\",\"false\"].includes(r.toLowerCase());case\"nmtoken\":return\"string\"==typeof r&&a.values.includes(r.toLowerCase());case\"nmtokens\":return(n=Yp(r)).reduce((function(e,t){return e&&a.values.includes(t)}),0!==n.length);case\"idref\":try{var o=Pl(e.actualNode);return!(!r||!o.getElementById(r))}catch(e){throw new TypeError(\"Cannot resolve id references for partial DOM\")}case\"idrefs\":return us(e,t).some((function(e){return!!e}));case\"string\":return\"\"!==r.trim();case\"decimal\":return!(!(n=r.match(/^[-+]?([0-9]*)\\\\.?([0-9]*)$/))||!n[1]&&\\\n!n[2]);case\"int\":return o=void 0!==a.minValue?a.minValue:-1/0,/^[-+]?[0-9]+$/.test(r)&&parseInt(r)>=o}},gh=function(e){return!!gs.ariaAttrs[e]};var vh=[\"cell-header-not-in-table\",\"cell-header-not-th\",\"header-refs-self\",\"empty-hdrs\"],bh=vh[0],yh=vh[1],Dh=vh[2],wh=vh[3];function xh(e){return\"caption\"===e.props.nodeName}var Eh={};ce(Eh,{getAriaRolesByType:function(){return eh},getAriaRolesSupportingNameFromContent:function(){return nh},getElementSpec:function(){return Us},getElementsByContentType:function(){return Ds},getGlobalAriaAttrs:function(){return ws},implicitHtmlRoles:function(){return Ss}}),Ni=du;var Ah=[\"alert\",\"log\",\"status\"];function Fh(e){return e=t.getComputedStyle((e=>{for(var t=e,n=e.textContent.trim(),r=n;r===n&&void 0!==t;){var a=-1;if(0===(e=t).children.length)return e;for(;a++,\"\"===(r=e.children[a].textContent.trim())&&a+1<e.children.length;);t=e.children[a]}return e})(e)),{fontWeight:(e=>{switch(e){case\"lighter\":return 100;case\"normal\":return 400;case\"bold\":return 700\\\n;case\"bolder\":return 900}return e=parseInt(e),isNaN(e)?400:e})(e.getPropertyValue(\"font-weight\")),fontSize:parseInt(e.getPropertyValue(\"font-size\")),isItalic:\"italic\"===e.getPropertyValue(\"font-style\")}}function Ch(e,t,n){return n.reduce((function(n,r){return n||(!r.size||e.fontSize/r.size>t.fontSize)&&(!r.weight||e.fontWeight-r.weight>t.fontWeight)&&(!r.italic||e.isItalic&&!t.isItalic)}),!1)}var kh=/[;,\\\\s]/,Rh=/^[0-9.]+$/;ce(Cn={},{aria:function(){return Um},color:function(){return Nh},dom:function(){return Ol},forms:function(){return ig},matches:function(){return Hs},math:function(){return hu},standards:function(){return Eh},table:function(){return jm},text:function(){return ls},utils:function(){return sa}});var Nh={},Th=(ce(Nh,{Color:function(){return md},centerPointOfRect:function(){return Th},elementHasImage:function(){return sd},elementIsDistinct:function(){return _h},filteredRectStack:function(){return Mh},flattenColors:function(){return Bh},flattenShadowColors:function(){return\\\n Lh},getBackgroundColor:function(){return eg},getBackgroundStack:function(){return qh},getContrast:function(){return rg},getForegroundColor:function(){return ag},getOwnBackgroundColor:function(){return gd},getRectStack:function(){return Oh},getStackingContext:function(){return Kh},getStrokeColorsFromShadows:function(){return Hh},getTextShadowColors:function(){return Yh},hasValidContrastRatio:function(){return og},incompleteData:function(){return ud},parseTextShadows:function(){return Wh},stackingContextToColor:function(){return Xh}}),function(e){if(!(e.left>t.innerWidth||t.innerHeight<e.top))return{x:Math.min(Math.ceil(e.left+e.width/2),t.innerWidth-1),y:Math.min(Math.ceil(e.top+e.height/2),t.innerHeight-1)}});function Sh(e){return e.getPropertyValue(\"font-family\").split(/[,;]/g).map((function(e){return e.trim().toLowerCase()}))}var _h=function(e,n){var r,a=t.getComputedStyle(e);return\"none\"!==a.getPropertyValue(\"background-image\")||!![\"border-bottom\",\"border-top\",\"outline\"].reduce((fu\\\nnction(e,t){var n=new md;return n.parseString(a.getPropertyValue(t+\"-color\")),e||\"none\"!==a.getPropertyValue(t+\"-style\")&&0<parseFloat(a.getPropertyValue(t+\"-width\"))&&0!==n.alpha}),!1)||(r=t.getComputedStyle(n),Sh(a)[0]!==Sh(r)[0])||(e=[\"text-decoration-line\",\"text-decoration-style\",\"font-weight\",\"font-style\",\"font-size\"].reduce((function(e,t){return e||a.getPropertyValue(t)!==r.getPropertyValue(t)}),!1),(n=a.getPropertyValue(\"text-decoration\")).split(\" \").length<3?e||n!==r.getPropertyValue(\"text-decoration\"):e)},Oh=function(e){var t=es(e);return!(e=zc(e))||e.length<=1?[t]:e.some((function(e){return void 0===e}))?null:(e.splice(0,0,t),e)},Mh=function(e){var t,n,r=Oh(e);return r&&1===r.length?r[0]:r&&1<r.length?(t=r.shift(),r.forEach((function(a,o){var i,l;0!==o&&(i=r[o-1],l=r[o],n=i.every((function(e,t){return e===l[t]}))||t.includes(e))})),n?r[0]:(ud.set(\"bgColor\",\"elmPartiallyObscuring\"),null)):(ud.set(\"bgColor\",\"outsideViewport\"),null)},Ph=[\"hue\",\"saturation\",\"color\",\"luminosity\"],\\\nIh={normal:function(e,t){return t},multiply:function(e,t){return t*e},screen:function(e,t){return e+t-e*t},overlay:function(e,t){return this[\"hard-light\"](t,e)},darken:function(e,t){return Math.min(e,t)},lighten:function(e,t){return Math.max(e,t)},\"color-dodge\":function(e,t){return 0===e?0:1===t?1:Math.min(1,e/(1-t))},\"color-burn\":function(e,t){return 1===e?1:0===t?0:1-Math.min(1,(1-e)/t)},\"hard-light\":function(e,t){return t<=.5?this.multiply(e,2*t):this.screen(e,2*t-1)},\"soft-light\":function(e,t){return t<=.5?e-(1-2*t)*e*(1-e):e+(2*t-1)*((e<=.25?((16*e-12)*e+4)*e:Math.sqrt(e))-e)},difference:function(e,t){return Math.abs(e-t)},exclusion:function(e,t){return e+t-2*e*t},hue:function(e,t){return t.setSaturation(e.getSaturation()).setLuminosity(e.getLuminosity())},saturation:function(e,t){return e.setSaturation(t.getSaturation()).setLuminosity(e.getLuminosity())},color:function(e,t){return t.setLuminosity(e.getLuminosity())},luminosity:function(e,t){return e.setLuminosity(t.getLuminosity(\\\n))}};function Bh(e,t){var n,r=((e,t,n)=>{var r;return Ph.includes(n)?Ih[n](e,t):(r=new md,[\"r\",\"g\",\"b\"].forEach((function(a){r[a]=Ih[n](e[a],t[a])})),r)})(t,e,2<arguments.length&&void 0!==arguments[2]?arguments[2]:\"normal\"),a=jh(e.red,e.alpha,t.red,t.alpha,255*r.r),o=jh(e.green,e.alpha,t.green,t.alpha,255*r.g);r=jh(e.blue,e.alpha,t.blue,t.alpha,255*r.b);return 0===(e=(t=e.alpha+t.alpha*(1-e.alpha),e=0,n=1,Math.min(Math.max(e,t),n)))?new md(a,o,r,e):(t=Math.round(a/e),n=Math.round(o/e),a=Math.round(r/e),new md(t,n,a,e))}function jh(e,t,n,r,a){return t*(1-r)*e+t*r*a+(1-t)*r*n}function Lh(e,t){var n=e.alpha,r=(1-n)*t.red+n*e.red;return new md(r,(1-n)*t.green+n*e.green,(1-n)*t.blue+n*e.blue,e.alpha+t.alpha*(1-e.alpha))}function qh(e){for(var n=zc(e).map((function(n){return(e=>{var n=e.indexOf(r.body),a=gd(t.getComputedStyle(r.documentElement));return 1<n&&0===a.alpha&&!sd(r.documentElement)&&(1<n&&(e.splice(n,1),e.push(r.body)),0<(a=e.indexOf(r.documentElement)))&&(e.splice(a,1),e.push(r.d\\\nocumentElement)),e})(n=Ed(n,e))})),a=0;a<n.length;a++){var o=n[a];if(o[0]!==e)return ud.set(\"bgColor\",\"bgOverlap\"),null;if(0!==a&&!((e,t)=>{if(e!==t){if(null===e||null===t)return;if(e.length!==t.length)return;for(var n=0;n<e.length;++n)if(e[n]!==t[n])return}return 1})(o,n[0]))return ud.set(\"bgColor\",\"elmPartiallyObscuring\"),null}return n[0]||null}var zh=.54,Vh=.5,Gh=1.5,$h=[\"top\",\"right\",\"bottom\",\"left\"];function Hh(e){var t=void 0!==(t=(1<arguments.length&&void 0!==arguments[1]?arguments[1]:{}).ignoreEdgeCount)&&t;e=(e=>{var t,n={},r=K(e);try{for(r.s();!(t=r.n()).done;){var a=t.value,o=a.colorStr,i=a.pixels,l=(null!=n[o]||(n[o]={top:[],right:[],bottom:[],left:[]}),n[o]),u=V(i,2),s=u[0],c=u[1];Vh<s?l.right.push(s):Vh<-s&&l.left.push(-s),Vh<c?l.bottom.push(c):Vh<-c&&l.top.push(-c)}}catch(e){r.e(e)}finally{r.f()}return n})(e),e=Object.entries(e).map((function(e){var t=(e=V(e,2))[0],n=e[1];e=$h.filter((function(e){return 0!==n[e].length})).length;return{colorStr:t,sides:n,edgeCount:e}}));\\\nreturn!t&&e.some((function(e){return 1<(e=e.edgeCount)&&e<4}))?null:e.map(Uh).filter((function(e){return null!==e}))}function Uh(e){var t,n,r=e.colorStr,a=e.sides;return 4!==e.edgeCount?null:((e=new md).parseString(r),n=!(t=0),$h.forEach((function(e){t+=a[e].length/4,n=n&&a[e].every((function(e){return Gh<e}))})),n||(e.alpha=1-Math.pow(zh,t)),e)}function Wh(e){var t={pixels:[]},n=[t];if(!(o=e.trim()))return[];for(;o;){var r=o.match(/^[a-z]+(\\\\([^)]+\\\\))?/i)||o.match(/^#[0-9a-f]+/i),a=o.match(/^([0-9.-]+)px/i)||o.match(/^(0)/);if(r)xa(!t.colorStr,\"Multiple colors identified in text-shadow: \".concat(e)),o=o.replace(r[0],\"\").trim(),t.colorStr=r[0];else if(a){xa(t.pixels.length<3,\"Too many pixel units in text-shadow: \".concat(e));var o=o.replace(a[0],\"\").trim();r=parseFloat((\".\"===a[1][0]?\"0\":\"\")+a[1]);t.pixels.push(r)}else{if(\",\"!==o[0])throw new Error(\"Unable to process text-shadows: \".concat(o));xa(2<=t.pixels.length,\"Missing pixel value in text-shadow: \".concat(e)),n.push(t={pixels:[]}),\\\no=o.substr(1).trim()}}return n.forEach((function(e){2===(e=e.pixels).length&&e.push(0)})),n}function Yh(e){var n,r=(n=1<arguments.length&&void 0!==arguments[1]?arguments[1]:{}).minRatio,a=n.maxRatio,o=n.ignoreEdgeCount,i=[],l=t.getComputedStyle(e);if(\"none\"!==(n=l.getPropertyValue(\"text-shadow\"))){e=l.getPropertyValue(\"font-size\");var u,s=parseInt(e),c=(xa(!1===isNaN(s),\"Unable to determine font-size value \".concat(e)),[]),d=K(Wh(n));try{for(d.s();!(u=d.n()).done;){var p=u.value,f=p.colorStr||l.getPropertyValue(\"color\"),m=V(p.pixels,3),h=m[0],g=m[1],v=m[2],b=void 0===v?0:v;if(!(a&&s*a<=b))if(r&&b<s*r)c.push({colorStr:f,pixels:p.pixels});else{if(0<c.length){var y=Hh(c,{ignoreEdgeCount:o});if(null===y)return null;i.push.apply(i,M(y)),c.splice(0,c.length)}var D=(e=>{var t=e.colorStr,n=e.offsetY,r=e.blurRadius,a=e.fontSize;return e.offsetX>r||r<n?new md(0,0,0,0):((e=new md).parseString(t),e.alpha*=((e,t)=>0===e?1:.185/(e/t+.4))(r,a),e)})({colorStr:f,offsetX:h,offsetY:g,blurRadius:b,fontSiz\\\ne:s});i.push(D)}}}catch(e){d.e(e)}finally{d.f()}if(0<c.length){if(null===(e=Hh(c,{ignoreEdgeCount:o})))return null;i.push.apply(i,M(e))}}return i}function Kh(e,t){var n,r,a=_l(e);return a._stackingContext||(n=[],r=new Map,(t=null!=t?t:qh(e)).forEach((function(e){var t=(t=e=_l(e),(o=new md).parseString(t.getComputedStylePropertyValue(\"background-color\")),o),a=e._stackingOrder.filter((function(e){return!!e.vNode})),o=(a.forEach((function(e,t){e=e.vNode;var o=null==(o=a[t-1])?void 0:o.vNode;o=Qh(r,e,o);0!==t||r.get(e)||n.unshift(o),r.set(e,o)})),null==(o=a[a.length-1])?void 0:o.vNode);e=Qh(r,e,o);a.length||n.unshift(e),e.bgColor=t})),a._stackingContext=n)}function Xh(e){var t;return null!=(t=e.descendants)&&t.length?(t=Bh(e.descendants.reduce(Zh,Jh()),e.bgColor,e.descendants[0].blendMode)).alpha*=e.opacity:(t=e.bgColor).alpha*=e.opacity,{color:t,blendMode:e.blendMode}}function Zh(e,t){return e=e instanceof md?e:Xh(e).color,Bh(Xh(t).color,e,t.blendMode)}function Jh(e,t){return{vNode:e,ance\\\nstor:t,opacity:parseFloat(null!=(t=null==e?void 0:e.getComputedStylePropertyValue(\"opacity\"))?t:1),bgColor:new md(0,0,0,0),blendMode:(null==e?void 0:e.getComputedStylePropertyValue(\"mix-blend-mode\"))||void 0,descendants:[]}}function Qh(e,t,n){var r=e.get(n);e=null!=(e=e.get(t))?e:Jh(t,r);return r&&n!==t&&!r.descendants.includes(e)&&r.descendants.unshift(e),e}function eg(e){var n=1<arguments.length&&void 0!==arguments[1]?arguments[1]:[],a=2<arguments.length&&void 0!==arguments[2]?arguments[2]:.1,o=_l(e),i=o._cache.getBackgroundColor;return i?(n.push.apply(n,M(i.bgElms)),ud.set(\"bgColor\",i.incompleteData),i.bgColor):(i=((e,n,a)=>{var o=qh(e);if(!o)return null;var i=Lc(e);(a=null!=(a=Yh(e,{minRatio:a,ignoreEdgeCount:!0}))?a:[]).length&&(a=[{color:a.reduce(Lh)}]);for(var l=0;l<o.length;l++){var u=o[l],s=t.getComputedStyle(u);if(sd(u,s))return n.push(u),null;var c=gd(s);if(0!==c.alpha){if(\"inline\"!==s.getPropertyValue(\"display\")&&!tg(u,i))return n.push(u),ud.set(\"bgColor\",\"elmPartiallyObscu\\\nred\"),null;if(n.push(u),1===c.alpha)break}}var d=(a=(d=Kh(e,o)).map(Xh).concat(a),((e,n)=>{var a,o,i,l,u=[];return n||(n=r.documentElement,l=r.body,n=t.getComputedStyle(n),a=t.getComputedStyle(l),o=gd(n),l=0!==(i=gd(a)).alpha&&tg(l,e.getBoundingClientRect()),(0!==i.alpha&&0===o.alpha||l&&1!==i.alpha)&&u.unshift({color:i,blendMode:ng(a.getPropertyValue(\"mix-blend-mode\"))}),0===o.alpha)||l&&1===i.alpha||u.unshift({color:o,blendMode:ng(n.getPropertyValue(\"mix-blend-mode\"))}),u})(e,o.includes(r.body)));return a.unshift.apply(a,M(d)),0===a.length?new md(255,255,255,1):(e=a.reduce((function(e,t){return Bh(t.color,e.color instanceof md?e.color:e,t.blendMode)})),Bh(e.color instanceof md?e.color:e,new md(255,255,255,1)))})(e,n,a),o._cache.getBackgroundColor={bgColor:i,bgElms:n,incompleteData:ud.get(\"bgColor\")},i)}function tg(e,n){n=Array.isArray(n)?n:[n];var r=e.getBoundingClientRect(),a=r.right,o=r.bottom,i=t.getComputedStyle(e).getPropertyValue(\"overflow\");return([\"scroll\",\"auto\"].includes(i)\\\n||e instanceof t.HTMLHtmlElement)&&(a=r.left+e.scrollWidth,o=r.top+e.scrollHeight),n.every((function(e){return e.top>=r.top&&e.bottom<=o&&e.left>=r.left&&e.right<=a}))}function ng(e){return e||void 0}var rg=function(e,t){return t&&e?(t.alpha<1&&(t=Bh(t,e)),e=e.getRelativeLuminance(),t=t.getRelativeLuminance(),(Math.max(t,e)+.05)/(Math.min(t,e)+.05)):null};function ag(e,n,r){for(var a=3<arguments.length&&void 0!==arguments[3]?arguments[3]:{},o=t.getComputedStyle(e),i=[],l=0,u=[function(){var e,t,n=o,r=void 0===(r=(r=a).textStrokeEmMin)?0:r;return 0===(t=parseFloat(n.getPropertyValue(\"-webkit-text-stroke-width\")))||(e=n.getPropertyValue(\"font-size\"),t/=parseFloat(e),isNaN(t))||t<r?null:(e=n.getPropertyValue(\"-webkit-text-stroke-color\"),(new md).parseString(e))},function(){return e=o,(new md).parseString(e.getPropertyValue(\"-webkit-text-fill-color\")||e.getPropertyValue(\"color\"));var e},function(){return Yh(e,{minRatio:0})}];l<u.length;l++){var s=(0,u[l])();if(s&&(i=i.concat(s),1===s.alpha\\\n))break}var c=i.reduce((function(e,t){return Bh(e,t)}));return null===(r=null==r?eg(e,[]):r)?(r=ud.get(\"bgColor\"),ud.set(\"fgColor\",r),null):Bh(((e,t,n)=>{for(;t;){var r;1===t.opacity&&t.ancestor||(e.alpha*=t.opacity,r=(null==(r=t.ancestor)?void 0:r.descendants)||n,(r=(r=1!==t.opacity?r.slice(0,r.indexOf(t)):r).map(Xh)).length&&(r=r.reduce((function(e,t){return Bh(t.color,e.color instanceof md?e.color:e)}),{color:new md(0,0,0,0),blendMode:\"normal\"}),e=Bh(e,r))),t=t.ancestor}return e})(c,function e(t,n){var r,a=K(t);try{for(a.s();!(r=a.n()).done;){var o,i=r.value;if((null==(o=i.vNode)?void 0:o.actualNode)===n)return i;var l=e(i.descendants,n);if(l)return l}}catch(e){a.e(e)}finally{a.f()}}(r=Kh(e),e),r),new md(255,255,255,1))}var og=function(e,t,n,r){return e=rg(e,t),{isValid:(t=r&&Math.ceil(72*n)/96<14||!r&&Math.ceil(72*n)/96<18?4.5:3)<e,contrastRatio:e,expectedContrastRatio:t}},ig={},lg=(ce(ig,{isAriaCombobox:function(){return cc},isAriaListbox:function(){return sc},isAriaRange:function\\\n(){return pc},isAriaTextbox:function(){return uc},isDisabled:function(){return ug},isNativeSelect:function(){return lc},isNativeTextbox:function(){return ic}}),[\"fieldset\",\"button\",\"select\",\"input\",\"textarea\"]),ug=function e(t){var n,r,a=t._isDisabled;return\"boolean\"!=typeof a&&(n=t.props.nodeName,r=t.attr(\"aria-disabled\"),a=!(!lg.includes(n)||!t.hasAttr(\"disabled\"))||(r?\"true\"===r.toLowerCase():!!t.parent&&e(t.parent)),t._isDisabled=a),a};function sg(e,t){var n=null==(n=t.data)?void 0:n.headingOrder,r=dg(t.node.ancestry,1);return n&&(t=n.map((function(e){return O({},e,{ancestry:r.concat(e.ancestry)})})),-1===(n=((e,t)=>{for(;t.length;){var n=cg(e,t);if(-1!==n)return n;t=dg(t,1)}return-1})(e,r))?e.push.apply(e,M(t)):e.splice.apply(e,[n,0].concat(M(t)))),e}function cg(e,t){return e.findIndex((function(e){return Gf(e.ancestry,t)}))}function dg(e,t){return e.slice(0,e.length-t)}function pg(e,t){return e=e.boundingClientRect,t=t.boundingClientRect,e.top>=t.top&&e.left>=t.left&&e.bottom<=t.\\\nbottom&&e.right<=t.right}function fg(e){return{width:Math.round(10*e.width)/10,height:Math.round(10*e.height)/10}}function mg(e,t){return Vp(e,t)&&!as(t)}function hg(e){return e.map((function(e){return e.actualNode}))}function gg(e,t){var n=1<arguments.length&&void 0!==t&&t;return e.map((function(e){return{vChild:e,nested:n}}))}function vg(e){return\"\"!==(e||\"\").trim()}function bg(e){return e=Nc(e,{emoji:!0,nonBmp:!0,punctuations:!0}),Ns(e)}function yg(e){return null!==(e=Zf(e.attr(\"tabindex\")))&&e<0}var Dg=[\"block\",\"list-item\",\"table\",\"flex\",\"grid\",\"inline-block\"];function wg(e){return e=t.getComputedStyle(e).getPropertyValue(\"display\"),-1!==Dg.indexOf(e)||\"table-\"===e.substr(0,6)}function xg(e,t){return e=e.getRelativeLuminance(),t=t.getRelativeLuminance(),(Math.max(e,t)+.05)/(Math.min(e,t)+.05)}var Eg=[\"block\",\"list-item\",\"table\",\"flex\",\"grid\",\"inline-block\"];function Ag(e){return e=t.getComputedStyle(e).getPropertyValue(\"display\"),-1!==Eg.indexOf(e)||\"table-\"===e.substr(0,6)}var Fg=\\\ncl((function(e,n){function r(e,t){return a.getPropertyValue(e)===t}var a=t.getComputedStyle(e,n);return r(\"content\",\"none\")||r(\"display\",\"none\")||r(\"visibility\",\"hidden\")||!1===r(\"position\",\"absolute\")||0===gd(a).alpha&&r(\"background-image\",\"none\")?0:(e=Cg(a.getPropertyValue(\"width\")),n=Cg(a.getPropertyValue(\"height\")),\"px\"!==e.unit||\"px\"!==n.unit?0===e.value||0===n.value?0:1/0:e.value*n.value)}));function Cg(e){var t=(e=V(e.match(/^([0-9.]+)([a-z]+)$/i)||[],3))[1];e=void 0===(e=e[2])?\"\":e;return{value:parseFloat(void 0===t?\"\":t),unit:e.toLowerCase()}}var kg={ARTICLE:!0,ASIDE:!0,NAV:!0,SECTION:!0},Rg={alert:!0,alertdialog:!0,application:!0,article:!0,banner:!1,complementary:!0,contentinfo:!0,dialog:!0,form:!0,log:!0,main:!0,navigation:!0,region:!0,search:!1,status:!0,tabpanel:!0};function Ng(e,t,n,r){var a=ys(e);if(!(n=n||fh(a)))return null;for(var o=n.includes(\"group\"),i=r?e:e.parent;i;){var l=Xs(i,{noPresentational:!0});if(l){if(\"group\"!==l||!o)return n.includes(l)?null:n;t.includes(\\\na)&&n.push(a),n=n.filter((function(e){return\"group\"!==e}))}i=i.parent}return n}function Tg(e){return 3===(e=e.vNode).props.nodeType?0<e.props.nodeValue.trim().length:Uc(e,!1,!0)}var Sg=cl((function(e){var t;if(e)return(t=Xs(e,{noPresentational:!0,chromium:!0}))?ed(t):Sg(e.parent)}));function _g(e){var t,n,r=(1<arguments.length&&void 0!==arguments[1]?arguments[1]:{}).invalidTableRowAttrs,a=2<arguments.length?arguments[2]:void 0;r=null!=(t=null==r||null==(t=r.filter)?void 0:t.call(r,(function(e){return a.hasAttr(e)})))?t:[];return 0===r.length||!(t=(t=(e=>{if(e.parent)return Wd(e,'table:not([role]), [role~=\"treegrid\"], [role~=\"table\"], [role~=\"grid\"]')})(a))&&Xs(t))||\"treegrid\"===t||(n=\"row\".concat(1<r.length?\"Plural\":\"Singular\"),this.data({messageKey:n,invalidAttrs:r,ownerRole:t}),!1)}function Og(e,t,n){var r=(a=n.props).nodeName,a=a.type,o=(e=>e?(e=e.toLowerCase(),[\"mixed\",\"true\"].includes(e)?e:\"false\"):\"\")(n.attr(\"aria-checked\"));return\"input\"!==r||\"checkbox\"!==a||!o||o===(r=(e=>e.pro\\\nps.indeterminate?\"mixed\":e.props.checked?\"true\":\"false\")(n))||(this.data({messageKey:\"checkbox\",checkState:r}),!1)}var Mg={row:_g,checkbox:Og};var Pg=function(e,t){try{return\"svg\"===t.props.nodeName||!!Wd(t,\"svg\")}catch(e){return!1}},Ig=[function(e,t){return Bg(t)},function(e,t){return\"area\"!==t.props.nodeName},function(e,t){return!Pg(0,t)},function(e,t){return rs(t)},function(e,t){return as(t)||!jg(t)},function(e){return!rd(e,{noLengthCompare:!0})}];function Bg(e){return\"widget\"===ed(e)}var jg=cl((function e(t){return!(null==t||!t.parent)&&(!(!Bg(t.parent)||!as(t.parent))||e(t.parent))})),Lg=function(e,t){var n=ys(t);return!(n&&![\"none\",\"presentation\"].includes(n)&&!(fs[n]||{}).accessibleNameRequired&&!rs(t))},qg=function(e,t,n){return n.initiator},zg={emoji:!0,nonBmp:!1,punctuations:!0},Vg={\"abstractrole-evaluate\":function(e,t,n){return 0<(n=Yp(n.attr(\"role\")).filter((function(e){return\"abstract\"===ed(e)}))).length&&(this.data(n),!0)},\"accesskeys-after\":function(e){var t={};return e.\\\nfilter((function(e){if(e.data){var n=e.data.toUpperCase();if(!t[n])return(t[n]=e).relatedNodes=[],!0;t[n].relatedNodes.push(e.relatedNodes[0])}return!1})).map((function(e){return e.result=!!e.relatedNodes.length,e}))},\"accesskeys-evaluate\":function(e,t,n){return nu(n)||(this.data(n.attr(\"accesskey\")),this.relatedNodes([e])),!0},\"alt-space-value-evaluate\":function(e,t,n){return\"string\"==typeof(n=n.attr(\"alt\"))&&/^\\\\s+$/.test(n)},\"aria-allowed-attr-evaluate\":function(e,t,n){var r,a=[],o=Xs(n),i=Wm(o),l=(Array.isArray(t[o])&&(i=tm(t[o].concat(i))),K(n.attrNames));try{for(l.s();!(r=l.n()).done;){var u=r.value;!gh(u)||i.includes(u)||((e,t,n)=>\"aria-required\"===e&&\"false\"===t||!(\"aria-multiline\"!==e||\"false\"!==t||!n.hasAttr(\"contenteditable\")))(u,n.attr(u),n)||a.push(u)}}catch(e){l.e(e)}finally{l.f()}return!a.length||(this.data(a.map((function(e){return e+'=\"'+n.attr(e)+'\"'}))),!(o||qf(n)||rs(n))&&void 0)},\"aria-allowed-attr-matches\":function(e,t){var n=/^aria-/,r=t.attrNames;if(r.length)for(\\\nvar a=0,o=r.length;a<o;a++)if(n.test(r[a]))return!0;return!1},\"aria-allowed-role-evaluate\":function(e){var t=2<arguments.length?arguments[2]:void 0,n=void 0===(n=(r=1<arguments.length&&void 0!==arguments[1]?arguments[1]:{}).allowImplicit)||n,r=void 0===(r=r.ignoredTags)?[]:r,a=t.props.nodeName;return!!r.map((function(e){return e.toLowerCase()})).includes(a)||!(r=Qm(t,n)).length||(this.data(r),!nc(t)&&void 0)},\"aria-allowed-role-matches\":function(e,t){return null!==ys(t,{dpub:!0,fallback:!0})},\"aria-busy-evaluate\":function(e,t,n){return\"true\"===n.attr(\"aria-busy\")},\"aria-conditional-attr-evaluate\":function(e,t,n){var r=Xs(n);return!Mg[r]||Mg[r].call(this,e,t,n)},\"aria-conditional-checkbox-attr-evaluate\":Og,\"aria-conditional-row-attr-evaluate\":_g,\"aria-errormessage-evaluate\":function(e,t,n){t=Array.isArray(t)?t:[];var r=n.attr(\"aria-errormessage\"),a=n.hasAttr(\"aria-errormessage\"),o=n.attr(\"aria-invalid\");return!n.hasAttr(\"aria-invalid\")||\"false\"===o||-1!==t.indexOf(r)||!a||(this.data(Yp(\\\nr)),function(e){if(\"\"===e.trim())return gs.ariaAttrs[\"aria-errormessage\"].allowEmpty;var t;try{t=e&&us(n,\"aria-errormessage\")[0]}catch(t){return void this.data({messageKey:\"idrefs\",values:Yp(e)})}return t?nc(t)?\"alert\"===ys(t)||\"assertive\"===t.getAttribute(\"aria-live\")||\"polite\"===t.getAttribute(\"aria-live\")||-1<Yp(n.attr(\"aria-describedby\")).indexOf(e):(this.data({messageKey:\"hidden\",values:Yp(e)}),!1):void 0}.call(this,r))},\"aria-has-attr-matches\":function(e,t){var n=/^aria-/;return t.attrNames.some((function(e){return n.test(e)}))},\"aria-hidden-body-evaluate\":function(e,t,n){return\"true\"!==n.attr(\"aria-hidden\")},\"aria-hidden-focus-matches\":function(e){return function e(t){return!t||\"true\"!==t.getAttribute(\"aria-hidden\")&&e(ou(t))}(ou(e))},\"aria-label-evaluate\":function(e,t,n){return!!Ns(ds(n))},\"aria-labelledby-evaluate\":function(e,t,n){try{return!!Ns(cs(n))}catch(e){}},\"aria-level-evaluate\":function(e,t,n){if(n=n.attr(\"aria-level\"),!(6<(n=parseInt(n,10))))return!0},\"aria-prohibited\\\n-attr-evaluate\":function(e){var t,n=2<arguments.length?arguments[2]:void 0,r=(null==(r=1<arguments.length&&void 0!==arguments[1]?arguments[1]:{})?void 0:r.elementsAllowedAriaLabel)||[],a=n.props.nodeName,o=Xs(n,{chromium:!0,fallback:!0});return 0!==(r=((e,t,n,r)=>{var a=gs.ariaRoles[t];return a?a.prohibitedAttrs||[]:t||r.includes(n)||\"widget\"===Sg(e)?[]:[\"aria-label\",\"aria-labelledby\"]})(n,o,a,r).filter((function(e){return!!n.attrNames.includes(e)&&\"\"!==Ns(n.attr(e))}))).length&&(t=null!==o?\"hasRole\":\"noRole\",this.data({role:o,nodeName:a,messageKey:t+=1<r.length?\"Plural\":\"Singular\",prohibited:r}),o=bc(n,{subtreeDescendant:!0}),\"\"===Ns(o)||void 0)},\"aria-required-attr-evaluate\":function(e){var t,n=1<arguments.length&&void 0!==arguments[1]?arguments[1]:{},r=2<arguments.length?arguments[2]:void 0,a=ys(r),o=r.attrNames,i=ph(a);return Array.isArray(n[a])&&(i=tm(n[a],i)),!(a&&o.length&&i.length&&(n=r,\"separator\"!==a||rs(n))&&(o=r,\"combobox\"!==a||\"false\"!==o.attr(\"aria-expanded\"))&&(\"slider\"!\\\n==a||null==(n=r.attr(\"aria-valuetext\"))||!n.trim())&&(t=Us(r),(o=i.filter((function(e){return!(r.attr(e)||void 0!==(null==(n=(n=t).implicitAttrs)?void 0:n[e]));var n}))).length)&&(this.data(o),1))},\"aria-required-children-evaluate\":function(e,t,n){t=t&&Array.isArray(t.reviewEmpty)?t.reviewEmpty:[];var r,a,o,i=ys(n,{dpub:!0}),l=mh(i);return null===l||((a=(r=((e,t)=>{function n(){if(3===r.props.nodeType&&a.push({vNode:r,role:null}),1!==r.props.nodeType||!nc(r))return 1;var e,n=Xs(r,{noPresentational:!0}),i=(e=r,ws().find((function(t){return e.hasAttr(t)}))),l=!!i||rs(r);!n&&!l||[\"group\",\"rowgroup\"].includes(n)&&t.some((function(e){return e===n}))?o.push.apply(o,M(r.children)):(n||l)&&a.push({role:n,attr:i||\"tabindex\",vNode:r})}for(var r,a=[],o=ec(e);r=o.shift();)n();return a})(n,l)).filter((function(e){var t=e.role;return 1===e.vNode.props.nodeType&&!l.includes(t)}))).length?(this.relatedNodes(a.map((function(e){return e.vNode}))),this.data({messageKey:\"unallowed\",values:a.map((function(\\\ne){var t=e.vNode,n=(e=e.attr,t.props),r=n.nodeName;return 3===n.nodeType?\"#text\":(n=ys(t,{dpub:!0}))?\"[role=\".concat(n,\"]\"):e?r+\"[\".concat(e,\"]\"):r})).filter((function(e,t,n){return n.indexOf(e)===t})).join(\", \")}),!1):(o=l,!!r.some((function(e){return(e=e.role)&&o.includes(e)}))||(\"true\"===n.attr(\"aria-busy\")?(this.data({messageKey:\"aria-busy\"}),!0):(this.data(l),!(!t.includes(i)||r.some(Tg))&&void 0))))},\"aria-required-children-matches\":function(e,t){return t=ys(t,{dpub:!0}),!!mh(t)},\"aria-required-parent-evaluate\":function(e,t,n){var r=t&&Array.isArray(t.ownGroupRoles)?t.ownGroupRoles:[],a=Ng(n,r);if(!a)return!0;var o=(e=>{for(var t,n=[];e;)e.getAttribute(\"id\")&&(t=Aa(e.getAttribute(\"id\")),t=Pl(e).querySelector(\"[aria-owns~=\".concat(t,\"]\")))&&n.push(t),e=e.parentElement;return n.length?n:null})(e);if(o)for(var i=0,l=o.length;i<l;i++)if(!(a=Ng(_l(o[i]),r,a,!0)))return!0;return this.data(a),!1},\"aria-required-parent-matches\":function(e,t){return t=ys(t),!!fh(t)},\"aria-roledescription-\\\nevaluate\":function(e){var t=1<arguments.length&&void 0!==arguments[1]?arguments[1]:{},n=Xs(2<arguments.length?arguments[2]:void 0);return!!(t.supportedRoles||[]).includes(n)||!(!n||\"presentation\"===n||\"none\"===n)&&void 0},\"aria-unsupported-attr-evaluate\":function(e,t,n){return!!(n=n.attrNames.filter((function(t){var n=gs.ariaAttrs[t];return!!gh(t)&&(t=n.unsupported,\"object\"!==a(t)?!!t:!Hs(e,t.exceptions))}))).length&&(this.data(n),!0)},\"aria-valid-attr-evaluate\":function(e,t,n){t=Array.isArray(t.value)?t.value:[];var r=[],a=/^aria-/;return n.attrNames.forEach((function(e){-1===t.indexOf(e)&&a.test(e)&&!gh(e)&&r.push(e)})),!r.length||(this.data(r),!1)},\"aria-valid-attr-value-evaluate\":function(e,t,n){t=Array.isArray(t.value)?t.value:[];var r=\"\",a=\"\",i=[],l=/^aria-/,u=[\"aria-errormessage\"],s={\"aria-controls\":function(){var e=!1===[\"false\",null].includes(n.attr(\"aria-haspopup\"));return e&&(r='aria-controls=\"'.concat(n.attr(\"aria-controls\"),'\"'),a=\"controlsWithinPopup\"),\"false\"!==n.attr(\"a\\\nria-expanded\")&&\"false\"!==n.attr(\"aria-selected\")&&0==e},\"aria-current\":function(e){e||(r='aria-current=\"'.concat(n.attr(\"aria-current\"),'\"'),a=\"ariaCurrent\")},\"aria-owns\":function(){return\"false\"!==n.attr(\"aria-expanded\")},\"aria-describedby\":function(e){e||(r='aria-describedby=\"'.concat(n.attr(\"aria-describedby\"),'\"'),a=o._tree&&o._tree[0]._hasShadowRoot?\"noIdShadow\":\"noId\")},\"aria-labelledby\":function(e){e||(r='aria-labelledby=\"'.concat(n.attr(\"aria-labelledby\"),'\"'),a=o._tree&&o._tree[0]._hasShadowRoot?\"noIdShadow\":\"noId\")}};return n.attrNames.forEach((function(e){if(!u.includes(e)&&!t.includes(e)&&l.test(e)){var o,c=n.attr(e);try{o=hh(n,e)}catch(o){return r=\"\".concat(e,'=\"').concat(c,'\"'),void(a=\"idrefs\")}s[e]&&!s[e](o)||o||(\"\"===c&&(o=e,\"string\"!==(null==(o=gs.ariaAttrs[e])?void 0:o.type))?(r=e,a=\"empty\"):i.push(\"\".concat(e,'=\"').concat(c,'\"')))}})),i.length?(this.data(i),!1):!r||void this.data({messageKey:a,needsReview:r})},\"attr-non-space-content-evaluate\":function(e){var t=1<ar\\\nguments.length&&void 0!==arguments[1]?arguments[1]:{},n=2<arguments.length?arguments[2]:void 0;if(t.attribute&&\"string\"==typeof t.attribute)return n.hasAttr(t.attribute)?(n=n.attr(t.attribute),!!Ns(n)||(this.data({messageKey:\"emptyAttr\"}),!1)):(this.data({messageKey:\"noAttr\"}),!1);throw new TypeError(\"attr-non-space-content requires options.attribute to be a string\")},\"autocomplete-appropriate-evaluate\":function(e,t,n){var r,o,i;return\"input\"!==n.props.nodeName||(o={bday:[\"text\",\"search\",\"date\"],email:[\"text\",\"search\",\"email\"],username:[\"text\",\"search\",\"email\"],\"street-address\":[\"text\"],tel:[\"text\",\"search\",\"tel\"],\"tel-country-code\":[\"text\",\"search\",\"tel\"],\"tel-national\":[\"text\",\"search\",\"tel\"],\"tel-area-code\":[\"text\",\"search\",\"tel\"],\"tel-local\":[\"text\",\"search\",\"tel\"],\"tel-local-prefix\":[\"text\",\"search\",\"tel\"],\"tel-local-suffix\":[\"text\",\"search\",\"tel\"],\"tel-extension\":[\"text\",\"search\",\"tel\"],\"cc-number\":r=[\"text\",\"search\",\"number\",\"tel\"],\"cc-exp\":[\"text\",\"search\",\"month\",\"tel\"],\"cc-ex\\\np-month\":r,\"cc-exp-year\":r,\"cc-csc\":r,\"transaction-amount\":r,\"bday-day\":r,\"bday-month\":r,\"bday-year\":r,\"new-password\":[\"text\",\"search\",\"password\"],\"current-password\":[\"text\",\"search\",\"password\"],url:i=[\"text\",\"search\",\"url\"],photo:i,impp:i},\"object\"===a(t)&&Object.keys(t).forEach((function(e){o[e]||(o[e]=[]),o[e]=o[e].concat(t[e])})),i=(r=n.attr(\"autocomplete\").split(/\\\\s+/g).map((function(e){return e.toLowerCase()})))[r.length-1],!!Sc.stateTerms.includes(i))||(r=o[i],i=n.hasAttr(\"type\")?Ns(n.attr(\"type\")).toLowerCase():\"text\",i=Fm().includes(i)?i:\"text\",void 0===r?\"text\"===i:r.includes(i))},\"autocomplete-matches\":function(e,t){var n=t.attr(\"autocomplete\");if(!n||\"\"===Ns(n))return!1;if(n=t.props.nodeName,!1===[\"textarea\",\"input\",\"select\"].includes(n))return!1;var r=t.attr(\"aria-readonly\")||\"false\";return!t.hasAttr(\"readonly\")&&\"true\"!==r.toLowerCase()&&((\"input\"!==n||![\"submit\",\"reset\",\"button\",\"hidden\"].includes(t.props.type))&&(r=t.attr(\"aria-disabled\")||\"false\",!t.hasAttr(\"disabled\")\\\n&&\"true\"!==r.toLowerCase()&&(n=ys(t),(!((r=Zf(t.attr(\"tabindex\")))<0&&t.hasAttr(\"role\"))||void 0!==(n=gs.ariaRoles[n])&&\"widget\"===n.type)&&!(r<0&&t.actualNode&&!du(t)&&!nc(t)))))},\"autocomplete-valid-evaluate\":function(e,t,n){return n=n.attr(\"autocomplete\")||\"\",_c(n,t)},\"avoid-inline-spacing-evaluate\":function(e,t){return!(0<(t=t.cssProperties.filter((function(t){if(\"important\"===e.style.getPropertyPriority(t))return t}))).length&&(this.data(t),1))},\"braille-label-equivalent-evaluate\":function(e,t,n){var r;if(!(null!=(r=n.attr(\"aria-braillelabel\"))?r:\"\").trim())return!0;try{return\"\"!==Ns(kc(n))}catch(e){}},\"braille-roledescription-equivalent-evaluate\":function(e,t,n){var r=null!=(r=n.attr(\"aria-brailleroledescription\"))?r:\"\";return\"\"===Ns(r)||(\"string\"!=typeof(r=n.attr(\"aria-roledescription\"))?(this.data({messageKey:\"noRoleDescription\"}),!1):\"\"!==Ns(r)||(this.data({messageKey:\"emptyRoleDescription\"}),!1))},\"bypass-matches\":function(e,t,n){return!qg(0,0,n)||!!e.querySelector(\"a[href]\")\\\n},\"caption-evaluate\":function(e,t,n){return!fm(n,\"track\").some((function(e){return\"captions\"===(e.attr(\"kind\")||\"\").toLowerCase()}))&&void 0},\"caption-faked-evaluate\":function(e){var t=xs(e),n=t[0];return t.length<=1||n.length<=1||e.rows.length<=1||n.reduce((function(e,t,r){return e||t!==n[r+1]&&void 0!==n[r+1]}),!1)},\"color-contrast-evaluate\":function(e,n,r){var a=n.ignoreUnicode,o=n.ignoreLength,i=n.ignorePseudo,l=n.boldValue,u=n.boldTextPt,s=n.largeTextPt,c=n.contrastRatio,d=n.shadowOutlineEmMax,p=n.pseudoSizeThreshold;if(!du(e))return this.data({messageKey:\"hidden\"}),!0;var f=ac(r,!1,!0);if(a&&(h=Fc(a=f,m={nonBmp:!0}),a=\"\"===Ns(Nc(a,m)),h)&&a)this.data({messageKey:\"nonBmp\"});else{var m=t.getComputedStyle(e),h=parseFloat(m.getPropertyValue(\"font-size\"));a=m.getPropertyValue(\"font-weight\"),l=parseFloat(a)>=l||\"bold\"===a,a=Math.ceil(72*h)/96,a=(u=l&&a<u||!l&&a<s?c.normal:c.large).expected,s=u.minThreshold,c=u.maxThreshold,u=((e,t)=>{var n=void 0===(n=t.pseudoSizeThreshold)?.25:n;if(!(\\\nt=void 0!==(t=t.ignorePseudo)&&t)){var r=(t=e.boundingClientRect).width*t.height*n;do{if(r<Fg(e.actualNode,\":before\")+Fg(e.actualNode,\":after\"))return e}while(e=e.parent)}})(r,{ignorePseudo:i,pseudoSizeThreshold:p});if(u)this.data({fontSize:\"\".concat((72*h/96).toFixed(1),\"pt (\").concat(h,\"px)\"),fontWeight:l?\"bold\":\"normal\",messageKey:\"pseudoContent\",expectedContrastRatio:a+\":1\"}),this.relatedNodes(u.actualNode);else{var g,v,b;if(null!==(r=Yh(e,{minRatio:.001,maxRatio:d})))return u=ag(e,!(i=[]),p=eg(e,i,d),n),n=d=e=null,0===r.length?e=rg(p,u):u&&p&&(n=[].concat(M(r),[p]).reduce(Lh),r=rg(p,u),b=rg(p,n),g=rg(n,u),(e=Math.max(r,b,g))!==r)&&(d=g<b?\"shadowOnBgColor\":\"fgOnShadowColor\"),r=a<e,\"number\"==typeof s&&(\"number\"!=typeof e||e<s)||\"number\"==typeof c&&(\"number\"!=typeof e||c<e)?(this.data({contrastRatio:e}),!0):(g=Math.floor(100*e)/100,null===p?v=ud.get(\"bgColor\"):r||(v=d),b=1===f.length,(s=1==g)?v=ud.set(\"bgColor\",\"equalRatio\"):r||!b||o||(v=\"shortTextContent\"),this.data({fgColor:u?u.toH\\\nexString():void 0,bgColor:p?p.toHexString():void 0,contrastRatio:g,fontSize:\"\".concat((72*h/96).toFixed(1),\"pt (\").concat(h,\"px)\"),fontWeight:l?\"bold\":\"normal\",messageKey:v,expectedContrastRatio:a+\":1\",shadowColor:n?n.toHexString():void 0}),null===u||null===p||s||b&&!o&&!r?(v=null,ud.clear(),void this.relatedNodes(i)):(r||this.relatedNodes(i),r));this.data({messageKey:\"complexTextShadows\"})}}},\"color-contrast-matches\":function(e,n){var a=(f=n.props).nodeName;if(\"option\"===a)return!1;if(\"select\"===a&&!e.options.length)return!1;if(\"input\"===a&&[\"hidden\",\"range\",\"color\",\"checkbox\",\"radio\",\"image\"].includes(f.type))return!1;if(ug(n)||Vu(n))return!1;if([\"input\",\"select\",\"textarea\"].includes(a)){if(f=t.getComputedStyle(e),f=parseInt(f.getPropertyValue(\"text-indent\"),10)){var o={top:(o=e.getBoundingClientRect()).top,bottom:o.bottom,left:o.left+f,right:o.right+f};if(!Rd(o,e))return!1}return!0}if(f=Bl(n,\"label\"),\"label\"===a||f){if(o=f||e,a=f?_l(f):n,o.htmlFor&&(o=(f=Pl(o).getElementById(o.htmlF\\\nor))&&_l(f))&&ug(o))return!1;if((f=fm(a,'input:not([type=\"hidden\"],[type=\"image\"],[type=\"button\"],[type=\"submit\"],[type=\"reset\"]), select, textarea')[0])&&ug(f))return!1}for(var i,l=[],u=n;u;)u.props.id&&(i=Km(u).filter((function(e){return Yp(e.getAttribute(\"aria-labelledby\")||\"\").includes(u.props.id)})).map((function(e){return _l(e)})),l.push.apply(l,M(i))),u=u.parent;if(0<l.length&&l.every(ug))return!1;if(\"\"===(a=ac(o=n,!1,!0))||\"\"===Nc(a,zg)||!o.children.some((function(e){return\"#text\"===e.props.nodeName&&!Cc(e)})))return!1;if(!parseFloat(n.getComputedStylePropertyValue(\"font-size\")))return!1;for(var s=r.createRange(),c=n.children,d=0;d<c.length;d++){var p=c[d];3===p.actualNode.nodeType&&\"\"!==Ns(p.actualNode.nodeValue)&&s.selectNodeContents(p.actualNode)}var f=Array.from(s.getClientRects()),m=zl(n);return f.some((function(t){var n,r=Rd(t,e);return m.length?(n=m.some((function(e){return Ll(t,e.boundingClientRect)})),r&&n):r}))},\"css-orientation-lock-evaluate\":function(e,t,n,r){r=void\\\n 0===(r=(r||{}).cssom)?void 0:r;var a=void 0===(t=(t||{}).degreeThreshold)?0:t;if(r&&r.length){for(var o=!1,i=[],l=r.reduce((function(e,t){var n,r=t.sheet;return e[n=(n=t.shadowId)||\"topDocument\"]||(e[n]={root:t.root,rules:[]}),r&&r.cssRules&&(t=Array.from(r.cssRules),e[n].rules=e[n].rules.concat(t)),e}),{}),u=function(){var e=c[s],t=(e=l[e]).root;if(!(e=e.rules.filter(d)).length)return 1;e.forEach((function(e){e=e.cssRules,Array.from(e).forEach((function(e){var n=(e=>{var t=e.selectorText;e=e.style;return!(!t||e.length<=0||!(t=e.transform||e.webkitTransform||e.msTransform||!1)&&!e.rotate||(t=(e=>e&&(e=e.match(/(rotate|rotateZ|rotate3d|matrix|matrix3d)\\\\(([^)]+)\\\\)(?!.*(rotate|rotateZ|rotate3d|matrix|matrix3d))/))?p((e=V(e,3))[1],e[2]):0)(t),e=p(\"rotate\",e.rotate),!(t+=e))||(t=Math.abs(t),Math.abs(t-180)%180<=a))&&Math.abs(t-90)%90<=a})(e);n&&\"HTML\"!==e.selectorText.toUpperCase()&&(e=Array.from(t.querySelectorAll(e.selectorText))||[],i=i.concat(e)),o=o||n}))}))},s=0,c=Object.keys(l);s<c.\\\nlength;s++)u();return!o||(i.length&&this.relatedNodes(i),!1)}function d(e){var t=e.type;e=e.cssText;return 4===t&&(/orientation:\\\\s*landscape/i.test(e)||/orientation:\\\\s*portrait/i.test(e))}function p(e,t){switch(e){case\"rotate\":case\"rotateZ\":return f(t);case\"rotate3d\":var n=V(t.split(\",\").map((function(e){return e.trim()})),4),r=n[2];n=n[3];return 0===parseInt(r)?void 0:f(n);case\"matrix\":case\"matrix3d\":var a,o;return(r=(r=t).split(\",\")).length<=6?(a=(o=V(r,2))[0],o=o[1],m(Math.atan2(parseFloat(o),parseFloat(a)))):(o=parseFloat(r[8]),a=Math.asin(o),o=Math.cos(a),m(Math.acos(parseFloat(r[0])/o)));default:return 0}}function f(e){var t=V(e.match(/(deg|grad|rad|turn)/)||[],1)[0];if(!t)return 0;var n=parseFloat(e.replace(t,\"\"));switch(t){case\"rad\":return m(n);case\"grad\":var r=n;return(r%=400)<0&&(r+=400),Math.round(r/400*360);case\"turn\":return Math.round(360/(1/n));default:return parseInt(n)}}function m(e){return Math.round(e*(180/Math.PI))}},\"data-table-large-matches\":function(e){return!!Gm(\\\ne)&&3<=(e=xs(e)).length&&3<=e[0].length&&3<=e[1].length&&3<=e[2].length},\"data-table-matches\":function(e){return Gm(e)},\"deprecatedrole-evaluate\":function(e,t,n){n=Xs(n,{dpub:!0,fallback:!0});var r=gs.ariaRoles[n];return!(null==r||!r.deprecated||(this.data(n),0))},\"dlitem-evaluate\":function(e){var t=(e=ou(e)).nodeName.toUpperCase(),n=ys(e);return\"DIV\"===t&&[\"presentation\",\"none\",null].includes(n)&&(t=(e=ou(e)).nodeName.toUpperCase(),n=ys(e)),\"DL\"===t&&!(n&&![\"presentation\",\"none\",\"list\"].includes(n))},\"doc-has-title-evaluate\":function(){var e=r.title;return!!Ns(e)},\"duplicate-id-active-matches\":function(e){var t=e.getAttribute(\"id\").trim();t='*[id=\"'.concat(Aa(t),'\"]'),t=Array.from(Pl(e).querySelectorAll(t));return!uh(e)&&t.some(rs)},\"duplicate-id-after\":function(e){var t=[];return e.filter((function(e){return-1===t.indexOf(e.data)&&(t.push(e.data),!0)}))},\"duplicate-id-aria-matches\":function(e){return uh(e)},\"duplicate-id-evaluate\":function(e){var t,n=e.getAttribute(\"id\").trim();retur\\\nn!n||(t=Pl(e),(t=Array.from(t.querySelectorAll('[id=\"'.concat(Aa(n),'\"]'))).filter((function(t){return t!==e}))).length&&this.relatedNodes(t),this.data(n),0===t.length)},\"duplicate-id-misc-matches\":function(e){var t=e.getAttribute(\"id\").trim();t='*[id=\"'.concat(Aa(t),'\"]'),t=Array.from(Pl(e).querySelectorAll(t));return!uh(e)&&t.every((function(e){return!rs(e)}))},\"duplicate-img-label-evaluate\":function(e,t,n){return![\"none\",\"presentation\"].includes(Xs(n))&&!!(t=Wd(n,t.parentSelector))&&\"\"!==(t=ac(t,!0).toLowerCase())&&t===kc(n).toLowerCase()},\"exists-evaluate\":function(){},\"explicit-evaluate\":function(e,t,n){var r=this;if(!n.attr(\"id\"))return!1;if(n.actualNode){var a=Pl(n.actualNode),o=Aa(n.attr(\"id\"));a=Array.from(a.querySelectorAll('label[for=\"'.concat(o,'\"]')));if(this.relatedNodes(a),!a.length)return!1;try{return a.some((function(e){return!du(e)||(e=Ns(ss(e,{inControlContext:!0,startNode:n})),r.data({explicitLabel:e}),!!e)}))}catch(e){}}},\"fallbackrole-evaluate\":function(e,t,n){var\\\n r=Yp(n.attr(\"role\"));return!(r.length<=1)&&(!(!Ws(n)&&2===r.length&&r.includes(\"none\")&&r.includes(\"presentation\"))||void 0)},\"focusable-content-evaluate\":function(e,t,n){var r=n.tabbableElements;return!!r&&0<r.filter((function(e){return e!==n})).length},\"focusable-disabled-evaluate\":function(e,t,n){var r=[\"button\",\"fieldset\",\"input\",\"select\",\"textarea\"];return!((n=n.tabbableElements)&&n.length&&(n=n.filter((function(e){return r.includes(e.props.nodeName)})),this.relatedNodes(n.map((function(e){return e.actualNode}))),0!==n.length)&&!ad())||!!n.every((function(e){var t=e.getComputedStylePropertyValue(\"pointer-events\"),n=parseInt(e.getComputedStylePropertyValue(\"width\")),r=parseInt(e.getComputedStylePropertyValue(\"height\"));return e.actualNode.onfocus||(0===n||0===r)&&\"none\"===t}))&&void 0},\"focusable-element-evaluate\":function(e,t,n){return!(!n.hasAttr(\"contenteditable\")||!function e(t){return\"true\"===(t=t.attr(\"contenteditable\"))||\"\"===t||\"false\"!==t&&(!!(t=Wd(n.parent,\"[contentedita\\\nble]\"))&&e(t))}(n))||as(n)},\"focusable-modal-open-evaluate\":function(e,t,n){return!(n=n.tabbableElements.map((function(e){return e.actualNode})))||!n.length||!ad()||void this.relatedNodes(n)},\"focusable-no-name-evaluate\":function(e,t,n){if(!as(n))return!1;try{return!kc(n)}catch(e){}},\"focusable-not-tabbable-evaluate\":function(e,t,n){var r=[\"button\",\"fieldset\",\"input\",\"select\",\"textarea\"];return!((n=n.tabbableElements)&&n.length&&(n=n.filter((function(e){return!r.includes(e.props.nodeName)})),this.relatedNodes(n.map((function(e){return e.actualNode}))),0!==n.length)&&!ad())||!!n.every((function(e){var t=e.getComputedStylePropertyValue(\"pointer-events\"),n=parseInt(e.getComputedStylePropertyValue(\"width\")),r=parseInt(e.getComputedStylePropertyValue(\"height\"));return e.actualNode.onfocus||(0===n||0===r)&&\"none\"===t}))&&void 0},\"frame-focusable-content-evaluate\":function(e,t,n){if(n.children)try{return!n.children.some((function e(t){if(as(t))return!0;if(!t.children){if(1===t.props.nodeType)\\\nthrow new Error(\"Cannot determine children\");return!1}return t.children.some((function(t){return e(t)}))}))}catch(e){}},\"frame-focusable-content-matches\":function(e,t,n){var r;return!n.initiator&&!n.focusable&&1<(null==(r=n.size)?void 0:r.width)*(null==(r=n.size)?void 0:r.height)},\"frame-tested-after\":function(e){var t={};return e.filter((function(e){var n;return\"html\"!==e.node.ancestry[e.node.ancestry.length-1]?(n=e.node.ancestry.flat(1/0).join(\" > \"),t[n]=e,!0):(n=e.node.ancestry.slice(0,e.node.ancestry.length-1).flat(1/0).join(\" > \"),t[n]&&(t[n].result=!0),!1)}))},\"frame-tested-evaluate\":function(e,t){return!t.isViolation&&void 0},\"frame-title-has-text-matches\":function(e){return e=e.getAttribute(\"title\"),!!Ns(e)},\"has-alt-evaluate\":function(e,t,n){var r=n.props.nodeName;return!![\"img\",\"input\",\"area\"].includes(r)&&n.hasAttr(\"alt\")},\"has-descendant-after\":function(e){return e.some((function(e){return!0===e.result}))&&e.forEach((function(e){e.result=!0})),e},\"has-descendant-evaluate\":\\\nfunction(e,t,n){if(t&&t.selector&&\"string\"==typeof t.selector)return!(!t.passForModal||!ad())||(n=rm(n,t.selector,nc),this.relatedNodes(n.map((function(e){return e.actualNode}))),0<n.length);throw new TypeError(\"has-descendant requires options.selector to be a string\")},\"has-global-aria-attribute-evaluate\":function(e,t,n){var r=ws().filter((function(e){return n.hasAttr(e)}));return this.data(r),0<r.length},\"has-implicit-chromium-role-matches\":function(e,t){return null!==Ws(t,{chromium:!0})},\"has-lang-evaluate\":function(e,t,n){var a=void 0!==r&&dl(r);return t.attributes.includes(\"xml:lang\")&&t.attributes.includes(\"lang\")&&vg(n.attr(\"xml:lang\"))&&!vg(n.attr(\"lang\"))&&!a?(this.data({messageKey:\"noXHTML\"}),!1):!!t.attributes.some((function(e){return vg(n.attr(e))}))||(this.data({messageKey:\"noLang\"}),!1)},\"has-text-content-evaluate\":function(e,t,n){try{return\"\"!==Ns(bc(n))}catch(e){}},\"has-widget-role-evaluate\":function(e,t,n){return null!==(n=ys(n))&&(\"widget\"===(n=ed(n))||\"composite\"===n\\\n)},\"heading-matches\":function(e,t){return\"heading\"===Xs(t)},\"heading-order-after\":function(e){(t=M(t=e)).sort((function(e,t){return e=e.node,t=t.node,e.ancestry.length-t.ancestry.length}));var t,n=t.reduce(sg,[]).filter((function(e){return-1!==e.level}));return e.forEach((function(e){e.result=((e,t)=>{var n=null!=(n=null==(n=t[e=cg(t,e.node.ancestry)])?void 0:n.level)?n:-1;t=null!=(t=null==(t=t[e-1])?void 0:t.level)?t:-1;return 0===e||(-1!==n?n-t<=1:void 0)})(e,n)})),e},\"heading-order-evaluate\":function(){var e,t=Sl.get(\"headingOrder\");return t||(t=(e=rm(o._tree[0],\"h1, h2, h3, h4, h5, h6, [role=heading], iframe, frame\",nc)).map((function(e){return{ancestry:[Rl(e.actualNode)],level:(t=(t=Xs(e))&&t.includes(\"heading\"),n=e.attr(\"aria-level\"),r=parseInt(n,10),e=V(e.props.nodeName.match(/h(\\\\d)/)||[],2)[1],t?e&&!n?parseInt(e,10):isNaN(r)||r<1?e?parseInt(e,10):2:r||-1:-1)};var t,n,r})),this.data({headingOrder:t}),Sl.set(\"headingOrder\",e)),!0},\"help-same-as-label-evaluate\":function(e,t,n){n=P\\\nc(n);var r=e.getAttribute(\"title\");return!!n&&(r||(r=\"\",e.getAttribute(\"aria-describedby\")&&(r=us(e,\"aria-describedby\").map((function(e){return e?ss(e):\"\"})).join(\"\"))),Ns(r)===Ns(n))},\"hidden-content-evaluate\":function(e,n,r){if(![\"SCRIPT\",\"HEAD\",\"TITLE\",\"NOSCRIPT\",\"STYLE\",\"TEMPLATE\"].includes(e.nodeName.toUpperCase())&&Uc(r)){if(\"none\"===(r=t.getComputedStyle(e)).getPropertyValue(\"display\"))return;if(\"hidden\"===r.getPropertyValue(\"visibility\")&&(!(e=(r=ou(e))&&t.getComputedStyle(r))||\"hidden\"!==e.getPropertyValue(\"visibility\")))return}return!0},\"hidden-explicit-label-evaluate\":function(e,t,n){if(n.hasAttr(\"id\")){if(!n.actualNode)return;var r,a=Pl(e);e=Aa(e.getAttribute(\"id\"));if((a=a.querySelector('label[for=\"'.concat(e,'\"]')))&&!nc(a)){try{r=kc(n).trim()}catch(e){return}return\"\"===r}}return!1},\"html-namespace-matches\":function(e,t){return!Pg(0,t)},\"html5-scope-evaluate\":function(e){return!Qc(r)||\"TH\"===e.nodeName.toUpperCase()},\"identical-links-same-purpose-after\":function(e){if(e.l\\\nength<2)return e;for(var t=e.filter((function(e){return void 0!==e.result})),n=[],r={},o=function(e){var o=t[e],i=(u=o.data).name,l=u.urlProps;if(r[i])return 1;var u=t.filter((function(t,n){return t.data.name===i&&n!==e})),s=u.every((function(e){return function e(t,n){var r,o;return!(!t||!n)&&(r=Object.getOwnPropertyNames(t),o=Object.getOwnPropertyNames(n),r.length===o.length)&&r.every((function(r){var o=t[r];r=n[r];return a(o)===a(r)&&(\"object\"===a(o)||\"object\"===a(r)?e(o,r):o===r)}))}(e.data.urlProps,l)}));u.length&&!s&&(o.result=void 0),o.relatedNodes=[],(s=o.relatedNodes).push.apply(s,M(u.map((function(e){return e.relatedNodes[0]})))),r[i]=u,n.push(o)},i=0;i<t.length;i++)o(i);return n},\"identical-links-same-purpose-evaluate\":function(e,t,n){if(n=ls.accessibleTextVirtual(n),n=ls.sanitize(ls.removeUnicode(n,{emoji:!0,nonBmp:!0,punctuations:!0})).toLowerCase())return n={name:n,urlProps:Ol.urlPropsFromAttribute(e,\"href\")},this.data(n),this.relatedNodes([e]),!0},\"identical-links-same-pu\\\nrpose-matches\":function(e,t){return!(!kc(t)||(t=Xs(e))&&\"link\"!==t)},\"implicit-evaluate\":function(e,t,n){try{var r,a=Wd(n,\"label\");return!!a&&(r=Ns(kc(a,{inControlContext:!0,startNode:n})),a.actualNode&&this.relatedNodes([a.actualNode]),this.data({implicitLabel:r}),!!r)}catch(e){}},\"inline-style-property-evaluate\":function(e,n){var r=n.cssProperty,a=n.absoluteValues,o=n.minValue,i=n.maxValue,l=void 0===(l=n.normalValue)?0:l,u=n.multiLineOnly;return!!(!n.noImportant&&\"important\"!==e.style.getPropertyPriority(r)||u&&!od(e))||(n={},\"number\"==typeof o&&(n.minValue=o),\"number\"==typeof i&&(n.maxValue=i),u=e.style.getPropertyValue(r),[\"inherit\",\"unset\",\"revert\",\"revert-layer\"].includes(u)?(this.data(O({value:u},n)),!0):(u=((e,n)=>{var r=n.cssProperty,a=n.absoluteValues;n=n.normalValue;return\"normal\"===(r=(e=t.getComputedStyle(e)).getPropertyValue(r))||(n=parseFloat(r),a)?n:(a=parseFloat(e.getPropertyValue(\"font-size\")),e=Math.round(n/a*100)/100,isNaN(e)?r:e)})(e,{absoluteValues:a,cssProperty:\\\nr,normalValue:l}),this.data(O({value:u},n)),\"number\"==typeof u?(\"number\"!=typeof o||o<=u)&&(\"number\"!=typeof i||u<=i):void 0))},\"inserted-into-focus-order-matches\":function(e){return Kc(e)},\"internal-link-present-evaluate\":function(e,t,n){return fm(n,\"a[href]\").some((function(e){return/^#[^/!]/.test(e.attr(\"href\"))}))},\"invalid-children-evaluate\":function(e){var t=1<arguments.length&&void 0!==arguments[1]?arguments[1]:{},n=2<arguments.length?arguments[2]:void 0,r=[],a=[];if(n.children){for(var o=gg(n.children);o.length;){var i=(l=o.shift()).vChild,l=l.nested;if(t.divGroups&&!l&&\"div\"===(u=i).props.nodeName&&null===ys(u)){if(!i.children)return;var u=gg(i.children,!0);o.push.apply(o,M(u))}else u=((e,t,n)=>{var r=void 0===(r=n.validRoles)?[]:r,a=(n=void 0===(n=n.validNodeNames)?[]:n,(i=e.props).nodeName),o=i.nodeType,i=i.nodeValue;t=t?\"div > \":\"\";return 3===o&&\"\"!==i.trim()?t+\"#text\":!(1!==o||!nc(e))&&((i=ys(e))?!r.includes(i)&&t+\"[role=\".concat(i,\"]\"):!n.includes(a)&&t+a)})(i,l,t),u&&(a.\\\nincludes(u)||a.push(u),1===(null==i||null==(l=i.actualNode)?void 0:l.nodeType))&&r.push(i.actualNode)}return 0!==a.length&&(this.data({values:a.join(\", \")}),this.relatedNodes(r),!0)}},\"invalidrole-evaluate\":function(e,t,n){return!!(n=Yp(n.attr(\"role\"))).every((function(e){return!bs(e.toLowerCase(),{allowAbstract:!0})}))&&(this.data(n),!0)},\"is-element-focusable-evaluate\":function(e,t,n){return rs(n)},\"is-initiator-matches\":qg,\"is-on-screen-evaluate\":Ni,\"is-visible-matches\":du,\"is-visible-on-screen-matches\":function(e,t){return du(t)},\"label-content-name-mismatch-evaluate\":function(e,t,n){var r=null==t?void 0:t.pixelThreshold,a=null!=(a=null==t?void 0:t.occurrenceThreshold)?a:null==t?void 0:t.occuranceThreshold;return t=ss(e).toLowerCase(),!(e=Ns(bc(n,{subtreeDescendant:!0,ignoreIconLigature:!0,pixelThreshold:r,occurrenceThreshold:a})).toLowerCase())||(Tc(t)<1||Tc(e)<1?void 0:(n=e,r=bg(r=t),n=bg(n),!(!r||!n)&&r.includes(n)))},\"label-content-name-mismatch-matches\":function(e,t){var n=Xs(\\\ne);return!!(n&&eh(\"widget\").includes(n)&&nh().includes(n)&&(Ns(ds(t))||Ns(cs(e)))&&Ns(ac(t)))},\"label-matches\":function(e,t){return\"input\"!==t.props.nodeName||!1===t.hasAttr(\"type\")||(t=t.attr(\"type\").toLowerCase(),!1===[\"hidden\",\"image\",\"button\",\"submit\",\"reset\"].includes(t))},\"landmark-has-body-context-matches\":function(e,t){return e.hasAttribute(\"role\")||!Bl(t,\"article, aside, main, nav, section\")},\"landmark-is-top-level-evaluate\":function(e){var t=eh(\"landmark\"),n=ou(e),r=Xs(e);for(this.data({role:r});n;){var a=ys(n);if((a=a||\"FORM\"===n.nodeName.toUpperCase()?a:Ws(n))&&t.includes(a)&&(\"main\"!==a||\"complementary\"!==r))return!1;n=ou(n)}return!0},\"landmark-is-unique-after\":function(e){var t=[];return e.filter((function(e){var n=t.find((function(t){return e.data.role===t.data.role&&e.data.accessibleText===t.data.accessibleText}));return n?(n.result=!1,n.relatedNodes.push(e.relatedNodes[0]),!1):(t.push(e),e.relatedNodes=[],!0)}))},\"landmark-is-unique-evaluate\":function(e,t,n){var r=Xs(e\\\n);return n=(n=kc(n))?n.toLowerCase():null,this.data({role:r,accessibleText:n}),this.relatedNodes([e]),!0},\"landmark-unique-matches\":function(e,t){return n=t,a=eh(\"landmark\"),!!(o=Xs(n))&&(\"section\"!==(r=n.props.nodeName)&&\"form\"!==r?0<=a.indexOf(o)||\"region\"===o:!!kc(n))&&nc(t);var n,r,a,o},\"layout-table-matches\":function(e){return!Gm(e)&&!rs(e)},\"link-in-text-block-evaluate\":function(e,t){var n=t.requiredContrastRatio;if(t=t.allowSameColor,Ag(e))return!1;for(var r=ou(e);r&&1===r.nodeType&&!Ag(r);)r=ou(r);if(r){this.relatedNodes([r]);var a=ag(e),o=ag(r),i=(e=eg(e),eg(r)),l=a&&o?xg(a,o):void 0;if((l=l&&Math.floor(100*l)/100)&&n<=l)return!0;var u=e&&i?xg(e,i):void 0;if((u=u&&Math.floor(100*u)/100)&&n<=u)return!0;if(u){if(l)return!(!t||1!==l||1!==u)||(1===l&&1<u?this.data({messageKey:\"bgContrast\",contrastRatio:u,requiredContrastRatio:n,nodeBackgroundColor:e?e.toHexString():void 0,parentBackgroundColor:i?i.toHexString():void 0}):this.data({messageKey:\"fgContrast\",contrastRatio:l,requiredCo\\\nntrastRatio:n,nodeColor:a?a.toHexString():void 0,parentColor:o?o.toHexString():void 0}),!1)}else u=null!=(t=ud.get(\"bgColor\"))?t:\"bgContrast\",this.data({messageKey:u}),ud.clear()}},\"link-in-text-block-matches\":function(e){var t=Ns(e.innerText),n=ys(e);return!(n&&\"link\"!==n||!t||!du(e))&&rd(e)},\"link-in-text-block-style-evaluate\":function(e){if(wg(e))return!1;for(var n=ou(e);n&&1===n.nodeType&&!wg(n);)n=ou(n);return n?(this.relatedNodes([n]),!!_h(e,n)||!!(e=>{for(var n=0,r=[\"before\",\"after\"];n<r.length;n++){var a=r[n];if(\"none\"!==t.getComputedStyle(e,\":\".concat(a)).getPropertyValue(\"content\"))return 1}})(e)&&void this.data({messageKey:\"pseudoContent\"})):void 0},\"listitem-evaluate\":function(e,t,n){var r;if(n=n.parent)return r=n.props.nodeName,n=ys(n),!![\"presentation\",\"none\",\"list\"].includes(n)||(n&&bs(n)?(this.data({messageKey:\"roleNotValid\"}),!1):[\"ul\",\"ol\",\"menu\"].includes(r))},\"matches-definition-evaluate\":function(e,t,n){return Hs(n,t.matcher)},\"meta-refresh-evaluate\":function(e,t,n\\\n){var r=(a=t||{}).minDelay,a=a.maxDelay;return!(n=V((n.attr(\"content\")||\"\").trim().split(kh),1)[0]).match(Rh)||(n=parseFloat(n),this.data({redirectDelay:n}),\"number\"==typeof r&&n<=t.minDelay)||\"number\"==typeof a&&n>t.maxDelay},\"meta-viewport-scale-evaluate\":function(e,t,n){var r,a=void 0===(a=(t=t||{}).scaleMinimum)?2:a;return t=void 0!==(t=t.lowerBound)&&t,!((n=n.attr(\"content\")||\"\")&&(n=n.split(/[;,]/).reduce((function(e,t){var n;return(t=t.trim())&&(n=(t=V(t.split(\"=\"),2))[0],t=t[1],n)&&t&&(n=n.toLowerCase().trim(),t=t.toLowerCase().trim(),\"maximum-scale\"===n&&\"yes\"===t&&(t=1),\"maximum-scale\"===n&&parseFloat(t)<0||(e[n]=t)),e}),{}),!(t&&n[\"maximum-scale\"]&&parseFloat(n[\"maximum-scale\"])<t))&&(t||\"no\"!==n[\"user-scalable\"]?(r=parseFloat(n[\"user-scalable\"]),!t&&n[\"user-scalable\"]&&(r||0===r)&&-1<r&&r<1?(this.data(\"user-scalable\"),1):n[\"maximum-scale\"]&&parseFloat(n[\"maximum-scale\"])<a&&(this.data(\"maximum-scale\"),1)):(this.data(\"user-scalable=no\"),1)))},\"multiple-label-evaluate\":functi\\\non(e){var t=Aa(e.getAttribute(\"id\")),n=e.parentNode,r=(r=Pl(e)).documentElement||r,a=Array.from(r.querySelectorAll('label[for=\"'.concat(t,'\"]')));for(a.length&&(a=a.filter((function(e){return!nu(e)})));n;)\"LABEL\"===n.nodeName.toUpperCase()&&-1===a.indexOf(n)&&a.push(n),n=n.parentNode;return this.relatedNodes(a),1<a.length&&(1<(r=a.filter(nc)).length||!us(e,\"aria-labelledby\").includes(r[0]))&&void 0},\"nested-interactive-matches\":function(e,t){return!!(t=Xs(t))&&!!gs.ariaRoles[t].childrenPresentational},\"no-autoplay-audio-evaluate\":function(e,t){var n,r=e.hasAttribute(\"controls\");return e.hasAttribute(\"loop\")?r:e.duration?(t=void 0===(t=t.allowedDuration)?3:t,(e.currentSrc?(n=(e=>{if(e=e.match(/#t=(.*)/))return V(e,2)[1].split(\",\").map((function(e){if(/:/.test(e)){for(var t=e.split(\":\"),n=0,r=1;0<t.length;)n+=r*parseInt(t.pop(),10),r*=60;return parseFloat(n)}return parseFloat(e)}))})(e.currentSrc))?1!==n.length?Math.abs(n[1]-n[0]):Math.abs(e.duration-n[0]):Math.abs(e.duration-(e.currentT\\\nime||0)):0)<=t||!!r):void console.warn(\"axe.utils.preloadMedia did not load metadata\")},\"no-autoplay-audio-matches\":function(e){return!!e.currentSrc&&!e.hasAttribute(\"paused\")&&!e.hasAttribute(\"muted\")},\"no-empty-role-matches\":function(e,t){return!!t.hasAttr(\"role\")&&!!t.attr(\"role\").trim()},\"no-explicit-name-required-matches\":Lg,\"no-focusable-content-evaluate\":function(e,t,n){if(n.children)try{var r,a=function e(t){if(!t.children){if(1===t.props.nodeType)throw new Error(\"Cannot determine children\");return[]}var n=[];return t.children.forEach((function(t){\"widget\"===ed(t)&&rs(t)?n.push(t):n.push.apply(n,M(e(t)))})),n}(n);return!a.length||(0<(r=a.filter(yg)).length?(this.data({messageKey:\"notHidden\"}),this.relatedNodes(r)):this.relatedNodes(a),!1)}catch(e){}},\"no-implicit-explicit-label-evaluate\":function(e,t,n){var r,a,o=Xs(n,{noImplicit:!0});this.data(o);try{r=Ns(yc(n)).toLowerCase(),a=Ns(kc(n)).toLowerCase()}catch(e){return}return!(!a&&!r||(a||!r)&&a.includes(r))&&void 0},\"no-naming-\\\nmethod-matches\":function(e,t){var n=Us(t).namingMethods;return!(n&&0!==n.length||\"combobox\"===ys(t)&&fm(t,'input:not([type=\"hidden\"])').length||sh(t,{popupRoles:[\"listbox\"]}))},\"no-negative-tabindex-matches\":function(e,t){return null===(t=Zf(t.attr(\"tabindex\")))||0<=t},\"no-role-matches\":function(e,t){return!t.attr(\"role\")},\"non-empty-if-present-evaluate\":function(e,t,n){var r=n.props.nodeName,a=(n.attr(\"type\")||\"\").toLowerCase();return(n=n.attr(\"value\"))&&this.data({messageKey:\"has-label\"}),!(\"input\"!==r||![\"submit\",\"reset\"].includes(a))&&null===n},\"not-html-matches\":function(e,t){return\"html\"!==t.props.nodeName},\"object-is-loaded-matches\":function(e,t){return[Lg,function(e){var t;return null==e||null==(t=e.ownerDocument)||!t.createRange||((t=e.ownerDocument.createRange()).setStart(e,0),t.setEnd(e,e.childNodes.length),0===t.getClientRects().length)}].every((function(n){return n(e,t)}))},\"only-dlitems-evaluate\":function(e,t,n){var r=[\"definition\",\"term\",\"list\"];return(n=n.children.reduc\\\ne((function(e,t){var n=t.actualNode;return\"DIV\"===n.nodeName.toUpperCase()&&null===Xs(n)?e.concat(t.children):e.concat(t)}),[]).reduce((function(e,t){var n,a=(t=t.actualNode).nodeName.toUpperCase();return 1===t.nodeType&&nc(t)?(n=ys(t),(\"DT\"!==a&&\"DD\"!==a||n)&&!r.includes(n)&&e.badNodes.push(t)):3===t.nodeType&&\"\"!==t.nodeValue.trim()&&(e.hasNonEmptyTextNode=!0),e}),{badNodes:[],hasNonEmptyTextNode:!1})).badNodes.length&&this.relatedNodes(n.badNodes),!!n.badNodes.length||n.hasNonEmptyTextNode},\"only-listitems-evaluate\":function(e,t,n){var r=!1,a=!1,o=!0,i=[],l=[],u=[];if(n.children.forEach((function(e){var t,n,s=e.actualNode;3===s.nodeType&&\"\"!==s.nodeValue.trim()?r=!0:1===s.nodeType&&nc(s)&&(o=!1,t=\"LI\"===s.nodeName.toUpperCase(),n=\"listitem\"===(e=Xs(e)),t||n||i.push(s),t&&!n&&(l.push(s),u.includes(e)||u.push(e)),n)&&(a=!0)})),r||i.length)this.relatedNodes(i);else{if(o||a)return!1;this.relatedNodes(l),this.data({messageKey:\"roleNotValid\",roles:u.join(\", \")})}return!0},\"p-as-heading-ev\\\naluate\":function(e,t,n){var r=(i=Array.from(e.parentNode.children)).indexOf(e),a=(t=t||{}).margins||[],o=i.slice(r+1).find((function(e){return\"P\"===e.nodeName.toUpperCase()})),i=i.slice(0,r).reverse().find((function(e){return\"P\"===e.nodeName.toUpperCase()})),l=(r=Fh(e),o?Fh(o):null),u=(i=i?Fh(i):null,t.passLength);return t=t.failLength,e=e.textContent.trim().length,(o=null==o?void 0:o.textContent.trim().length)*u<e||!l||!Ch(r,l,a)||!!((u=Bl(n,\"blockquote\"))&&\"BLOCKQUOTE\"===u.nodeName.toUpperCase()||i&&!Ch(r,i,a)||o*t<e)&&void 0},\"p-as-heading-matches\":function(e){var t=Array.from(e.parentNode.childNodes),n=e.textContent.trim();return!(0===n.length||2<=(n.match(/[.!?:;](?![.!?:;])/g)||[]).length)&&0!==t.slice(t.indexOf(e)+1).filter((function(e){return\"P\"===e.nodeName.toUpperCase()&&\"\"!==e.textContent.trim()})).length},\"page-no-duplicate-after\":function(e){return e.filter((function(e){return\"ignored\"!==e.data}))},\"page-no-duplicate-evaluate\":function(e,t,n){if(!t||!t.selector||\"string\"!=\\\ntypeof t.selector)throw new TypeError(\"page-no-duplicate requires options.selector to be a string\");var r=\"page-no-duplicate;\"+t.selector;if(!Sl.get(r))return Sl.set(r,!0),r=rm(o._tree[0],t.selector,nc),\"string\"==typeof t.nativeScopeFilter&&(r=r.filter((function(e){return e.actualNode.hasAttribute(\"role\")||!Bl(e,t.nativeScopeFilter)}))),\"string\"==typeof t.role&&(r=r.filter((function(e){return Xs(e)===t.role}))),this.relatedNodes(r.filter((function(e){return e!==n})).map((function(e){return e.actualNode}))),r.length<=1;this.data(\"ignored\")},\"presentation-role-conflict-matches\":function(e,t){return null!==Ws(t,{chromiumRoles:!0})},\"presentational-role-evaluate\":function(e,t,n){var r=ys(n);if([\"presentation\",\"none\"].includes(r)&&[\"iframe\",\"frame\"].includes(n.props.nodeName)&&n.hasAttr(\"title\"))this.data({messageKey:\"iframe\",nodeName:n.props.nodeName});else{var a,o=Xs(n);if([\"presentation\",\"none\"].includes(o))return this.data({role:o}),!0;[\"presentation\",\"none\"].includes(r)&&(r=ws().some((\\\nfunction(e){return n.hasAttr(e)})),a=rs(n),this.data({messageKey:r&&!a?\"globalAria\":!r&&a?\"focusable\":\"both\",role:o}))}return!1},\"region-after\":function(e){var t=e.filter((function(e){return e.data.isIframe}));return e.forEach((function(e){if(!e.result&&1!==e.node.ancestry.length){var n,r=e.node.ancestry.slice(0,-1),a=K(t);try{for(a.s();!(n=a.n()).done;){var o=n.value;if(Gf(r,o.node.ancestry)){e.result=o.result;break}}}catch(e){a.e(e)}finally{a.f()}}})),t.forEach((function(e){e.result||(e.result=!0)})),e},\"region-evaluate\":function(e,t,n){return this.data({isIframe:[\"iframe\",\"frame\"].includes(n.props.nodeName)}),!Sl.get(\"regionlessNodes\",(function(){return function e(t,n){var a=t.actualNode;if(\"button\"===Xs(t)||function(e,t){var n=e.actualNode,r=Xs(e),a=(n=(n.getAttribute(\"aria-live\")||\"\").toLowerCase().trim(),eh(\"landmark\"));return!!([\"assertive\",\"polite\"].includes(n)||Ah.includes(r)||a.includes(r)||t.regionMatcher&&Hs(e,t.regionMatcher))}(t,n)||[\"iframe\",\"frame\"].includes(t.props.nod\\\neName)||bd(t.actualNode)&&Xu(t.actualNode,\"href\")||!nc(a)){for(var o=t;o;)o._hasRegionDescendant=!0,o=o.parent;return[\"iframe\",\"frame\"].includes(t.props.nodeName)?[t]:[]}return a!==r.body&&Wc(a,!0)&&!function(e){return[\"none\",\"presentation\"].includes(Xs(e))&&!Hc(e)}(t)?[t]:t.children.filter((function(e){return 1===(e=e.actualNode).nodeType})).map((function(t){return e(t,n)})).reduce((function(e,t){return e.concat(t)}),[])}(o._tree[0],t).map((function(e){for(;e.parent&&!e.parent._hasRegionDescendant&&e.parent.actualNode!==r.body;)e=e.parent;return e})).filter((function(e,t,n){return n.indexOf(e)===t}))})).includes(n)},\"same-caption-summary-evaluate\":function(e,t,n){var r;if(void 0!==n.children)return r=n.attr(\"summary\"),!(!(n=!!(n=n.children.find(xh))&&Ns(bc(n)))||!r)&&Ns(r).toLowerCase()===Ns(n).toLowerCase()},\"scope-value-evaluate\":function(e,t){return e=e.getAttribute(\"scope\").toLowerCase(),-1!==t.values.indexOf(e)},\"scrollable-region-focusable-matches\":function(e,t){return void 0!==\\\nCf(e,13)&&!1===sh(t)&&fm(t,\"*\").some((function(e){return Uc(e,!0,!0)}))},\"skip-link-evaluate\":function(e){return!!(e=Xu(e,\"href\"))&&(nc(e)||void 0)},\"skip-link-matches\":function(e){return bd(e)&&su(e)},\"structured-dlitems-evaluate\":function(e,t,n){var r=n.children;if(!r||!r.length)return!1;for(var a,o=!1,i=!1,l=0;l<r.length;l++){if((o=\"DT\"===(a=r[l].props.nodeName.toUpperCase())||o)&&\"DD\"===a)return!1;\"DD\"===a&&(i=!0)}return o||i},\"summary-interactive-matches\":function(e,t){var n,r,a=t.parent;return!(\"details\"!==a.props.nodeName||(r=null==(r=(n=t).actualNode)?void 0:r.parentElement)&&r!==n.parent.actualNode)&&a.children.find((function(e){return\"summary\"===e.props.nodeName}))===t},\"svg-namespace-matches\":Pg,\"svg-non-empty-title-evaluate\":function(e,t,n){if(n.children){if(n=n.children.find((function(e){return\"title\"===e.props.nodeName})),!n)return this.data({messageKey:\"noTitle\"}),!1;try{if(\"\"===bc(n,{includeHidden:!0}).trim())return this.data({messageKey:\"emptyTitle\"}),!1}catch(e){retur\\\nn}return!0}},\"tabindex-evaluate\":function(e,t,n){return null===(n=Zf(n.attr(\"tabindex\")))||n<=0},\"table-or-grid-role-matches\":function(e,t){return t=Xs(t),[\"treegrid\",\"grid\",\"table\"].includes(t)},\"target-offset-evaluate\":function(e,t,n){var r=(null==t?void 0:t.minOffset)||24;if(yu(10*r,n.boundingClientRect))return this.data({messageKey:\"large\",minOffset:r}),!0;var a,o,i=[],l=r,u=K(Lu(n,r));try{for(u.s();!(a=u.n()).done;){var s=a.value;if(\"widget\"===ed(s)&&rs(s)){var c=null;try{c=Du(n,s,r/2)}catch(e){if(e.message.startsWith(\"splitRects\"))return void this.data({messageKey:\"tooManyRects\",closestOffset:0,minOffset:r});throw e}null===c||r<=.05+(c=2*(o=c,Math.round(10*o)/10))||(l=Math.min(l,c),i.push(s))}}}catch(e){u.e(e)}finally{u.f()}return 0===i.length?(this.data({closestOffset:l,minOffset:r}),!0):(this.relatedNodes(i.map((function(e){return e.actualNode}))),i.some(as)?(this.data({closestOffset:l,minOffset:r}),!as(n)&&void 0):void this.data({messageKey:\"nonTabbableNeighbor\",closestOffset:\\\nl,minOffset:r}))},\"target-size-evaluate\":function(e,t,n){t=(null==t?void 0:t.minSize)||24;var r,a,o,i,l,u,s=n.boundingClientRect;return yu(10*t,s)?(this.data({messageKey:\"large\",minSize:t}),!0):(l=yu.bind(null,t),i=Lu(n),a=n,r=i.filter((function(e){return!pg(e,a)&&mg(a,e)})),o=(i=((e,t)=>{var n,r=[],a=[],o=K(t);try{for(o.s();!(n=o.n()).done;){var i=n.value;!mg(e,i)&&xu(e,i)&&\"none\"!==i.getComputedStylePropertyValue(\"pointer-events\")&&(pg(e,i)?r:a).push(i)}}catch(e){o.e(e)}finally{o.f()}return{fullyObscuringElms:r,partialObscuringElms:a}})(n,i)).fullyObscuringElms,i=i.partialObscuringElms,!r.length||!o.length&&l(s)?o.length?(this.relatedNodes(hg(o)),this.data({messageKey:\"obscured\"}),!0):(o=!as(n)&&void 0,l(s)?(i=i.filter((function(e){return\"widget\"===ed(e)&&rs(e)}))).length?(n=((e,t)=>{var n;e=e.boundingClientRect,t=t.map((function(e){return e.boundingClientRect}));try{n=Eu(e,t)}catch(e){return null}var r=void 0;return n.reduce((function(e,t){var n=yu(r,e);return n!==yu(r,t)?n?e:t:(n=e\\\n.width*e.height,t.width*t.height<n?e:t)}))})(n,i))?l(n)?(this.data(O({minSize:t},fg(n||s))),this.relatedNodes(hg(i)),!0):r.length?(this.data({minSize:t,messageKey:\"contentOverflow\"}),void this.relatedNodes(hg(r))):(l=i.every(as),u=\"partiallyObscured\".concat(l?\"\":\"NonTabbable\"),this.data(O({messageKey:u,minSize:t},fg(n))),this.relatedNodes(hg(i)),l?o:void 0):void this.data({minSize:t,messageKey:\"tooManyRects\"}):(this.data(O({minSize:t},fg(s))),!0):(this.data(O({minSize:t},fg(s))),o)):(this.data({minSize:t,messageKey:\"contentOverflow\"}),void this.relatedNodes(hg(r))))},\"td-has-header-evaluate\":function(e){var t=[],n=Lm(e),r=xs(e);return n.forEach((function(e){Wc(e)&&Vm(e)&&!dh(e)&&!zm(e,r).some((function(e){return null!==e&&!!Wc(e)}))&&t.push(e)})),!t.length||(this.relatedNodes(t),!1)},\"td-headers-attr-evaluate\":function(e){for(var t=[],n={},r=0;r<e.rows.length;r++)for(var a=e.rows[r],o=0;o<a.cells.length;o++){var i=a.cells[o],l=(t.push(i),i.getAttribute(\"id\"));l&&(n[l]=Xs(i))}var u,s=F(\\\nF(F(F({},Dh,new Set),bh,new Set),yh,new Set),wh,new Set),c=(t.forEach((function(e){var t,r;e.hasAttribute(\"headers\")&&nc(e)&&((t=e.getAttribute(\"headers\").trim())?(r=e.getAttribute(\"id\"),Yp(t).forEach((function(t){r&&t===r?s[Dh].add(e):n[t]?[\"columnheader\",\"rowheader\"].includes(n[t])||s[yh].add(e):s[bh].add(e)}))):s[wh].add(e))})),K(vh));try{for(c.s();!(u=c.n()).done;){var d=u.value;if(0<s[d].size)return this.relatedNodes(M(s[d])),d===wh?void 0:(this.data({messageKey:d}),!1)}}catch(e){c.e(e)}finally{c.f()}return!0},\"th-has-data-cells-evaluate\":function(e){var t=Lm(e),n=this,r=[],a=(t=(t.forEach((function(e){var t;(t=((t=e.getAttribute(\"headers\"))&&(r=r.concat(t.split(/\\\\s+/))),e.getAttribute(\"aria-labelledby\")))&&(r=r.concat(t.split(/\\\\s+/)))})),t.filter((function(e){return\"\"!==Ns(e.textContent)&&(\"TH\"===e.nodeName.toUpperCase()||-1!==[\"rowheader\",\"columnheader\"].indexOf(ys(e)))}))),xs(e)),o=!0;return t.forEach((function(e){var t,i;e.getAttribute(\"id\")&&r.includes(e.getAttribute(\"id\"))||\\\n(t=Es(e,a),i=!1,(i=!(i=Fs(e)?Hm(\"down\",t,a).find((function(t){return!Fs(t)&&zm(t,a).includes(e)})):i)&&Cs(e)?Hm(\"right\",t,a).find((function(t){return!Cs(t)&&zm(t,a).includes(e)})):i)||n.relatedNodes(e),o=o&&i)})),!!o||void 0},\"title-only-evaluate\":function(e,t,n){var r=Pc(n),a=Js(n);return n=n.attr(\"aria-describedby\"),!(r||!a&&!n)},\"unique-frame-title-after\":function(e){var t={};return e.forEach((function(e){t[e.data]=void 0!==t[e.data]?++t[e.data]:0})),e.forEach((function(e){e.result=!!t[e.data]})),e},\"unique-frame-title-evaluate\":function(e,t,n){return n=Ns(n.attr(\"title\")).toLowerCase(),this.data(n),!0},\"unsupportedrole-evaluate\":function(e,t,n){n=Xs(n,{dpub:!0,fallback:!0});var r=vs(n);return r&&this.data(n),r},\"valid-lang-evaluate\":function(e,t,n){var r=[];return t.attributes.forEach((function(e){var a,o,i=n.attr(e);\"string\"==typeof i&&(a=of(i),o=t.value?!t.value.map(of).includes(a):!Rm(a),\"\"!==a&&o||\"\"!==i&&!Ns(i))&&r.push(e+'=\"'+n.attr(e)+'\"')})),!!r.length&&!(\"html\"!==n.props.n\\\nodeName&&!Yc(n)||(this.data(r),0))},\"valid-scrollable-semantics-evaluate\":function(e,t){return(n=ys(n=e))&&(Rg[n]||t.roles.includes(n))||(t=(t=e).nodeName.toUpperCase(),kg[t])||!1;var n},\"widget-not-inline-matches\":function(e,t){return Ig.every((function(n){return n(e,t)}))},\"window-is-top-matches\":function(e){return e.ownerDocument.defaultView.self===e.ownerDocument.defaultView.top},\"xml-lang-mismatch-evaluate\":function(e,t,n){return of(n.attr(\"lang\"))===of(n.attr(\"xml:lang\"))},\"xml-lang-mismatch-matches\":function(e){var t=of(e.getAttribute(\"lang\"));return e=of(e.getAttribute(\"xml:lang\")),Rm(t)&&Rm(e)}},Gg=function(e){this.id=e.id,this.data=null,this.relatedNodes=[],this.result=null};function $g(e){if(\"string\"!=typeof e)return e;if(Vg[e])return Vg[e];if(/^\\\\s*function[\\\\s\\\\w]*\\\\(/.test(e))return new Function(\"return \"+e+\";\")();throw new ReferenceError(\"Function ID does not exist in the metadata-function-map: \".concat(e))}function Hg(e){return e=0<arguments.length&&void 0!==e?e:{},Array.is\\\nArray(e)||\"object\"!==a(e)?{value:e}:e}function Ug(e){e&&(this.id=e.id,this.configure(e))}Ug.prototype.enabled=!0,Ug.prototype.run=function(e,t,n,r,a){var o=((t=t||{}).hasOwnProperty(\"enabled\")?t:this).enabled,i=this.getOptions(t.options);if(o){var l;o=new Gg(this),t=Id(o,t,r,a);try{l=this.evaluate.call(t,e.actualNode,i,e,n)}catch(t){return e&&e.actualNode&&(t.errorNode=Ip.toSpec(e)),void a(t)}t.isAsync||(o.result=l,r(o))}else r(null)},Ug.prototype.runSync=function(e,t,n){if(!(void 0===(a=(t=t||{}).enabled)?this.enabled:a))return null;var r,a=this.getOptions(t.options),o=new Gg(this);(t=Id(o,t)).async=function(){throw new Error(\"Cannot run async check while in a synchronous run\")};try{r=this.evaluate.call(t,e.actualNode,a,e,n)}catch(t){throw e&&e.actualNode&&(t.errorNode=Ip.toSpec(e)),t}return o.result=r,o},Ug.prototype.configure=function(e){var t=this;e.evaluate&&!Vg[e.evaluate]||(this._internalCheck=!0),e.hasOwnProperty(\"enabled\")&&(this.enabled=e.enabled),e.hasOwnProperty(\"options\")&\\\n&(this._internalCheck?this.options=Hg(e.options):this.options=e.options),[\"evaluate\",\"after\"].filter((function(t){return e.hasOwnProperty(t)})).forEach((function(n){return t[n]=$g(e[n])}))},Ug.prototype.getOptions=function(e){return this._internalCheck?$p(this.options,Hg(e||{})):e||this.options};var Wg=Ug,Yg=function(e){this.id=e.id,this.result=oa.NA,this.pageLevel=e.pageLevel,this.impact=null,this.nodes=[]};function Kg(e,t){this._audit=t,this.id=e.id,this.selector=e.selector||\"*\",e.impact&&(xa(oa.impact.includes(e.impact),\"Impact \".concat(e.impact,\" is not a valid impact\")),this.impact=e.impact),this.excludeHidden=\"boolean\"!=typeof e.excludeHidden||e.excludeHidden,this.enabled=\"boolean\"!=typeof e.enabled||e.enabled,this.pageLevel=\"boolean\"==typeof e.pageLevel&&e.pageLevel,this.reviewOnFail=\"boolean\"==typeof e.reviewOnFail&&e.reviewOnFail,this.any=e.any||[],this.all=e.all||[],this.none=e.none||[],this.tags=e.tags||[],this.preload=!!e.preload,this.actIds=e.actIds,e.matches&&(this.matche\\\ns=$g(e.matches))}function Xg(e){var t,n;if(e.length)return t=!1,n={},e.forEach((function(e){var r=e.results.filter((function(e){return e}));(n[e.type]=r).length&&(t=!0)})),t?n:null}Kg.prototype.matches=function(){return!0},Kg.prototype.gather=function(e){var t=1<arguments.length&&void 0!==arguments[1]?arguments[1]:{},n=\"mark_gather_start_\"+this.id,r=\"mark_gather_end_\"+this.id,a=\"mark_isVisibleToScreenReaders_start_\"+this.id,o=\"mark_isVisibleToScreenReaders_end_\"+this.id;t.performanceTimer&&Qf.mark(n),e=bm(this.selector,e);return this.excludeHidden&&(t.performanceTimer&&Qf.mark(a),e=e.filter(nc),t.performanceTimer)&&(Qf.mark(o),Qf.measure(\"rule_\"+this.id+\"#gather_axe.utils.isVisibleToScreenReaders\",a,o)),t.performanceTimer&&(Qf.mark(r),Qf.measure(\"rule_\"+this.id+\"#gather\",n,r)),e},Kg.prototype.runChecks=function(e,t,n,r,a,o){var i=this,l=Qd();this[e].forEach((function(e){var a=i._audit.checks[e.id||e],o=gf(a,i.id,n);l.defer((function(e,n){a.run(t,o,r,e,(function(e){n(new wm({ruleId:i.id\\\n,method:\"\".concat(a.id,\"#evaluate\"),errorNode:new Pd(t),error:e}))}))}))})),l.then((function(t){t=t.filter((function(e){return e})),a({type:e,results:t})})).catch(o)},Kg.prototype.runChecksSync=function(e,t,n,r){var a=this,o=[];return this[e].forEach((function(e){e=a._audit.checks[e.id||e];var i=gf(e,a.id,n);o.push(e.runSync(t,i,r))})),{type:e,results:o=o.filter((function(e){return e}))}},Kg.prototype.run=function(e){var t,n=this,r=1<arguments.length&&void 0!==arguments[1]?arguments[1]:{},a=2<arguments.length?arguments[2]:void 0,o=3<arguments.length?arguments[3]:void 0,i=(r.performanceTimer&&this._trackPerformance(),Qd()),l=new Yg(this);try{t=this.gatherAndMatchNodes(e,r)}catch(t){return void o(t)}r.performanceTimer&&this._logGatherPerformance(t),t.forEach((function(t){i.defer((function(a,o){var i=Qd();[\"any\",\"all\",\"none\"].forEach((function(a){i.defer((function(o,i){n.runChecks(a,t,r,e,o,i)}))})),i.then((function(e){var r=Xg(e);r&&(r.node=new Pd(t),l.nodes.push(r),n.reviewOnFail)&&([\"a\\\nny\",\"all\"].forEach((function(e){r[e].forEach((function(e){!1===e.result&&(e.result=void 0)}))})),r.none.forEach((function(e){!0===e.result&&(e.result=void 0)}))),a()})).catch((function(e){return o(e)}))}))})),i.then((function(){r.performanceTimer&&n._logRulePerformance(),setTimeout((function(){a(l)}),0)})).catch((function(e){r.performanceTimer&&n._logRulePerformance(),o(e)}))},Kg.prototype.runSync=function(e){var t=this,n=1<arguments.length&&void 0!==arguments[1]?arguments[1]:{},r=(n.performanceTimer&&this._trackPerformance(),new Yg(this)),a=this.gatherAndMatchNodes(e,n);return n.performanceTimer&&this._logGatherPerformance(a),a.forEach((function(a){var o=[],i=([\"any\",\"all\",\"none\"].forEach((function(r){o.push(t.runChecksSync(r,a,n,e))})),Xg(o));i&&(i.node=a.actualNode?new Pd(a):null,r.nodes.push(i),t.reviewOnFail)&&([\"any\",\"all\"].forEach((function(e){i[e].forEach((function(e){!1===e.result&&(e.result=void 0)}))})),i.none.forEach((function(e){!0===e.result&&(e.result=void 0)})))})),n.pe\\\nrformanceTimer&&this._logRulePerformance(),r},Kg.prototype._trackPerformance=function(){this._markStart=\"mark_rule_start_\"+this.id,this._markEnd=\"mark_rule_end_\"+this.id,this._markChecksStart=\"mark_runchecks_start_\"+this.id,this._markChecksEnd=\"mark_runchecks_end_\"+this.id},Kg.prototype._logGatherPerformance=function(e){ia(\"gather for \".concat(this.id,\" (\").concat(e.length,\" nodes): \").concat(Qf.timeElapsed(),\"ms\")),Qf.mark(this._markChecksStart)},Kg.prototype._logRulePerformance=function(){Qf.mark(this._markChecksEnd),Qf.mark(this._markEnd),Qf.measure(\"runchecks_\"+this.id,this._markChecksStart,this._markChecksEnd),Qf.measure(\"rule_\"+this.id,this._markStart,this._markEnd)},Kg.prototype.gatherAndMatchNodes=function(e,t){var n=this,r=\"mark_matches_start_\"+this.id,a=\"mark_matches_end_\"+this.id,o=this.gather(e,t);return t.performanceTimer&&Qf.mark(r),o=o.filter((function(t){try{return n.matches(t.actualNode,t,e)}catch(e){throw new wm({ruleId:n.id,method:\"#matches\",errorNode:new Pd(t),error\\\n:e})}})),t.performanceTimer&&(Qf.mark(a),Qf.measure(\"rule_\"+this.id+\"#matches\",r,a)),o},Kg.prototype.after=function(e,t){var n,r,a,o,i=this;return Bp(n=this).map((function(e){return(e=n._audit.checks[e.id||e])&&\"function\"==typeof e.after?e:null})).filter(Boolean).forEach((function(n){l=e.nodes,r=n.id,a=[],l.forEach((function(e){Bp(e).forEach((function(t){t.id===r&&(t.node=e.node,a.push(t))}))}));var r,a,o,l=a,u=gf(n,i.id,t);try{o=n.after(l,u.options)}catch(l){throw new wm({ruleId:i.id,method:\"\".concat(n.id,\"#after\"),errorNode:null==(u=e.nodes)||null==(u=u[0])?void 0:u.node,error:l})}i.reviewOnFail&&o.forEach((function(e){var t=(i.any.includes(e.id)||i.all.includes(e.id))&&!1===e.result,n=i.none.includes(e.id)&&!0===e.result;(t||n)&&(e.result=void 0)})),l.forEach((function(e){delete e.node,-1===o.indexOf(e)&&(e.filtered=!0)}))})),e.nodes=(a=[\"any\",\"all\",\"none\"],o=(r=e).nodes.filter((function(e){var t=0;return a.forEach((function(n){e[n]=e[n].filter((function(e){return!0!==e.filtered})),\\\nt+=e[n].length})),0<t})),o=r.pageLevel&&o.length?[o.reduce((function(e,t){if(e)return a.forEach((function(n){e[n].push.apply(e[n],t[n])})),e}))]:o),e},Kg.prototype.configure=function(e){e.hasOwnProperty(\"selector\")&&(this.selector=e.selector),e.hasOwnProperty(\"excludeHidden\")&&(this.excludeHidden=\"boolean\"!=typeof e.excludeHidden||e.excludeHidden),e.hasOwnProperty(\"enabled\")&&(this.enabled=\"boolean\"!=typeof e.enabled||e.enabled),e.hasOwnProperty(\"pageLevel\")&&(this.pageLevel=\"boolean\"==typeof e.pageLevel&&e.pageLevel),e.hasOwnProperty(\"reviewOnFail\")&&(this.reviewOnFail=\"boolean\"==typeof e.reviewOnFail&&e.reviewOnFail),e.hasOwnProperty(\"any\")&&(this.any=e.any),e.hasOwnProperty(\"all\")&&(this.all=e.all),e.hasOwnProperty(\"none\")&&(this.none=e.none),e.hasOwnProperty(\"tags\")&&(this.tags=e.tags),e.hasOwnProperty(\"actIds\")&&(this.actIds=e.actIds),e.hasOwnProperty(\"matches\")&&(this.matches=$g(e.matches)),e.impact&&(xa(oa.impact.includes(e.impact),\"Impact \".concat(e.impact,\" is not a valid impa\\\nct\")),this.impact=e.impact)};var Zg=/\\\\{\\\\{.+?\\\\}\\\\}/g,Jg=W((function e(t){H(this,e),this.lang=\"en\",this.defaultConfig=t,this.standards=gs,this._init(),this._defaultLocale=null}),[{key:\"_setDefaultLocale\",value:function(){if(!this._defaultLocale){for(var e={checks:{},rules:{},failureSummaries:{},incompleteFallbackMessage:\"\",lang:this.lang},t=Object.keys(this.data.checks),n=0;n<t.length;n++){var r=t[n],a=this.data.checks[r].messages,o=a.pass;e.checks[r]={pass:o,fail:a.fail,incomplete:a.incomplete}}for(var i=Object.keys(this.data.rules),l=0;l<i.length;l++){var u=i[l],s=this.data.rules[u],c=s.description;e.rules[u]={description:c,help:s.help}}for(var d=Object.keys(this.data.failureSummaries),p=0;p<d.length;p++){var f=d[p],m=this.data.failureSummaries[f].failureMessage;e.failureSummaries[f]={failureMessage:m}}e.incompleteFallbackMessage=this.data.incompleteFallbackMessage,this._defaultLocale=e}}},{key:\"_resetLocale\",value:function(){var e=this._defaultLocale;e&&this.applyLocale(e)}},{key:\"_app\\\nlyCheckLocale\",value:function(e){for(var t=Object.keys(e),n=0;n<t.length;n++){var r=t[n];if(!this.data.checks[r])throw new Error('Locale provided for unknown check: \"'.concat(r,'\"'));this.data.checks[r]=tv(this.data.checks[r],e[r])}}},{key:\"_applyRuleLocale\",value:function(e){for(var t=Object.keys(e),n=0;n<t.length;n++){var r=t[n];if(!this.data.rules[r])throw new Error('Locale provided for unknown rule: \"'.concat(r,'\"'));this.data.rules[r]=nv(this.data.rules[r],e[r])}}},{key:\"_applyFailureSummaries\",value:function(e){for(var t=Object.keys(e),n=0;n<t.length;n++){var r=t[n];if(!this.data.failureSummaries[r])throw new Error('Locale provided for unknown failureMessage: \"'.concat(r,'\"'));this.data.failureSummaries[r]=rv(this.data.failureSummaries[r],e[r])}}},{key:\"applyLocale\",value:function(e){this._setDefaultLocale(),e.checks&&this._applyCheckLocale(e.checks),e.rules&&this._applyRuleLocale(e.rules),e.failureSummaries&&this._applyFailureSummaries(e.failureSummaries,\"failureSummaries\"),e.in\\\ncompleteFallbackMessage&&(this.data.incompleteFallbackMessage=av(this.data.incompleteFallbackMessage,e.incompleteFallbackMessage)),e.lang&&(this.lang=e.lang)}},{key:\"setAllowedOrigins\",value:function(e){var t,n=Qg(),r=(this.allowedOrigins=[],K(e));try{for(r.s();!(t=r.n()).done;){var a=t.value;if(a===oa.allOrigins)return void(this.allowedOrigins=[\"*\"]);a!==oa.sameOrigin?this.allowedOrigins.push(a):n&&this.allowedOrigins.push(n)}}catch(e){r.e(e)}finally{r.f()}}},{key:\"_init\",value:function(){var e=(e=>{var t;return e?(t=Bd(e)).commons=e.commons:t={},t.reporter=t.reporter||null,t.noHtml=t.noHtml||!1,t.allowedOrigins||(e=Qg(),t.allowedOrigins=e?[e]:[]),t.rules=t.rules||[],t.checks=t.checks||[],t.data=O({checks:{},rules:{}},t.data),t})(this.defaultConfig);this.lang=e.lang||\"en\",this.reporter=e.reporter,this.commands={},this.rules=[],this.checks={},this.brand=\"axe\",this.application=\"axeAPI\",this.tagExclude=[\"experimental\",\"deprecated\"],this.noHtml=e.noHtml,this.allowedOrigins=e.allowedOrigin\\\ns,ev(e.rules,this,\"addRule\"),ev(e.checks,this,\"addCheck\"),this.data={},this.data.checks=e.data&&e.data.checks||{},this.data.rules=e.data&&e.data.rules||{},this.data.failureSummaries=e.data&&e.data.failureSummaries||{},this.data.incompleteFallbackMessage=e.data&&e.data.incompleteFallbackMessage||\"\",this._constructHelpUrls()}},{key:\"registerCommand\",value:function(e){this.commands[e.id]=e.callback}},{key:\"addRule\",value:function(e){e.metadata&&(this.data.rules[e.id]=e.metadata);var t=this.getRule(e.id);t?t.configure(e):this.rules.push(new Kg(e,this))}},{key:\"addCheck\",value:function(e){var t=e.metadata;\"object\"===a(t)&&(this.data.checks[e.id]=t,\"object\"===a(t.messages))&&Object.keys(t.messages).filter((function(e){return t.messages.hasOwnProperty(e)&&\"string\"==typeof t.messages[e]})).forEach((function(e){0===t.messages[e].indexOf(\"function\")&&(t.messages[e]=new Function(\"return \"+t.messages[e]+\";\")())})),this.checks[e.id]?this.checks[e.id].configure(e):this.checks[e.id]=new Wg(e)}},{key:\\\n\"run\",value:function(e,t,n,r){this.normalizeOptions(t),Pd.setRunOptions(t),o._selectCache=[],l=this.rules,a=e,i=t;var a,i,l=l.reduce((function(e,t){return hm(t,a,i)&&(t.preload?e.later:e.now).push(t),e}),{now:[],later:[]}),u=l.now,s=l.later,c=Qd();u.forEach((function(n){c.defer(ov(n,e,t))})),l=Qd();(u=(s.length&&l.defer((function(e){um(t).then((function(t){return e(t)})).catch((function(t){console.warn(\"Couldn't load preload assets: \",t),e(void 0)}))})),Qd())).defer(c),u.defer(l),u.then((function(a){var i,l=a.pop(),u=(l&&l.length&&(l=l[0])&&(e=O({},e,l)),a[0]);s.length?(i=Qd(),s.forEach((function(n){n=ov(n,e,t),i.defer(n)})),i.then((function(e){o._selectCache=void 0,n(u.concat(e).filter((function(e){return!!e})))})).catch(r)):(o._selectCache=void 0,n(u.filter((function(e){return!!e}))))})).catch(r)}},{key:\"after\",value:function(e,t){var n=this.rules;return e.map((function(e){if(e.error)return e;var r=jp(n,\"id\",e.id);if(!r)throw new Error(\"Result for unknown rule. You may be running mis\\\nmatch axe-core versions\");try{return r.after(e,t)}catch(e){if(t.debug)throw e;return iv(r,e)}}))}},{key:\"getRule\",value:function(e){return this.rules.find((function(t){return t.id===e}))}},{key:\"normalizeOptions\",value:function(e){var t=[],n=[];if(this.rules.forEach((function(e){n.push(e.id),e.tags.forEach((function(e){t.includes(e)||t.push(e)}))})),[\"object\",\"string\"].includes(a(e.runOnly))){if(\"string\"==typeof e.runOnly&&(e.runOnly=[e.runOnly]),Array.isArray(e.runOnly)){var r=e.runOnly.find((function(e){return t.includes(e)})),i=e.runOnly.find((function(e){return n.includes(e)}));if(r&&i)throw new Error(\"runOnly cannot be both rules and tags\");e.runOnly=i?{type:\"rule\",values:e.runOnly}:{type:\"tag\",values:e.runOnly}}if((r=e.runOnly).value&&!r.values&&(r.values=r.value,delete r.value),!Array.isArray(r.values)||0===r.values.length)throw new Error(\"runOnly.values must be a non-empty array\");if([\"rule\",\"rules\"].includes(r.type))r.type=\"rule\",r.values.forEach((function(e){if(!n.includes(e)\\\n)throw new Error(\"unknown rule \\`\"+e+\"\\` in options.runOnly\")}));else{if(![\"tag\",\"tags\",void 0].includes(r.type))throw new Error(\"Unknown runOnly type '\".concat(r.type,\"'\"));r.type=\"tag\",i=r.values.filter((function(e){return!t.includes(e)&&!/wcag2[1-3]a{1,3}/.test(e)})),0!==i.length&&o.log(\"Could not find tags \\`\"+i.join(\"\\`, \\`\")+\"\\`\")}}return\"object\"===a(e.rules)&&Object.keys(e.rules).forEach((function(e){if(!n.includes(e))throw new Error(\"unknown rule \\`\"+e+\"\\` in options.rules\")})),e}},{key:\"setBranding\",value:function(e){var t={brand:this.brand,application:this.application};\"string\"==typeof e&&(this.application=e),e&&e.hasOwnProperty(\"brand\")&&e.brand&&\"string\"==typeof e.brand&&(this.brand=e.brand),e&&e.hasOwnProperty(\"application\")&&e.application&&\"string\"==typeof e.application&&(this.application=e.application),this._constructHelpUrls(t)}},{key:\"_constructHelpUrls\",value:function(){var e=this,t=0<arguments.length&&void 0!==arguments[0]?arguments[0]:null,n=(o.version.match(/^[1-9][0-9]*\\\\.\\\n[0-9]+/)||[\"x.y\"])[0];this.rules.forEach((function(r){e.data.rules[r.id]||(e.data.rules[r.id]={});var a=e.data.rules[r.id];(\"string\"!=typeof a.helpUrl||t&&a.helpUrl===lv(t,r.id,n))&&(a.helpUrl=lv(e,r.id,n))}))}},{key:\"resetRulesAndChecks\",value:function(){this._init(),this._resetLocale()}}]);function Qg(){return t.origin&&\"null\"!==t.origin?t.origin:t.location&&t.location.origin&&\"null\"!==t.location.origin?t.location.origin:void 0}function ev(e,t,n){for(var r=0,a=e.length;r<a;r++)t[n](e[r])}var tv=function(e,t){var n=t.pass,r=t.fail;return\"string\"==typeof n&&Zg.test(n)&&(n=Oa.default.compile(n)),\"string\"==typeof r&&Zg.test(r)&&(r=Oa.default.compile(r)),O({},e,{messages:{pass:n||e.messages.pass,fail:r||e.messages.fail,incomplete:\"object\"===a(e.messages.incomplete)?O({},e.messages.incomplete,t.incomplete):t.incomplete}})},nv=function(e,t){var n=t.help;t=t.description;return\"string\"==typeof n&&Zg.test(n)&&(n=Oa.default.compile(n)),\"string\"==typeof t&&Zg.test(t)&&(t=Oa.default.compile(t)),O\\\n({},e,{help:n||e.help,description:t||e.description})},rv=function(e,t){return O({},e,{failureMessage:(t=\"string\"==typeof(t=t.failureMessage)&&Zg.test(t)?Oa.default.compile(t):t)||e.failureMessage})},av=function(e,t){return(t=\"string\"==typeof t&&Zg.test(t)?Oa.default.compile(t):t)||e};function ov(e,t,n){return n.performanceTimer&&Qf.mark(\"mark_rule_start_\"+e.id),function(r,a){e.run(t,n,(function(e){return r(e)}),(function(t){n.debug?a(t):r(iv(e,t))}))}}function iv(e,t){var n=t.errorNode,a=[{id:\"error-occurred\",result:void 0,data:t=ym(t),relatedNodes:[]}];n=n||new Pd(r.documentElement);return Object.assign(new Yg(e),{error:t,result:oa.CANTTELL,nodes:[{any:[],all:[],none:a,node:n}]})}function lv(e,t,n){var r=e.brand,a=e.application;e=e.lang;return oa.helpUrlBase+r+\"/\"+(n||o.version.substring(0,o.version.lastIndexOf(\".\")))+\"/\"+t+\"?application=\"+encodeURIComponent(a)+(e&&\"en\"!==e?\"&lang=\"+encodeURIComponent(e):\"\")}function uv(e){var n=t&&\"Node\"in t&&\"NodeList\"in t,a=!!r;if(!n||!a){if(!e||!e\\\n.ownerDocument)throw new Error('Required \"window\" or \"document\" globals not defined and cannot be deduced from the context. Either set the globals before running or pass in a valid Element.');a||(Sl.set(\"globalDocumentSet\",!0),r=e.ownerDocument),n||(Sl.set(\"globalWindowSet\",!0),t=r.defaultView)}}var sv=function(){Sl.get(\"globalDocumentSet\")&&(Sl.set(\"globalDocumentSet\",!1),r=null),Sl.get(\"globalWindowSet\")&&(Sl.set(\"globalWindowSet\",!1),t=null),o._memoizedFns.forEach((function(e){return e.clear()})),Sl.clear(),o._tree=void 0,o._selectorData=void 0,o._selectCache=void 0};function cv(e,t,n,r){try{e=new xf(e),o._tree=e.flatTree,o._selectorData=wl(e.flatTree)}catch(a){return sv(),r(a)}var a=Qd(),i=o._audit;t.performanceTimer&&Qf.auditStart(),e.frames.length&&!1!==t.iframes&&a.defer((function(n,r){zp(e,t,\"rules\",null,n,r)})),a.defer((function(n,r){i.run(e,t,n,r)})),a.then((function(a){try{t.performanceTimer&&Qf.auditEnd();var o=qp(a.map((function(e){return{results:e}})));e.initiator&&(t.per\\\nformanceTimer&&Qf.mark(\"auditAfterStart\"),o=i.after(o,t),t.performanceTimer&&(Qf.mark(\"auditAfterEnd\"),Qf.measure(\"audit.after\",\"auditAfterStart\",\"auditAfterEnd\"),Qf.logMeasures(\"audit.after\")),o.forEach(dm),o=o.map(va));try{n(o,sv)}catch(a){sv(),ia(a)}}catch(a){sv(),r(a)}})).catch((function(e){sv(),r(e)}))}function dv(e){this._run=e.run,this._collect=e.collect,this._registry={},e.commands.forEach((function(e){o._audit.registerCommand(e)}))}function pv(e){var t=(e=V(e,3))[0],n=e[1],i=(e=e[2],new TypeError(\"axe.run arguments are invalid\"));if(!Mf(t)){if(void 0!==e)throw i;e=n,n=t,t=r}if(\"object\"!==a(n)){if(void 0!==e)throw i;e=n,n={}}if(\"function\"!=typeof e&&void 0!==e)throw i;return(n=Bd(n)).reporter=null!=(i=null!=(i=n.reporter)?i:null==(i=o._audit)?void 0:i.reporter)?i:\"v1\",{context:t,options:n,callback:e}}t.top!==t&&(Np.subscribe(\"axe.start\",(function(e,t,n){function a(e){e instanceof Error==0&&(e=new Error(e)),n(e)}var i=n,l=e&&e.context||{},u=(l.hasOwnProperty(\"include\")&&!l.inclu\\\nde.length&&(l.include=[r]),e&&e.options||{});switch(e.command){case\"rules\":return cv(l,u,(function(e,t){e=Ip.mapRawResults(e),i(e),t()}),a);case\"cleanup-plugin\":return Mm(i,a);default:if(o._audit&&o._audit.commands&&o._audit.commands[e.command])return o._audit.commands[e.command](e,n)}})),Np.subscribe(\"axe.ping\",(function(e,t,n){n({axe:!0})}))),dv.prototype.run=function(){return this._run.apply(this,arguments)},dv.prototype.collect=function(){return this._collect.apply(this,arguments)},dv.prototype.cleanup=function(e){var t=o.utils.queue(),n=this;Object.keys(this._registry).forEach((function(e){t.defer((function(t){n._registry[e].cleanup(t)}))})),t.then(e)},dv.prototype.add=function(e){this._registry[e.id]=e};var fv=function(){};var mv=function(e,t,n){if(\"function\"==typeof t&&(n=t,t={}),!e||!Array.isArray(e))return n(e);n(e.map((function(e){for(var t=O({},e),n=0,r=[\"passes\",\"violations\",\"incomplete\",\"inapplicable\"];n<r.length;n++){var a=r[n];t[a]=Ip.mapRawNodeResults(t[a])}return t})))\\\n};No={base:{Audit:Jg,CheckResult:Gg,Check:Wg,Context:xf,RuleResult:Yg,Rule:Kg,metadataFunctionMap:Vg},public:{reporters:Pm},helpers:{failureSummary:lf,incompleteFallbackMessage:uf,processAggregate:cf},utils:{setDefaultFrameMessenger:kp,cacheNodeSelectors:ef,getNodesMatchingExpression:Xp,convertSelector:Hd},commons:{dom:{nativelyHidden:$l,displayHidden:Hl,visibilityHidden:Ul,contentVisibiltyHidden:Wl,ariaHidden:Yl,opacityHidden:Kl,scrollHidden:Xl,overflowHidden:Zl,clipHidden:Jl,areaHidden:Ql,detailsHidden:eu}}};o._thisWillBeDeletedDoNotUse=No,o.constants=oa,o.log=ia,o.AbstractVirtualNode=ua,o.SerialVirtualNode=Om,o.VirtualNode=Sd,o._cache=Sl,o.imports=Sa,o.cleanup=Mm,o.configure=function(e){var t=o._audit;if(!t)throw new Error(\"No audit configured\");if(e.axeVersion||e.ver){var n=e.axeVersion||e.ver;if(!/^\\\\d+\\\\.\\\\d+\\\\.\\\\d+(-canary)?/.test(n))throw new Error(\"Invalid configured version \".concat(n));var r=(a=V(n.split(\"-\"),2))[0],a=a[1],i=(r=V(r.split(\".\").map(Number),3))[0],l=r[1],u=(r=r[2],(\\\ns=V(o.version.split(\"-\"),2))[0]),s=s[1],c=(u=V(u.split(\".\").map(Number),3))[0],d=u[1];u=u[2];if(i!==c||d<l||d===l&&u<r||i===c&&l===d&&r===u&&a&&a!==s)throw new Error(\"Configured version \".concat(n,\" is not compatible with current axe version \").concat(o.version))}if(e.reporter&&(\"function\"==typeof e.reporter||Im(e.reporter))&&(t.reporter=e.reporter),e.checks){if(!Array.isArray(e.checks))throw new TypeError(\"Checks property must be an array\");e.checks.forEach((function(e){if(!e.id)throw new TypeError(\"Configured check \".concat(JSON.stringify(e),\" is invalid. Checks must be an object with at least an id property\"));t.addCheck(e)}))}var p,f=[];if(e.rules){if(!Array.isArray(e.rules))throw new TypeError(\"Rules property must be an array\");e.rules.forEach((function(e){if(!e.id)throw new TypeError(\"Configured rule \".concat(JSON.stringify(e),\" is invalid. Rules must be an object with at least an id property\"));f.push(e.id),t.addRule(e)}))}if(e.disableOtherRules&&t.rules.forEach((function(e){!1=\\\n==f.includes(e.id)&&(e.enabled=!1)})),void 0!==e.branding?t.setBranding(e.branding):t._constructHelpUrls(),e.tagExclude&&(t.tagExclude=e.tagExclude),e.locale&&t.applyLocale(e.locale),e.standards&&(p=e.standards,Object.keys(hs).forEach((function(e){p[e]&&(hs[e]=$p(hs[e],p[e]))}))),e.noHtml&&(t.noHtml=!0),e.allowedOrigins){if(!Array.isArray(e.allowedOrigins))throw new TypeError(\"Allowed origins property must be an array\");if(e.allowedOrigins.includes(\"*\"))throw new Error('\"*\" is not allowed. Use \"'.concat(oa.allOrigins,'\" instead'));t.setAllowedOrigins(e.allowedOrigins)}},o.frameMessenger=function(e){Np.updateMessenger(e)},o.getRules=function(e){var t=(e=e||[]).length?o._audit.rules.filter((function(t){return!!e.filter((function(e){return-1!==t.tags.indexOf(e)})).length})):o._audit.rules,n=o._audit.data.rules||{};return t.map((function(e){var t=n[e.id]||{};return{ruleId:e.id,description:t.description,help:t.help,helpUrl:t.helpUrl,tags:e.tags,actIds:e.actIds}}))},o._load=function(e){o._au\\\ndit=new Jg(e)},o.plugins={},o.registerPlugin=function(e){o.plugins[e.id]=new dv(e)},o.hasReporter=Im,o.getReporter=Bm,o.addReporter=function(e,t,n){Pm[e]=t,n&&(Tm=t)},o.reset=function(){var e=o._audit;if(!e)throw new Error(\"No audit configured\");e.resetRulesAndChecks(),Object.keys(hs).forEach((function(e){hs[e]=ms[e]}))},o._runRules=cv,o.runVirtualRule=function(e,t){var n=2<arguments.length&&void 0!==arguments[2]?arguments[2]:{},r=(n.reporter=n.reporter||o._audit.reporter||\"v1\",o._selectorData={},t instanceof ua||(t=new Om(t)),Af(e));if(r)return dm(r=(r=Object.create(r,{excludeHidden:{value:!1}})).runSync({initiator:!0,include:[t],exclude:[],frames:[],page:!1,focusable:!0,size:{},flatTree:[]},n)),va(r),(t=Da([r])).violations.forEach((function(e){return e.nodes.forEach((function(e){e.failureSummary=lf(e)}))})),O({},vf(),t,{toolOptions:n});throw new Error(\"unknown rule \\`\"+e+\"\\`\")},o.run=function(){for(var e=arguments.length,t=new Array(e),n=0;n<e;n++)t[n]=arguments[n];uv(t[0]);var r=(c=pv\\\n(t)).context,a=c.options,i=void 0===(c=c.callback)?fv:c,l=(c=(e=>{var t,n,r;return\"function\"==typeof Promise&&e===fv?t=new Promise((function(e,t){n=t,r=e})):(r=function(t){return e(null,t)},n=function(t){return e(t)}),{thenable:t,reject:n,resolve:r}})(i)).thenable,u=c.resolve,s=c.reject;try{xa(o._audit,\"No audit configured\"),xa(!o._running,\"Axe is already running. Use \\`await axe.run()\\` to wait for the previous run to finish before starting a new run.\")}catch(e){var c=e;if(\"function\"!=typeof i||i===fv)throw c;return void i(c.message)}return o._running=!0,a.performanceTimer&&Qf.start(),o._runRules(r,a,(function(e,t){function n(e){o._running=!1,t();try{s(e)}catch(e){o.log(e)}}try{a.performanceTimer&&Qf.mark(\"reporterStart\");var r=e,i=a,l=function(e){a.performanceTimer&&(Qf.mark(\"reporterEnd\"),Qf.measure(\"reporter\",\"reporterStart\",\"reporterEnd\"),Qf.logMeasures(\"reporter\"),Qf.end()),o._running=!1,t();try{u(e)}catch(e){o.log(e)}},c=n;void 0!==(r=Bm(i.reporter)(r,i,l,c))&&l(r)}catch(e){n(e)}}\\\n),(function(e){a.performanceTimer&&Qf.end(),o._running=!1,i(e),s(e)})),l},o.setup=function(e){if(o._tree)throw new Error(\"Axe is already setup. Call \\`axe.teardown()\\` before calling \\`axe.setup\\` again.\");return uv(e=e&&\"object\"===a(e.documentElement)&&\"object\"===a(e.defaultView)?e.documentElement:e),o._tree=tf(e),o._selectorData=wl(o._tree),o._tree[0]},o.teardown=sv,o.runPartial=function(){for(var e=arguments.length,t=new Array(e),n=0;n<e;n++)t[n]=arguments[n];var r=(a=pv(t)).options,a=a.context,i=(xa(o._audit,\"Axe is not configured. Audit is missing.\"),xa(!o._running,\"Axe is already running. Use \\`await axe.run()\\` to wait for the previous run to finish before starting a new run.\"),new xf(a,o._tree));return o._tree=i.flatTree,o._selectorData=wl(i.flatTree),o._running=!0,r.elementRef=!1,new Promise((function(e,t){o._audit.run(i,r,e,t)})).then((function(e){e=Ip.mapRawResults(e);var t,n=i.frames.map((function(e){return e=e.node,Ip.toSpec(e)}));return i.initiator&&(t=vf()),o._running=!1,sv(),\\\n{results:e,frames:n,environmentData:t}})).catch((function(e){return o._running=!1,sv(),Promise.reject(e)}))},o.finishRun=function(e){var t,n=Bd(n=1<arguments.length&&void 0!==arguments[1]?arguments[1]:{}),r=(e.find((function(e){return e.environmentData}))||{}).environmentData;o._audit.normalizeOptions(n),n.reporter=null!=(p=null!=(p=n.reporter)?p:null==(p=o._audit)?void 0:p.reporter)?p:\"v1\";var a=[],i=K(p=e);try{for(i.s();!(t=i.n()).done;){var l,u=t.value,s=a.shift();u&&(u.frameSpec=null!=s?s:null,l=(e=>{var t=e.frames,n=e.frameSpec;return n?t.map((function(e){return Ip.mergeSpecs(e,n)})):t})(u),a.unshift.apply(a,M(l)))}}catch(e){i.e(e)}finally{i.f()}var c,d,p=qp(e);return(p=o._audit.after(p,n)).forEach(dm),p=p.map(va),c=p,d=O({environmentData:r},n),new Promise((function(e,t){Bm(d.reporter)(c,d,e,t)}))},o.commons=Cn,o.utils=sa,o.addReporter(\"na\",(function(e,t,n){console.warn('\"na\" reporter will be deprecated in axe v4.0. Use the \"v2\" reporter instead.'),\"function\"==typeof t&&(n=t,t={})\\\n;var r=t.environmentData,a=k(a=t,D);n(O({},vf(r),{toolOptions:a},cf(e,t)))})),o.addReporter(\"no-passes\",(function(e,t,n){\"function\"==typeof t&&(n=t,t={});var r=t.environmentData,a=k(a=t,w);t.resultTypes=[\"violations\"],e=cf(e,t).violations,n(O({},vf(r),{toolOptions:a,violations:e}))})),o.addReporter(\"rawEnv\",(function(e,t,n){\"function\"==typeof t&&(n=t,t={});var r=t.environmentData;t=k(t,x),mv(e,t,(function(e){var t=vf(r);n({raw:e,env:t})}))})),o.addReporter(\"raw\",mv),o.addReporter(\"v1\",(function(e,t,n){function r(e){e.nodes.forEach((function(e){e.failureSummary=lf(e)}))}\"function\"==typeof t&&(n=t,t={});var a=t.environmentData,o=k(o=t,E);(e=cf(e,t)).incomplete.forEach(r),e.violations.forEach(r),n(O({},vf(a),{toolOptions:o},e))})),o.addReporter(\"v2\",(function(e,t,n){\"function\"==typeof t&&(n=t,t={});var r=t.environmentData,a=k(a=t,A);e=cf(e,t),n(O({},vf(r),{toolOptions:a},e))}),!0),o._load({lang:\"en\",data:{rules:{accesskeys:{description:\"Ensure every accesskey attribute value is unique\",he\\\nlp:\"accesskey attribute value should be unique\"},\"area-alt\":{description:\"Ensure <area> elements of image maps have alternative text\",help:\"Active <area> elements must have alternative text\"},\"aria-allowed-attr\":{description:\"Ensure an element's role supports its ARIA attributes\",help:\"Elements must only use supported ARIA attributes\"},\"aria-allowed-role\":{description:\"Ensure role attribute has an appropriate value for the element\",help:\"ARIA role should be appropriate for the element\"},\"aria-braille-equivalent\":{description:\"Ensure aria-braillelabel and aria-brailleroledescription have a non-braille equivalent\",help:\"aria-braille attributes must have a non-braille equivalent\"},\"aria-command-name\":{description:\"Ensure every ARIA button, link and menuitem has an accessible name\",help:\"ARIA commands must have an accessible name\"},\"aria-conditional-attr\":{description:\"Ensure ARIA attributes are used as described in the specification of the element's role\",help:\"ARIA attributes must be use\\\nd as specified for the element's role\"},\"aria-deprecated-role\":{description:\"Ensure elements do not use deprecated roles\",help:\"Deprecated ARIA roles must not be used\"},\"aria-dialog-name\":{description:\"Ensure every ARIA dialog and alertdialog node has an accessible name\",help:\"ARIA dialog and alertdialog nodes should have an accessible name\"},\"aria-hidden-body\":{description:'Ensure aria-hidden=\"true\" is not present on the document body.',help:'aria-hidden=\"true\" must not be present on the document body'},\"aria-hidden-focus\":{description:\"Ensure aria-hidden elements are not focusable nor contain focusable elements\",help:\"ARIA hidden element must not be focusable or contain focusable elements\"},\"aria-input-field-name\":{description:\"Ensure every ARIA input field has an accessible name\",help:\"ARIA input fields must have an accessible name\"},\"aria-meter-name\":{description:\"Ensure every ARIA meter node has an accessible name\",help:\"ARIA meter nodes must have an accessible name\"},\"aria-progre\\\nssbar-name\":{description:\"Ensure every ARIA progressbar node has an accessible name\",help:\"ARIA progressbar nodes must have an accessible name\"},\"aria-prohibited-attr\":{description:\"Ensure ARIA attributes are not prohibited for an element's role\",help:\"Elements must only use permitted ARIA attributes\"},\"aria-required-attr\":{description:\"Ensure elements with ARIA roles have all required ARIA attributes\",help:\"Required ARIA attributes must be provided\"},\"aria-required-children\":{description:\"Ensure elements with an ARIA role that require child roles contain them\",help:\"Certain ARIA roles must contain particular children\"},\"aria-required-parent\":{description:\"Ensure elements with an ARIA role that require parent roles are contained by them\",help:\"Certain ARIA roles must be contained by particular parents\"},\"aria-roledescription\":{description:\"Ensure aria-roledescription is only used on elements with an implicit or explicit role\",help:\"aria-roledescription must be on elements with a semant\\\nic role\"},\"aria-roles\":{description:\"Ensure all elements with a role attribute use a valid value\",help:\"ARIA roles used must conform to valid values\"},\"aria-text\":{description:'Ensure role=\"text\" is used on elements with no focusable descendants',help:'\"role=text\" should have no focusable descendants'},\"aria-toggle-field-name\":{description:\"Ensure every ARIA toggle field has an accessible name\",help:\"ARIA toggle fields must have an accessible name\"},\"aria-tooltip-name\":{description:\"Ensure every ARIA tooltip node has an accessible name\",help:\"ARIA tooltip nodes must have an accessible name\"},\"aria-treeitem-name\":{description:\"Ensure every ARIA treeitem node has an accessible name\",help:\"ARIA treeitem nodes should have an accessible name\"},\"aria-valid-attr-value\":{description:\"Ensure all ARIA attributes have valid values\",help:\"ARIA attributes must conform to valid values\"},\"aria-valid-attr\":{description:\"Ensure attributes that begin with aria- are valid ARIA attributes\",help:\"ARIA attr\\\nibutes must conform to valid names\"},\"audio-caption\":{description:\"Ensure <audio> elements have captions\",help:\"<audio> elements must have a captions track\"},\"autocomplete-valid\":{description:\"Ensure the autocomplete attribute is correct and suitable for the form field\",help:\"autocomplete attribute must be used correctly\"},\"avoid-inline-spacing\":{description:\"Ensure that text spacing set through style attributes can be adjusted with custom stylesheets\",help:\"Inline text spacing must be adjustable with custom stylesheets\"},blink:{description:\"Ensure <blink> elements are not used\",help:\"<blink> elements are deprecated and must not be used\"},\"button-name\":{description:\"Ensure buttons have discernible text\",help:\"Buttons must have discernible text\"},bypass:{description:\"Ensure each page has at least one mechanism for a user to bypass navigation and jump straight to the content\",help:\"Page must have means to bypass repeated blocks\"},\"color-contrast-enhanced\":{description:\"Ensure the contras\\\nt between foreground and background colors meets WCAG 2 AAA enhanced contrast ratio thresholds\",help:\"Elements must meet enhanced color contrast ratio thresholds\"},\"color-contrast\":{description:\"Ensure the contrast between foreground and background colors meets WCAG 2 AA minimum contrast ratio thresholds\",help:\"Elements must meet minimum color contrast ratio thresholds\"},\"css-orientation-lock\":{description:\"Ensure content is not locked to any specific display orientation, and the content is operable in all display orientations\",help:\"CSS Media queries must not lock display orientation\"},\"definition-list\":{description:\"Ensure <dl> elements are structured correctly\",help:\"<dl> elements must only directly contain properly-ordered <dt> and <dd> groups, <script>, <template> or <div> elements\"},dlitem:{description:\"Ensure <dt> and <dd> elements are contained by a <dl>\",help:\"<dt> and <dd> elements must be contained by a <dl>\"},\"document-title\":{description:\"Ensure each HTML document contains\\\n a non-empty <title> element\",help:\"Documents must have <title> element to aid in navigation\"},\"duplicate-id-active\":{description:\"Ensure every id attribute value of active elements is unique\",help:\"IDs of active elements must be unique\"},\"duplicate-id-aria\":{description:\"Ensure every id attribute value used in ARIA and in labels is unique\",help:\"IDs used in ARIA and labels must be unique\"},\"duplicate-id\":{description:\"Ensure every id attribute value is unique\",help:\"id attribute value must be unique\"},\"empty-heading\":{description:\"Ensure headings have discernible text\",help:\"Headings should not be empty\"},\"empty-table-header\":{description:\"Ensure table headers have discernible text\",help:\"Table header text should not be empty\"},\"focus-order-semantics\":{description:\"Ensure elements in the focus order have a role appropriate for interactive content\",help:\"Elements in the focus order should have an appropriate role\"},\"form-field-multiple-labels\":{description:\"Ensure form field does not h\\\nave multiple label elements\",help:\"Form field must not have multiple label elements\"},\"frame-focusable-content\":{description:\"Ensure <frame> and <iframe> elements with focusable content do not have tabindex=-1\",help:\"Frames with focusable content must not have tabindex=-1\"},\"frame-tested\":{description:\"Ensure <iframe> and <frame> elements contain the axe-core script\",help:\"Frames should be tested with axe-core\"},\"frame-title-unique\":{description:\"Ensure <iframe> and <frame> elements contain a unique title attribute\",help:\"Frames must have a unique title attribute\"},\"frame-title\":{description:\"Ensure <iframe> and <frame> elements have an accessible name\",help:\"Frames must have an accessible name\"},\"heading-order\":{description:\"Ensure the order of headings is semantically correct\",help:\"Heading levels should only increase by one\"},\"hidden-content\":{description:\"Inform users about hidden content.\",help:\"Hidden content on the page should be analyzed\"},\"html-has-lang\":{description:\"Ensure e\\\nvery HTML document has a lang attribute\",help:\"<html> element must have a lang attribute\"},\"html-lang-valid\":{description:\"Ensure the lang attribute of the <html> element has a valid value\",help:\"<html> element must have a valid value for the lang attribute\"},\"html-xml-lang-mismatch\":{description:\"Ensure that HTML elements with both valid lang and xml:lang attributes agree on the base language of the page\",help:\"HTML elements with lang and xml:lang must have the same base language\"},\"identical-links-same-purpose\":{description:\"Ensure that links with the same accessible name serve a similar purpose\",help:\"Links with the same name must have a similar purpose\"},\"image-alt\":{description:\"Ensure <img> elements have alternative text or a role of none or presentation\",help:\"Images must have alternative text\"},\"image-redundant-alt\":{description:\"Ensure image alternative is not repeated as text\",help:\"Alternative text of images should not be repeated as text\"},\"input-button-name\":{description:\"\\\nEnsure input buttons have discernible text\",help:\"Input buttons must have discernible text\"},\"input-image-alt\":{description:'Ensure <input type=\"image\"> elements have alternative text',help:\"Image buttons must have alternative text\"},\"label-content-name-mismatch\":{description:\"Ensure that elements labelled through their content must have their visible text as part of their accessible name\",help:\"Elements must have their visible text as part of their accessible name\"},\"label-title-only\":{description:\"Ensure that every form element has a visible label and is not solely labeled using hidden labels, or the title or aria-describedby attributes\",help:\"Form elements should have a visible label\"},label:{description:\"Ensure every form element has a label\",help:\"Form elements must have labels\"},\"landmark-banner-is-top-level\":{description:\"Ensure the banner landmark is at top level\",help:\"Banner landmark should not be contained in another landmark\"},\"landmark-complementary-is-top-level\":{descript\\\nion:\"Ensure the complementary landmark or aside is at top level\",help:\"Aside should not be contained in another landmark\"},\"landmark-contentinfo-is-top-level\":{description:\"Ensure the contentinfo landmark is at top level\",help:\"Contentinfo landmark should not be contained in another landmark\"},\"landmark-main-is-top-level\":{description:\"Ensure the main landmark is at top level\",help:\"Main landmark should not be contained in another landmark\"},\"landmark-no-duplicate-banner\":{description:\"Ensure the document has at most one banner landmark\",help:\"Document should not have more than one banner landmark\"},\"landmark-no-duplicate-contentinfo\":{description:\"Ensure the document has at most one contentinfo landmark\",help:\"Document should not have more than one contentinfo landmark\"},\"landmark-no-duplicate-main\":{description:\"Ensure the document has at most one main landmark\",help:\"Document should not have more than one main landmark\"},\"landmark-one-main\":{description:\"Ensure the document has a ma\\\nin landmark\",help:\"Document should have one main landmark\"},\"landmark-unique\":{description:\"Ensure landmarks are unique\",help:\"Landmarks should have a unique role or role/label/title (i.e. accessible name) combination\"},\"link-in-text-block\":{description:\"Ensure links are distinguished from surrounding text in a way that does not rely on color\",help:\"Links must be distinguishable without relying on color\"},\"link-name\":{description:\"Ensure links have discernible text\",help:\"Links must have discernible text\"},list:{description:\"Ensure that lists are structured correctly\",help:\"<ul> and <ol> must only directly contain <li>, <script> or <template> elements\"},listitem:{description:\"Ensure <li> elements are used semantically\",help:\"<li> elements must be contained in a <ul> or <ol>\"},marquee:{description:\"Ensure <marquee> elements are not used\",help:\"<marquee> elements are deprecated and must not be used\"},\"meta-refresh-no-exceptions\":{description:'Ensure <meta http-equiv=\"refresh\"> is not use\\\nd for delayed refresh',help:\"Delayed refresh must not be used\"},\"meta-refresh\":{description:'Ensure <meta http-equiv=\"refresh\"> is not used for delayed refresh',help:\"Delayed refresh under 20 hours must not be used\"},\"meta-viewport-large\":{description:'Ensure <meta name=\"viewport\"> can scale a significant amount',help:\"Users should be able to zoom and scale the text up to 500%\"},\"meta-viewport\":{description:'Ensure <meta name=\"viewport\"> does not disable text scaling and zooming',help:\"Zooming and scaling must not be disabled\"},\"nested-interactive\":{description:\"Ensure interactive controls are not nested as they are not always announced by screen readers or can cause focus problems for assistive technologies\",help:\"Interactive controls must not be nested\"},\"no-autoplay-audio\":{description:\"Ensure <video> or <audio> elements do not autoplay audio for more than 3 seconds without a control mechanism to stop or mute the audio\",help:\"<video> or <audio> elements must not play automatically\"}\\\n,\"object-alt\":{description:\"Ensure <object> elements have alternative text\",help:\"<object> elements must have alternative text\"},\"p-as-heading\":{description:\"Ensure bold, italic text and font-size is not used to style <p> elements as a heading\",help:\"Styled <p> elements must not be used as headings\"},\"page-has-heading-one\":{description:\"Ensure that the page, or at least one of its frames contains a level-one heading\",help:\"Page should contain a level-one heading\"},\"presentation-role-conflict\":{description:\"Ensure elements marked as presentational do not have global ARIA or tabindex so that all screen readers ignore them\",help:\"Elements marked as presentational should be consistently ignored\"},region:{description:\"Ensure all page content is contained by landmarks\",help:\"All page content should be contained by landmarks\"},\"role-img-alt\":{description:'Ensure [role=\"img\"] elements have alternative text',help:'[role=\"img\"] elements must have alternative text'},\"scope-attr-valid\":{descriptio\\\nn:\"Ensure the scope attribute is used correctly on tables\",help:\"scope attribute should be used correctly\"},\"scrollable-region-focusable\":{description:\"Ensure elements that have scrollable content are accessible by keyboard\",help:\"Scrollable region must have keyboard access\"},\"select-name\":{description:\"Ensure select element has an accessible name\",help:\"Select element must have an accessible name\"},\"server-side-image-map\":{description:\"Ensure that server-side image maps are not used\",help:\"Server-side image maps must not be used\"},\"skip-link\":{description:\"Ensure all skip links have a focusable target\",help:\"The skip-link target should exist and be focusable\"},\"summary-name\":{description:\"Ensure summary elements have discernible text\",help:\"Summary elements must have discernible text\"},\"svg-img-alt\":{description:\"Ensure <svg> elements with an img, graphics-document or graphics-symbol role have accessible text\",help:\"<svg> elements with an img role must have alternative text\"},tabindex\\\n:{description:\"Ensure tabindex attribute values are not greater than 0\",help:\"Elements should not have tabindex greater than zero\"},\"table-duplicate-name\":{description:\"Ensure the <caption> element does not contain the same text as the summary attribute\",help:\"Tables should not have the same summary and caption\"},\"table-fake-caption\":{description:\"Ensure that tables with a caption use the <caption> element.\",help:\"Data or header cells must not be used to give caption to a data table.\"},\"target-size\":{description:\"Ensure touch targets have sufficient size and space\",help:\"All touch targets must be 24px large, or leave sufficient space\"},\"td-has-header\":{description:\"Ensure that each non-empty data cell in a <table> larger than 3 by 3  has one or more table headers\",help:\"Non-empty <td> elements in larger <table> must have an associated table header\"},\"td-headers-attr\":{description:\"Ensure that each cell in a table that uses the headers attribute refers only to other <th> elements in tha\\\nt table\",help:\"Table cell headers attributes must refer to other <th> elements in the same table\"},\"th-has-data-cells\":{description:\"Ensure that <th> elements and elements with role=columnheader/rowheader have data cells they describe\",help:\"Table headers in a data table must refer to data cells\"},\"valid-lang\":{description:\"Ensure lang attributes have valid values\",help:\"lang attribute must have a valid value\"},\"video-caption\":{description:\"Ensure <video> elements have captions\",help:\"<video> elements must have captions\"}},checks:{abstractrole:{impact:\"serious\",messages:{pass:\"Abstract roles are not used\",fail:{singular:\"Abstract role cannot be directly used: \\${data.values}\",plural:\"Abstract roles cannot be directly used: \\${data.values}\"}}},\"aria-allowed-attr\":{impact:\"critical\",messages:{pass:\"ARIA attributes are used correctly for the defined role\",fail:{singular:\"ARIA attribute is not allowed: \\${data.values}\",plural:\"ARIA attributes are not allowed: \\${data.values}\"},incomplete:\"Chec\\\nk that there is no problem if the ARIA attribute is ignored on this element: \\${data.values}\"}},\"aria-allowed-role\":{impact:\"minor\",messages:{pass:\"ARIA role is allowed for given element\",fail:{singular:\"ARIA role \\${data.values} is not allowed for given element\",plural:\"ARIA roles \\${data.values} are not allowed for given element\"},incomplete:{singular:\"ARIA role \\${data.values} must be removed when the element is made visible, as it is not allowed for the element\",plural:\"ARIA roles \\${data.values} must be removed when the element is made visible, as they are not allowed for the element\"}}},\"aria-busy\":{impact:\"serious\",messages:{pass:\"Element has an aria-busy attribute\",fail:'Element uses aria-busy=\"true\" while showing a loader'}},\"aria-conditional-attr\":{impact:\"serious\",messages:{pass:\"ARIA attribute is allowed\",fail:{checkbox:'Remove aria-checked, or set it to \"\\${data.checkState}\" to match the real checkbox state',rowSingular:\"This attribute is supported with treegrid rows, but not \\${\\\ndata.ownerRole}: \\${data.invalidAttrs}\",rowPlural:\"These attributes are supported with treegrid rows, but not \\${data.ownerRole}: \\${data.invalidAttrs}\"}}},\"aria-errormessage\":{impact:\"critical\",messages:{pass:\"aria-errormessage exists and references elements visible to screen readers that use a supported aria-errormessage technique\",fail:{singular:\"aria-errormessage value \\`\\${data.values}\\` must use a technique to announce the message (e.g., aria-live, aria-describedby, role=alert, etc.)\",plural:\"aria-errormessage values \\`\\${data.values}\\` must use a technique to announce the message (e.g., aria-live, aria-describedby, role=alert, etc.)\",hidden:\"aria-errormessage value \\`\\${data.values}\\` cannot reference a hidden element\"},incomplete:{singular:\"Ensure aria-errormessage value \\`\\${data.values}\\` references an existing element\",plural:\"Ensure aria-errormessage values \\`\\${data.values}\\` reference existing elements\",idrefs:\"Unable to determine if aria-errormessage element exists on the page: \\${data.val\\\nues}\"}}},\"aria-hidden-body\":{impact:\"critical\",messages:{pass:\"No aria-hidden attribute is present on document body\",fail:\"aria-hidden=true should not be present on the document body\"}},\"aria-level\":{impact:\"serious\",messages:{pass:\"aria-level values are valid\",incomplete:\"aria-level values greater than 6 are not supported in all screenreader and browser combinations\"}},\"aria-prohibited-attr\":{impact:\"serious\",messages:{pass:\"ARIA attribute is allowed\",fail:{hasRolePlural:'\\${data.prohibited} attributes cannot be used with role \"\\${data.role}\".',hasRoleSingular:'\\${data.prohibited} attribute cannot be used with role \"\\${data.role}\".',noRolePlural:\"\\${data.prohibited} attributes cannot be used on a \\${data.nodeName} with no valid role attribute.\",noRoleSingular:\"\\${data.prohibited} attribute cannot be used on a \\${data.nodeName} with no valid role attribute.\"},incomplete:{hasRoleSingular:'\\${data.prohibited} attribute is not well supported with role \"\\${data.role}\".',hasRolePlural:'\\${data.prohibi\\\nted} attributes are not well supported with role \"\\${data.role}\".',noRoleSingular:\"\\${data.prohibited} attribute is not well supported on a \\${data.nodeName} with no valid role attribute.\",noRolePlural:\"\\${data.prohibited} attributes are not well supported on a \\${data.nodeName} with no valid role attribute.\"}}},\"aria-required-attr\":{impact:\"critical\",messages:{pass:\"All required ARIA attributes are present\",fail:{singular:\"Required ARIA attribute not present: \\${data.values}\",plural:\"Required ARIA attributes not present: \\${data.values}\"}}},\"aria-required-children\":{impact:\"critical\",messages:{pass:{default:\"Required ARIA children are present\",\"aria-busy\":\"Element has an aria-busy attribute, so it is allowed to omit required children\"},fail:{singular:\"Required ARIA child role not present: \\${data.values}\",plural:\"Required ARIA children role not present: \\${data.values}\",unallowed:\"Element has children which are not allowed: \\${data.values}\"},incomplete:{singular:\"Expecting ARIA child role to be\\\n added: \\${data.values}\",plural:\"Expecting ARIA children role to be added: \\${data.values}\"}}},\"aria-required-parent\":{impact:\"critical\",messages:{pass:\"Required ARIA parent role present\",fail:{singular:\"Required ARIA parent role not present: \\${data.values}\",plural:\"Required ARIA parents role not present: \\${data.values}\"}}},\"aria-roledescription\":{impact:\"serious\",messages:{pass:\"aria-roledescription used on a supported semantic role\",incomplete:\"Check that the aria-roledescription is announced by supported screen readers\",fail:\"Give the element a role that supports aria-roledescription\"}},\"aria-unsupported-attr\":{impact:\"critical\",messages:{pass:\"ARIA attribute is supported\",fail:\"ARIA attribute is not widely supported in screen readers and assistive technologies: \\${data.values}\"}},\"aria-valid-attr-value\":{impact:\"critical\",messages:{pass:\"ARIA attribute values are valid\",fail:{singular:\"Invalid ARIA attribute value: \\${data.values}\",plural:\"Invalid ARIA attribute values: \\${data.values}\"\\\n},incomplete:{noId:\"ARIA attribute element ID does not exist on the page: \\${data.needsReview}\",noIdShadow:\"ARIA attribute element ID does not exist on the page or is a descendant of a different shadow DOM tree: \\${data.needsReview}\",ariaCurrent:'ARIA attribute value is invalid and will be treated as \"aria-current=true\": \\${data.needsReview}',idrefs:\"Unable to determine if ARIA attribute element ID exists on the page: \\${data.needsReview}\",empty:\"ARIA attribute value is ignored while empty: \\${data.needsReview}\",controlsWithinPopup:\"Unable to determine if aria-controls referenced ID exists on the page while using aria-haspopup: \\${data.needsReview}\"}}},\"aria-valid-attr\":{impact:\"critical\",messages:{pass:\"ARIA attribute name is valid\",fail:{singular:\"Invalid ARIA attribute name: \\${data.values}\",plural:\"Invalid ARIA attribute names: \\${data.values}\"}}},\"braille-label-equivalent\":{impact:\"serious\",messages:{pass:\"aria-braillelabel is used on an element with accessible text\",fail:\"aria-braillelab\\\nel is used on an element with no accessible text\",incomplete:\"Unable to compute accessible text\"}},\"braille-roledescription-equivalent\":{impact:\"serious\",messages:{pass:\"aria-brailleroledescription is used on an element with aria-roledescription\",fail:{noRoleDescription:\"aria-brailleroledescription is used on an element with no aria-roledescription\",emptyRoleDescription:\"aria-brailleroledescription is used on an element with an empty aria-roledescription\"}}},deprecatedrole:{impact:\"minor\",messages:{pass:\"ARIA role is not deprecated\",fail:\"The role used is deprecated: \\${data}\"}},fallbackrole:{impact:\"serious\",messages:{pass:\"Only one role value used\",fail:\"Use only one role value, since fallback roles are not supported in older browsers\",incomplete:\"Use only role 'presentation' or 'none' since they are synonymous.\"}},\"has-global-aria-attribute\":{impact:\"minor\",messages:{pass:{singular:\"Element has global ARIA attribute: \\${data.values}\",plural:\"Element has global ARIA attributes: \\${data.\\\nvalues}\"},fail:\"Element does not have global ARIA attribute\"}},\"has-widget-role\":{impact:\"minor\",messages:{pass:\"Element has a widget role.\",fail:\"Element does not have a widget role.\"}},invalidrole:{impact:\"critical\",messages:{pass:\"ARIA role is valid\",fail:{singular:\"Role must be one of the valid ARIA roles: \\${data.values}\",plural:\"Roles must be one of the valid ARIA roles: \\${data.values}\"}}},\"is-element-focusable\":{impact:\"minor\",messages:{pass:\"Element is focusable.\",fail:\"Element is not focusable.\"}},\"no-implicit-explicit-label\":{impact:\"serious\",messages:{pass:\"There is no mismatch between a <label> and accessible name\",incomplete:\"Check that the <label> does not need be part of the ARIA \\${data} field's name\"}},unsupportedrole:{impact:\"critical\",messages:{pass:\"ARIA role is supported\",fail:\"The role used is not widely supported in screen readers and assistive technologies: \\${data}\"}},\"valid-scrollable-semantics\":{impact:\"minor\",messages:{pass:\"Element has valid semantics for an e\\\nlement in the focus order.\",fail:\"Element has invalid semantics for an element in the focus order.\"}},\"color-contrast-enhanced\":{impact:\"serious\",messages:{pass:\"Element has sufficient color contrast of \\${data.contrastRatio}\",fail:{default:\"Element has insufficient color contrast of \\${data.contrastRatio} (foreground color: \\${data.fgColor}, background color: \\${data.bgColor}, font size: \\${data.fontSize}, font weight: \\${data.fontWeight}). Expected contrast ratio of \\${data.expectedContrastRatio}\",fgOnShadowColor:\"Element has insufficient color contrast of \\${data.contrastRatio} between the foreground and shadow color (foreground color: \\${data.fgColor}, text-shadow color: \\${data.shadowColor}, font size: \\${data.fontSize}, font weight: \\${data.fontWeight}). Expected contrast ratio of \\${data.expectedContrastRatio}\",shadowOnBgColor:\"Element has insufficient color contrast of \\${data.contrastRatio} between the shadow color and background color (text-shadow color: \\${data.shadowColor}, background col\\\nor: \\${data.bgColor}, font size: \\${data.fontSize}, font weight: \\${data.fontWeight}). Expected contrast ratio of \\${data.expectedContrastRatio}\"},incomplete:{default:\"Unable to determine contrast ratio\",bgImage:\"Element's background color could not be determined due to a background image\",bgGradient:\"Element's background color could not be determined due to a background gradient\",imgNode:\"Element's background color could not be determined because element contains an image node\",bgOverlap:\"Element's background color could not be determined because it is overlapped by another element\",fgAlpha:\"Element's foreground color could not be determined because of alpha transparency\",elmPartiallyObscured:\"Element's background color could not be determined because it's partially obscured by another element\",elmPartiallyObscuring:\"Element's background color could not be determined because it partially overlaps other elements\",outsideViewport:\"Element's background color could not be determined because i\\\nt's outside the viewport\",equalRatio:\"Element has a 1:1 contrast ratio with the background\",shortTextContent:\"Element content is too short to determine if it is actual text content\",nonBmp:\"Element content contains only non-text characters\",pseudoContent:\"Element's background color could not be determined due to a pseudo element\"}}},\"color-contrast\":{impact:\"serious\",messages:{pass:{default:\"Element has sufficient color contrast of \\${data.contrastRatio}\",hidden:\"Element is hidden\"},fail:{default:\"Element has insufficient color contrast of \\${data.contrastRatio} (foreground color: \\${data.fgColor}, background color: \\${data.bgColor}, font size: \\${data.fontSize}, font weight: \\${data.fontWeight}). Expected contrast ratio of \\${data.expectedContrastRatio}\",fgOnShadowColor:\"Element has insufficient color contrast of \\${data.contrastRatio} between the foreground and shadow color (foreground color: \\${data.fgColor}, text-shadow color: \\${data.shadowColor}, font size: \\${data.fontSize}, font weight: \\$\\\n{data.fontWeight}). Expected contrast ratio of \\${data.expectedContrastRatio}\",shadowOnBgColor:\"Element has insufficient color contrast of \\${data.contrastRatio} between the shadow color and background color (text-shadow color: \\${data.shadowColor}, background color: \\${data.bgColor}, font size: \\${data.fontSize}, font weight: \\${data.fontWeight}). Expected contrast ratio of \\${data.expectedContrastRatio}\"},incomplete:{default:\"Unable to determine contrast ratio\",bgImage:\"Element's background color could not be determined due to a background image\",bgGradient:\"Element's background color could not be determined due to a background gradient\",imgNode:\"Element's background color could not be determined because element contains an image node\",bgOverlap:\"Element's background color could not be determined because it is overlapped by another element\",complexTextShadows:\"Element's contrast could not be determined because it uses complex text shadows\",fgAlpha:\"Element's foreground color could not be de\\\ntermined because of alpha transparency\",elmPartiallyObscured:\"Element's background color could not be determined because it's partially obscured by another element\",elmPartiallyObscuring:\"Element's background color could not be determined because it partially overlaps other elements\",outsideViewport:\"Element's background color could not be determined because it's outside the viewport\",equalRatio:\"Element has a 1:1 contrast ratio with the background\",shortTextContent:\"Element content is too short to determine if it is actual text content\",nonBmp:\"Element content contains only non-text characters\",pseudoContent:\"Element's background color could not be determined due to a pseudo element\"}}},\"link-in-text-block-style\":{impact:\"serious\",messages:{pass:\"Links can be distinguished from surrounding text by visual styling\",incomplete:{default:\"Check if the link needs styling to distinguish it from nearby text\",pseudoContent:\"Check if the link's pseudo style is sufficient to distinguish it from \\\nthe surrounding text\"},fail:\"The link has no styling (such as underline) to distinguish it from the surrounding text\"}},\"link-in-text-block\":{impact:\"serious\",messages:{pass:\"Links can be distinguished from surrounding text in some way other than by color\",fail:{fgContrast:\"The link has insufficient color contrast of \\${data.contrastRatio}:1 with the surrounding text. (Minimum contrast is \\${data.requiredContrastRatio}:1, link text: \\${data.nodeColor}, surrounding text: \\${data.parentColor})\",bgContrast:\"The link background has insufficient color contrast of \\${data.contrastRatio} (Minimum contrast is \\${data.requiredContrastRatio}:1, link background color: \\${data.nodeBackgroundColor}, surrounding background color: \\${data.parentBackgroundColor})\"},incomplete:{default:\"Element's foreground contrast ratio could not be determined\",bgContrast:\"Element's background contrast ratio could not be determined\",bgImage:\"Element's contrast ratio could not be determined due to a background image\",bgGradie\\\nnt:\"Element's contrast ratio could not be determined due to a background gradient\",imgNode:\"Element's contrast ratio could not be determined because element contains an image node\",bgOverlap:\"Element's contrast ratio could not be determined because of element overlap\"}}},\"autocomplete-appropriate\":{impact:\"serious\",messages:{pass:\"The autocomplete value is on an appropriate element\",fail:\"The autocomplete value is inappropriate for this type of input\"}},\"autocomplete-valid\":{impact:\"serious\",messages:{pass:\"the autocomplete attribute is correctly formatted\",fail:\"the autocomplete attribute is incorrectly formatted\",incomplete:\"the autocomplete attribute has a non-standard value. Check whether any standard value could be used instead.\"}},accesskeys:{impact:\"serious\",messages:{pass:\"Accesskey attribute value is unique\",fail:\"Document has multiple elements with the same accesskey\"}},\"focusable-content\":{impact:\"serious\",messages:{pass:\"Element contains focusable elements\",fail:\"Element sh\\\nould have focusable content\"}},\"focusable-disabled\":{impact:\"serious\",messages:{pass:\"No focusable elements contained within element\",incomplete:\"Check if the focusable elements immediately move the focus indicator\",fail:\"Focusable content should be disabled or be removed from the DOM\"}},\"focusable-element\":{impact:\"serious\",messages:{pass:\"Element is focusable\",fail:\"Element should be focusable\"}},\"focusable-modal-open\":{impact:\"serious\",messages:{pass:\"No focusable elements while a modal is open\",incomplete:\"Check that focusable elements are not tabbable in the current state\"}},\"focusable-no-name\":{impact:\"serious\",messages:{pass:\"Element is not in tab order or has accessible text\",fail:\"Element is in tab order and does not have accessible text\",incomplete:\"Unable to determine if element has an accessible name\"}},\"focusable-not-tabbable\":{impact:\"serious\",messages:{pass:\"No focusable elements contained within element\",incomplete:\"Check if the focusable elements immediately move the f\\\nocus indicator\",fail:'Focusable content should have tabindex=\"-1\" or be removed from the DOM'}},\"frame-focusable-content\":{impact:\"serious\",messages:{pass:\"Element does not have focusable descendants\",fail:\"Element has focusable descendants\",incomplete:\"Could not determine if element has descendants\"}},\"landmark-is-top-level\":{impact:\"moderate\",messages:{pass:\"The \\${data.role} landmark is at the top level.\",fail:\"The \\${data.role} landmark is contained in another landmark.\"}},\"no-focusable-content\":{impact:\"serious\",messages:{pass:\"Element does not have focusable descendants\",fail:{default:\"Element has focusable descendants\",notHidden:'Using a negative tabindex on an element inside an interactive control does not prevent assistive technologies from focusing the element (even with aria-hidden=\"true\")'},incomplete:\"Could not determine if element has descendants\"}},\"page-has-heading-one\":{impact:\"moderate\",messages:{pass:\"Page has at least one level-one heading\",fail:\"Page must have a leve\\\nl-one heading\"}},\"page-has-main\":{impact:\"moderate\",messages:{pass:\"Document has at least one main landmark\",fail:\"Document does not have a main landmark\"}},\"page-no-duplicate-banner\":{impact:\"moderate\",messages:{pass:\"Document does not have more than one banner landmark\",fail:\"Document has more than one banner landmark\"}},\"page-no-duplicate-contentinfo\":{impact:\"moderate\",messages:{pass:\"Document does not have more than one contentinfo landmark\",fail:\"Document has more than one contentinfo landmark\"}},\"page-no-duplicate-main\":{impact:\"moderate\",messages:{pass:\"Document does not have more than one main landmark\",fail:\"Document has more than one main landmark\"}},tabindex:{impact:\"serious\",messages:{pass:\"Element does not have a tabindex greater than 0\",fail:\"Element has a tabindex greater than 0\"}},\"alt-space-value\":{impact:\"critical\",messages:{pass:\"Element has a valid alt attribute value\",fail:\"Element has an alt attribute containing only a space character, which is not ignored by all\\\n screen readers\"}},\"duplicate-img-label\":{impact:\"minor\",messages:{pass:\"Element does not duplicate existing text in <img> alt text\",fail:\"Element contains <img> element with alt text that duplicates existing text\"}},\"explicit-label\":{impact:\"critical\",messages:{pass:\"Element has an explicit <label>\",fail:\"Element does not have an explicit <label>\",incomplete:\"Unable to determine if form element has an explicit <label>\"}},\"help-same-as-label\":{impact:\"minor\",messages:{pass:\"Help text (title or aria-describedby) does not duplicate label text\",fail:\"Help text (title or aria-describedby) text is the same as the label text\"}},\"hidden-explicit-label\":{impact:\"critical\",messages:{pass:\"Form element has a visible explicit <label>\",fail:\"Form element has explicit <label> that is hidden\",incomplete:\"Unable to determine if form element has explicit <label> that is hidden\"}},\"implicit-label\":{impact:\"critical\",messages:{pass:\"Element has an implicit (wrapped) <label>\",fail:\"Element does not have \\\nan implicit (wrapped) <label>\",incomplete:\"Unable to determine if form element has an implicit (wrapped) <label>\"}},\"label-content-name-mismatch\":{impact:\"serious\",messages:{pass:\"Element contains visible text as part of it's accessible name\",fail:\"Text inside the element is not included in the accessible name\"}},\"multiple-label\":{impact:\"moderate\",messages:{pass:\"Form field does not have multiple label elements\",incomplete:\"Multiple label elements is not widely supported in assistive technologies. Ensure the first label contains all necessary information.\"}},\"title-only\":{impact:\"serious\",messages:{pass:\"Form element does not solely use title attribute for its label\",fail:\"Only title used to generate label for form element\"}},\"landmark-is-unique\":{impact:\"moderate\",messages:{pass:\"Landmarks must have a unique role or role/label/title (i.e. accessible name) combination\",fail:\"The landmark must have a unique aria-label, aria-labelledby, or title to make landmarks distinguishable\"}},\"has\\\n-lang\":{impact:\"serious\",messages:{pass:\"The <html> element has a lang attribute\",fail:{noXHTML:\"The xml:lang attribute is not valid on HTML pages, use the lang attribute.\",noLang:\"The <html> element does not have a lang attribute\"}}},\"valid-lang\":{impact:\"serious\",messages:{pass:\"Value of lang attribute is included in the list of valid languages\",fail:\"Value of lang attribute not included in the list of valid languages\"}},\"xml-lang-mismatch\":{impact:\"moderate\",messages:{pass:\"Lang and xml:lang attributes have the same base language\",fail:\"Lang and xml:lang attributes do not have the same base language\"}},dlitem:{impact:\"serious\",messages:{pass:\"Description list item has a <dl> parent element\",fail:\"Description list item does not have a <dl> parent element\"}},listitem:{impact:\"serious\",messages:{pass:'List item has a <ul>, <ol> or role=\"list\" parent element',fail:{default:\"List item does not have a <ul>, <ol> parent element\",roleNotValid:'List item parent element has a role that is not\\\n role=\"list\"'}}},\"only-dlitems\":{impact:\"serious\",messages:{pass:\"dl element only has direct children that are allowed inside; <dt>, <dd>, or <div> elements\",fail:\"dl element has direct children that are not allowed: \\${data.values}\"}},\"only-listitems\":{impact:\"serious\",messages:{pass:\"List element only has direct children that are allowed inside <li> elements\",fail:\"List element has direct children that are not allowed: \\${data.values}\"}},\"structured-dlitems\":{impact:\"serious\",messages:{pass:\"When not empty, element has both <dt> and <dd> elements\",fail:\"When not empty, element does not have at least one <dt> element followed by at least one <dd> element\"}},caption:{impact:\"critical\",messages:{pass:\"The multimedia element has a captions track\",incomplete:\"Check that captions are available for the element\"}},\"frame-tested\":{impact:\"critical\",messages:{pass:\"The iframe was tested with axe-core\",fail:\"The iframe could not be tested with axe-core\",incomplete:\"The iframe still has to be test\\\ned with axe-core\"}},\"no-autoplay-audio\":{impact:\"moderate\",messages:{pass:\"<video> or <audio> does not output audio for more than allowed duration or has controls mechanism\",fail:\"<video> or <audio> outputs audio for more than allowed duration and does not have a controls mechanism\",incomplete:\"Check that the <video> or <audio> does not output audio for more than allowed duration or provides a controls mechanism\"}},\"css-orientation-lock\":{impact:\"serious\",messages:{pass:\"Display is operable, and orientation lock does not exist\",fail:\"CSS Orientation lock is applied, and makes display inoperable\",incomplete:\"CSS Orientation lock cannot be determined\"}},\"meta-viewport-large\":{impact:\"minor\",messages:{pass:\"<meta> tag does not prevent significant zooming on mobile devices\",fail:\"<meta> tag limits zooming on mobile devices\"}},\"meta-viewport\":{impact:\"critical\",messages:{pass:\"<meta> tag does not disable zooming on mobile devices\",fail:\"\\${data} on <meta> tag disables zooming on mobile devic\\\nes\"}},\"target-offset\":{impact:\"serious\",messages:{pass:{default:\"Target has sufficient space from its closest neighbors. Safe clickable space has a diameter of \\${data.closestOffset}px which is at least \\${data.minOffset}px.\",large:\"Target far exceeds the minimum size of \\${data.minOffset}px.\"},fail:\"Target has insufficient space to its closest neighbors. Safe clickable space has a diameter of \\${data.closestOffset}px instead of at least \\${data.minOffset}px.\",incomplete:{default:\"Element with negative tabindex has insufficient space to its closest neighbors. Safe clickable space has a diameter of \\${data.closestOffset}px instead of at least \\${data.minOffset}px. Is this a target?\",nonTabbableNeighbor:\"Target has insufficient space to its closest neighbors. Safe clickable space has a diameter of \\${data.closestOffset}px instead of at least \\${data.minOffset}px. Is the neighbor a target?\",tooManyRects:\"Could not get the target size because there are too many overlapping elements\"}}},\"target-size\\\n\":{impact:\"serious\",messages:{pass:{default:\"Control has sufficient size (\\${data.width}px by \\${data.height}px, should be at least \\${data.minSize}px by \\${data.minSize}px)\",obscured:\"Control is ignored because it is fully obscured and thus not clickable\",large:\"Target far exceeds the minimum size of \\${data.minSize}px.\"},fail:{default:\"Target has insufficient size (\\${data.width}px by \\${data.height}px, should be at least \\${data.minSize}px by \\${data.minSize}px)\",partiallyObscured:\"Target has insufficient size because it is partially obscured (smallest space is \\${data.width}px by \\${data.height}px, should be at least \\${data.minSize}px by \\${data.minSize}px)\"},incomplete:{default:\"Element with negative tabindex has insufficient size (\\${data.width}px by \\${data.height}px, should be at least \\${data.minSize}px by \\${data.minSize}px). Is this a target?\",contentOverflow:\"Element size could not be accurately determined due to overflow content\",partiallyObscured:\"Element with negative tabindex has insuf\\\nficient size because it is partially obscured (smallest space is \\${data.width}px by \\${data.height}px, should be at least \\${data.minSize}px by \\${data.minSize}px). Is this a target?\",partiallyObscuredNonTabbable:\"Target has insufficient size because it is partially obscured by a neighbor with negative tabindex (smallest space is \\${data.width}px by \\${data.height}px, should be at least \\${data.minSize}px by \\${data.minSize}px). Is the neighbor a target?\",tooManyRects:\"Could not get the target size because there are too many overlapping elements\"}}},\"header-present\":{impact:\"serious\",messages:{pass:\"Page has a heading\",fail:\"Page does not have a heading\"}},\"heading-order\":{impact:\"moderate\",messages:{pass:\"Heading order valid\",fail:\"Heading order invalid\",incomplete:\"Unable to determine previous heading\"}},\"identical-links-same-purpose\":{impact:\"minor\",messages:{pass:\"There are no other links with the same name, that go to a different URL\",incomplete:\"Check that links have the same purpose, o\\\nr are intentionally ambiguous.\"}},\"internal-link-present\":{impact:\"serious\",messages:{pass:\"Valid skip link found\",fail:\"No valid skip link found\"}},landmark:{impact:\"serious\",messages:{pass:\"Page has a landmark region\",fail:\"Page does not have a landmark region\"}},\"meta-refresh-no-exceptions\":{impact:\"minor\",messages:{pass:\"<meta> tag does not immediately refresh the page\",fail:\"<meta> tag forces timed refresh of page\"}},\"meta-refresh\":{impact:\"critical\",messages:{pass:\"<meta> tag does not immediately refresh the page\",fail:\"<meta> tag forces timed refresh of page (less than 20 hours)\"}},\"p-as-heading\":{impact:\"serious\",messages:{pass:\"<p> elements are not styled as headings\",fail:\"Heading elements should be used instead of styled <p> elements\",incomplete:\"Unable to determine if <p> elements are styled as headings\"}},region:{impact:\"moderate\",messages:{pass:\"All page content is contained by landmarks\",fail:\"Some page content is not contained by landmarks\"}},\"skip-link\":{impact:\"modera\\\nte\",messages:{pass:\"Skip link target exists\",incomplete:\"Skip link target should become visible on activation\",fail:\"No skip link target\"}},\"unique-frame-title\":{impact:\"serious\",messages:{pass:\"Element's title attribute is unique\",fail:\"Element's title attribute is not unique\"}},\"duplicate-id-active\":{impact:\"serious\",messages:{pass:\"Document has no active elements that share the same id attribute\",fail:\"Document has active elements with the same id attribute: \\${data}\"}},\"duplicate-id-aria\":{impact:\"critical\",messages:{pass:\"Document has no elements referenced with ARIA or labels that share the same id attribute\",fail:\"Document has multiple elements referenced with ARIA with the same id attribute: \\${data}\"}},\"duplicate-id\":{impact:\"minor\",messages:{pass:\"Document has no static elements that share the same id attribute\",fail:\"Document has multiple static elements with the same id attribute: \\${data}\"}},\"aria-label\":{impact:\"serious\",messages:{pass:\"aria-label attribute exists and is not\\\n empty\",fail:\"aria-label attribute does not exist or is empty\"}},\"aria-labelledby\":{impact:\"serious\",messages:{pass:\"aria-labelledby attribute exists and references elements that are visible to screen readers\",fail:\"aria-labelledby attribute does not exist, references elements that do not exist or references elements that are empty\",incomplete:\"Ensure aria-labelledby references an existing element\"}},\"avoid-inline-spacing\":{impact:\"serious\",messages:{pass:\"No inline styles with '!important' that affect text spacing has been specified\",fail:{singular:\"Remove '!important' from inline style \\${data.values}, as overriding this is not supported by most browsers\",plural:\"Remove '!important' from inline styles \\${data.values}, as overriding this is not supported by most browsers\"}}},\"button-has-visible-text\":{impact:\"critical\",messages:{pass:\"Element has inner text that is visible to screen readers\",fail:\"Element does not have inner text that is visible to screen readers\",incomplete:\"Unable to \\\ndetermine if element has children\"}},\"doc-has-title\":{impact:\"serious\",messages:{pass:\"Document has a non-empty <title> element\",fail:\"Document does not have a non-empty <title> element\"}},\"error-occurred\":{messages:{pass:\"\",incomplete:\"Axe encountered an error; test the page for this type of problem manually\"}},exists:{impact:\"minor\",messages:{pass:\"Element does not exist\",incomplete:\"Element exists\"}},\"has-alt\":{impact:\"critical\",messages:{pass:\"Element has an alt attribute\",fail:\"Element does not have an alt attribute\"}},\"has-visible-text\":{impact:\"minor\",messages:{pass:\"Element has text that is visible to screen readers\",fail:\"Element does not have text that is visible to screen readers\",incomplete:\"Unable to determine if element has children\"}},\"important-letter-spacing\":{impact:\"serious\",messages:{pass:\"Letter-spacing in the style attribute is not set to !important, or meets the minimum\",fail:\"letter-spacing in the style attribute must not use !important, or be at \\${data.minValue\\\n}em (current \\${data.value}em)\"}},\"important-line-height\":{impact:\"serious\",messages:{pass:\"line-height in the style attribute is not set to !important, or meets the minimum\",fail:\"line-height in the style attribute must not use !important, or be at \\${data.minValue}em (current \\${data.value}em)\"}},\"important-word-spacing\":{impact:\"serious\",messages:{pass:\"word-spacing in the style attribute is not set to !important, or meets the minimum\",fail:\"word-spacing in the style attribute must not use !important, or be at \\${data.minValue}em (current \\${data.value}em)\"}},\"is-on-screen\":{impact:\"serious\",messages:{pass:\"Element is not visible\",fail:\"Element is visible\"}},\"non-empty-alt\":{impact:\"critical\",messages:{pass:\"Element has a non-empty alt attribute\",fail:{noAttr:\"Element has no alt attribute\",emptyAttr:\"Element has an empty alt attribute\"}}},\"non-empty-if-present\":{impact:\"critical\",messages:{pass:{default:\"Element does not have a value attribute\",\"has-label\":\"Element has a non-empty value \\\nattribute\"},fail:\"Element has a value attribute and the value attribute is empty\"}},\"non-empty-placeholder\":{impact:\"serious\",messages:{pass:\"Element has a placeholder attribute\",fail:{noAttr:\"Element has no placeholder attribute\",emptyAttr:\"Element has an empty placeholder attribute\"}}},\"non-empty-title\":{impact:\"serious\",messages:{pass:\"Element has a title attribute\",fail:{noAttr:\"Element has no title attribute\",emptyAttr:\"Element has an empty title attribute\"}}},\"non-empty-value\":{impact:\"critical\",messages:{pass:\"Element has a non-empty value attribute\",fail:{noAttr:\"Element has no value attribute\",emptyAttr:\"Element has an empty value attribute\"}}},\"presentational-role\":{impact:\"minor\",messages:{pass:'Element\\\\'s default semantics were overridden with role=\"\\${data.role}\"',fail:{default:'Element\\\\'s default semantics were not overridden with role=\"none\" or role=\"presentation\"',globalAria:\"Element's role is not presentational because it has a global ARIA attribute\",focusable:\"Element'\\\ns role is not presentational because it is focusable\",both:\"Element's role is not presentational because it has a global ARIA attribute and is focusable\",iframe:'Using the \"title\" attribute on an \\${data.nodeName} element with a presentational role behaves inconsistently between screen readers'}}},\"role-none\":{impact:\"minor\",messages:{pass:'Element\\\\'s default semantics were overridden with role=\"none\"',fail:'Element\\\\'s default semantics were not overridden with role=\"none\"'}},\"role-presentation\":{impact:\"minor\",messages:{pass:'Element\\\\'s default semantics were overridden with role=\"presentation\"',fail:'Element\\\\'s default semantics were not overridden with role=\"presentation\"'}},\"svg-non-empty-title\":{impact:\"serious\",messages:{pass:\"Element has a child that is a title\",fail:{noTitle:\"Element has no child that is a title\",emptyTitle:\"Element child title is empty\"},incomplete:\"Unable to determine element has a child that is a title\"}},\"caption-faked\":{impact:\"serious\",messages:{pass:\"The \\\nfirst row of a table is not used as a caption\",fail:\"The first child of the table should be a caption instead of a table cell\"}},\"html5-scope\":{impact:\"moderate\",messages:{pass:\"Scope attribute is only used on table header elements (<th>)\",fail:\"In HTML 5, scope attributes may only be used on table header elements (<th>)\"}},\"same-caption-summary\":{impact:\"minor\",messages:{pass:\"Content of summary attribute and <caption> are not duplicated\",fail:\"Content of summary attribute and <caption> element are identical\",incomplete:\"Unable to determine if <table> element has a caption\"}},\"scope-value\":{impact:\"critical\",messages:{pass:\"Scope attribute is used correctly\",fail:\"The value of the scope attribute may only be 'row' or 'col'\"}},\"td-has-header\":{impact:\"critical\",messages:{pass:\"All non-empty data cells have table headers\",fail:\"Some non-empty data cells do not have table headers\"}},\"td-headers-attr\":{impact:\"serious\",messages:{pass:\"The headers attribute is exclusively used to refer to \\\nother header cells in the table\",incomplete:\"The headers attribute is empty\",fail:{\"cell-header-not-in-table\":\"The headers attribute is not exclusively used to refer to other header cells in the table\",\"cell-header-not-th\":\"The headers attribute must refer to header cells, not data cells\",\"header-refs-self\":\"The element with headers attribute refers to itself\"}}},\"th-has-data-cells\":{impact:\"serious\",messages:{pass:\"All table header cells refer to data cells\",fail:\"Not all table header cells refer to data cells\",incomplete:\"Table data cells are missing or empty\"}},\"hidden-content\":{impact:\"minor\",messages:{pass:\"All content on the page has been analyzed.\",fail:\"There were problems analyzing the content on this page.\",incomplete:\"There is hidden content on the page that was not analyzed. You will need to trigger the display of this content in order to analyze it.\"}}},failureSummaries:{any:{failureMessage:function(e){var t=\"Fix any of the following:\",n=e;if(n)for(var r=-1,a=n.length-1;r<\\\na;)t+=\"\\\\n  \"+n[r+=1].split(\"\\\\n\").join(\"\\\\n  \");return t}},none:{failureMessage:function(e){var t=\"Fix all of the following:\",n=e;if(n)for(var r=-1,a=n.length-1;r<a;)t+=\"\\\\n  \"+n[r+=1].split(\"\\\\n\").join(\"\\\\n  \");return t}}},incompleteFallbackMessage:\"axe couldn't tell the reason. Time to break out the element inspector!\"},rules:[{id:\"accesskeys\",impact:\"serious\",selector:\"[accesskey]\",excludeHidden:!1,tags:[\"cat.keyboard\",\"best-practice\"],all:[],any:[],none:[\"accesskeys\"]},{id:\"area-alt\",impact:\"critical\",selector:\"map area[href]\",excludeHidden:!1,tags:[\"cat.text-alternatives\",\"wcag2a\",\"wcag244\",\"wcag412\",\"section508\",\"section508.22.a\",\"TTv5\",\"TT6.a\",\"EN-301-549\",\"EN-9.2.4.4\",\"EN-9.4.1.2\",\"ACT\",\"RGAAv4\",\"RGAA-1.1.2\"],actIds:[\"c487ae\"],all:[],any:[{options:{attribute:\"alt\"},id:\"non-empty-alt\"},\"aria-label\",\"aria-labelledby\",{options:{attribute:\"title\"},id:\"non-empty-title\"}],none:[]},{id:\"aria-allowed-attr\",impact:\"critical\",matches:\"aria-allowed-attr-matches\",tags:[\"cat.aria\",\"wcag2a\",\"wcag\\\n412\",\"EN-301-549\",\"EN-9.4.1.2\",\"RGAAv4\",\"RGAA-7.1.1\"],actIds:[\"5c01ea\"],all:[{options:{validTreeRowAttrs:[\"aria-posinset\",\"aria-setsize\",\"aria-expanded\",\"aria-level\"]},id:\"aria-allowed-attr\"}],any:[],none:[\"aria-unsupported-attr\"]},{id:\"aria-allowed-role\",impact:\"minor\",excludeHidden:!1,selector:\"[role]\",matches:\"aria-allowed-role-matches\",tags:[\"cat.aria\",\"best-practice\"],all:[],any:[{options:{allowImplicit:!0,ignoredTags:[]},id:\"aria-allowed-role\"}],none:[]},{id:\"aria-braille-equivalent\",reviewOnFail:!0,impact:\"serious\",selector:\"[aria-brailleroledescription], [aria-braillelabel]\",tags:[\"cat.aria\",\"wcag2a\",\"wcag412\",\"EN-301-549\",\"EN-9.4.1.2\"],all:[\"braille-roledescription-equivalent\",\"braille-label-equivalent\"],any:[],none:[]},{id:\"aria-command-name\",impact:\"serious\",selector:'[role=\"link\"], [role=\"button\"], [role=\"menuitem\"]',matches:\"no-naming-method-matches\",tags:[\"cat.aria\",\"wcag2a\",\"wcag412\",\"TTv5\",\"TT6.a\",\"EN-301-549\",\"EN-9.4.1.2\",\"ACT\",\"RGAAv4\",\"RGAA-11.9.1\"],actIds:[\"97a4e1\"]\\\n,all:[],any:[\"has-visible-text\",\"aria-label\",\"aria-labelledby\",{options:{attribute:\"title\"},id:\"non-empty-title\"}],none:[]},{id:\"aria-conditional-attr\",impact:\"serious\",matches:\"aria-allowed-attr-matches\",tags:[\"cat.aria\",\"wcag2a\",\"wcag412\",\"EN-301-549\",\"EN-9.4.1.2\",\"RGAAv4\",\"RGAA-7.1.1\"],actIds:[\"5c01ea\"],all:[{options:{invalidTableRowAttrs:[\"aria-posinset\",\"aria-setsize\",\"aria-expanded\",\"aria-level\"]},id:\"aria-conditional-attr\"}],any:[],none:[]},{id:\"aria-deprecated-role\",impact:\"minor\",selector:\"[role]\",matches:\"no-empty-role-matches\",tags:[\"cat.aria\",\"wcag2a\",\"wcag412\",\"EN-301-549\",\"EN-9.4.1.2\",\"RGAAv4\",\"RGAA-7.1.1\"],actIds:[\"674b10\"],all:[],any:[],none:[\"deprecatedrole\"]},{id:\"aria-dialog-name\",impact:\"serious\",selector:'[role=\"dialog\"], [role=\"alertdialog\"]',matches:\"no-naming-method-matches\",tags:[\"cat.aria\",\"best-practice\"],all:[],any:[\"aria-label\",\"aria-labelledby\",{options:{attribute:\"title\"},id:\"non-empty-title\"}],none:[]},{id:\"aria-hidden-body\",impact:\"critical\",selector:\"b\\\nody\",excludeHidden:!1,matches:\"is-initiator-matches\",tags:[\"cat.aria\",\"wcag2a\",\"wcag131\",\"wcag412\",\"EN-301-549\",\"EN-9.1.3.1\",\"EN-9.4.1.2\",\"RGAAv4\",\"RGAA-7.1.1\"],all:[],any:[\"aria-hidden-body\"],none:[]},{id:\"aria-hidden-focus\",impact:\"serious\",selector:'[aria-hidden=\"true\"]',matches:\"aria-hidden-focus-matches\",excludeHidden:!1,tags:[\"cat.name-role-value\",\"wcag2a\",\"wcag412\",\"TTv5\",\"TT6.a\",\"EN-301-549\",\"EN-9.4.1.2\",\"RGAAv4\",\"RGAA-7.1.1\"],actIds:[\"6cfa84\"],all:[\"focusable-modal-open\",\"focusable-disabled\",\"focusable-not-tabbable\"],any:[],none:[]},{id:\"aria-input-field-name\",impact:\"serious\",selector:'[role=\"combobox\"], [role=\"listbox\"], [role=\"searchbox\"], [role=\"slider\"], [role=\"spinbutton\"], [role=\"textbox\"]',matches:\"no-naming-method-matches\",tags:[\"cat.aria\",\"wcag2a\",\"wcag412\",\"TTv5\",\"TT5.c\",\"EN-301-549\",\"EN-9.4.1.2\",\"ACT\",\"RGAAv4\",\"RGAA-11.1.1\"],actIds:[\"e086e5\"],all:[],any:[\"aria-label\",\"aria-labelledby\",{options:{attribute:\"title\"},id:\"non-empty-title\"}],none:[\"no-implicit-explicit-l\\\nabel\"]},{id:\"aria-meter-name\",impact:\"serious\",selector:'[role=\"meter\"]',matches:\"no-naming-method-matches\",tags:[\"cat.aria\",\"wcag2a\",\"wcag111\",\"EN-301-549\",\"EN-9.1.1.1\",\"RGAAv4\",\"RGAA-11.1.1\"],all:[],any:[\"aria-label\",\"aria-labelledby\",{options:{attribute:\"title\"},id:\"non-empty-title\"}],none:[]},{id:\"aria-progressbar-name\",impact:\"serious\",selector:'[role=\"progressbar\"]',matches:\"no-naming-method-matches\",tags:[\"cat.aria\",\"wcag2a\",\"wcag111\",\"EN-301-549\",\"EN-9.1.1.1\",\"RGAAv4\",\"RGAA-11.1.1\"],all:[],any:[\"aria-label\",\"aria-labelledby\",{options:{attribute:\"title\"},id:\"non-empty-title\"}],none:[]},{id:\"aria-prohibited-attr\",impact:\"serious\",matches:\"aria-allowed-attr-matches\",tags:[\"cat.aria\",\"wcag2a\",\"wcag412\",\"EN-301-549\",\"EN-9.4.1.2\",\"RGAAv4\",\"RGAA-7.1.1\"],actIds:[\"5c01ea\"],all:[],any:[],none:[{options:{elementsAllowedAriaLabel:[\"applet\",\"input\"]},id:\"aria-prohibited-attr\"}]},{id:\"aria-required-attr\",impact:\"critical\",selector:\"[role]\",tags:[\"cat.aria\",\"wcag2a\",\"wcag412\",\"EN-301-549\",\"EN\\\n-9.4.1.2\",\"RGAAv4\",\"RGAA-7.1.1\"],actIds:[\"4e8ab6\"],all:[],any:[\"aria-required-attr\"],none:[]},{id:\"aria-required-children\",impact:\"critical\",selector:\"[role]\",matches:\"aria-required-children-matches\",tags:[\"cat.aria\",\"wcag2a\",\"wcag131\",\"EN-301-549\",\"EN-9.1.3.1\",\"RGAAv4\",\"RGAA-9.3.1\"],actIds:[\"bc4a75\",\"ff89c9\"],all:[],any:[{options:{reviewEmpty:[\"doc-bibliography\",\"doc-endnotes\",\"grid\",\"list\",\"listbox\",\"menu\",\"menubar\",\"table\",\"tablist\",\"tree\",\"treegrid\",\"rowgroup\"]},id:\"aria-required-children\"}],none:[]},{id:\"aria-required-parent\",impact:\"critical\",selector:\"[role]\",matches:\"aria-required-parent-matches\",tags:[\"cat.aria\",\"wcag2a\",\"wcag131\",\"EN-301-549\",\"EN-9.1.3.1\",\"RGAAv4\",\"RGAA-9.3.1\"],actIds:[\"ff89c9\"],all:[],any:[{options:{ownGroupRoles:[\"listitem\",\"treeitem\"]},id:\"aria-required-parent\"}],none:[]},{id:\"aria-roledescription\",impact:\"serious\",selector:\"[aria-roledescription]\",tags:[\"cat.aria\",\"wcag2a\",\"wcag412\",\"EN-301-549\",\"EN-9.4.1.2\",\"deprecated\"],enabled:!1,all:[],any:[{options:{\\\nsupportedRoles:[\"button\",\"img\",\"checkbox\",\"radio\",\"combobox\",\"menuitemcheckbox\",\"menuitemradio\"]},id:\"aria-roledescription\"}],none:[]},{id:\"aria-roles\",impact:\"critical\",selector:\"[role]\",matches:\"no-empty-role-matches\",tags:[\"cat.aria\",\"wcag2a\",\"wcag412\",\"EN-301-549\",\"EN-9.4.1.2\",\"RGAAv4\",\"RGAA-7.1.1\"],actIds:[\"674b10\"],all:[],any:[],none:[\"invalidrole\",\"abstractrole\",\"unsupportedrole\"]},{id:\"aria-text\",impact:\"serious\",selector:\"[role=text]\",tags:[\"cat.aria\",\"best-practice\"],all:[],any:[\"no-focusable-content\"],none:[]},{id:\"aria-toggle-field-name\",impact:\"serious\",selector:'[role=\"checkbox\"], [role=\"menuitemcheckbox\"], [role=\"menuitemradio\"], [role=\"radio\"], [role=\"switch\"], [role=\"option\"]',matches:\"no-naming-method-matches\",tags:[\"cat.aria\",\"wcag2a\",\"wcag412\",\"TTv5\",\"TT5.c\",\"EN-301-549\",\"EN-9.4.1.2\",\"ACT\",\"RGAAv4\",\"RGAA-7.1.1\"],actIds:[\"e086e5\"],all:[],any:[\"has-visible-text\",\"aria-label\",\"aria-labelledby\",{options:{attribute:\"title\"},id:\"non-empty-title\"}],none:[\"no-implicit-expli\\\ncit-label\"]},{id:\"aria-tooltip-name\",impact:\"serious\",selector:'[role=\"tooltip\"]',matches:\"no-naming-method-matches\",tags:[\"cat.aria\",\"wcag2a\",\"wcag412\",\"EN-301-549\",\"EN-9.4.1.2\"],all:[],any:[\"has-visible-text\",\"aria-label\",\"aria-labelledby\",{options:{attribute:\"title\"},id:\"non-empty-title\"}],none:[]},{id:\"aria-treeitem-name\",impact:\"serious\",selector:'[role=\"treeitem\"]',matches:\"no-naming-method-matches\",tags:[\"cat.aria\",\"best-practice\"],all:[],any:[\"has-visible-text\",\"aria-label\",\"aria-labelledby\",{options:{attribute:\"title\"},id:\"non-empty-title\"}],none:[]},{id:\"aria-valid-attr-value\",impact:\"critical\",matches:\"aria-has-attr-matches\",tags:[\"cat.aria\",\"wcag2a\",\"wcag412\",\"EN-301-549\",\"EN-9.4.1.2\",\"RGAAv4\",\"RGAA-7.1.1\"],actIds:[\"6a7281\"],all:[{options:[],id:\"aria-valid-attr-value\"},\"aria-errormessage\",\"aria-level\"],any:[],none:[]},{id:\"aria-valid-attr\",impact:\"critical\",matches:\"aria-has-attr-matches\",tags:[\"cat.aria\",\"wcag2a\",\"wcag412\",\"EN-301-549\",\"EN-9.4.1.2\",\"RGAAv4\",\"RGAA-7.1.1\"],a\\\nctIds:[\"5f99a7\"],all:[],any:[{options:[],id:\"aria-valid-attr\"}],none:[]},{id:\"audio-caption\",impact:\"critical\",selector:\"audio\",enabled:!1,excludeHidden:!1,tags:[\"cat.time-and-media\",\"wcag2a\",\"wcag121\",\"EN-301-549\",\"EN-9.1.2.1\",\"section508\",\"section508.22.a\",\"deprecated\"],actIds:[\"2eb176\",\"afb423\"],all:[],any:[],none:[\"caption\"]},{id:\"autocomplete-valid\",impact:\"serious\",matches:\"autocomplete-matches\",tags:[\"cat.forms\",\"wcag21aa\",\"wcag135\",\"EN-301-549\",\"EN-9.1.3.5\",\"ACT\",\"RGAAv4\",\"RGAA-11.13.1\"],actIds:[\"73f2c2\"],all:[{options:{stateTerms:[\"none\",\"false\",\"true\",\"disabled\",\"enabled\",\"undefined\",\"null\",\"xoff\",\"xon\"],ignoredValues:[\"text\",\"pronouns\",\"gender\",\"message\",\"content\"]},id:\"autocomplete-valid\"}],any:[],none:[]},{id:\"avoid-inline-spacing\",impact:\"serious\",selector:\"[style]\",matches:\"is-visible-on-screen-matches\",tags:[\"cat.structure\",\"wcag21aa\",\"wcag1412\",\"EN-301-549\",\"EN-9.1.4.12\",\"ACT\"],actIds:[\"24afc2\",\"9e45ec\",\"78fd32\"],all:[{options:{cssProperty:\"letter-spacing\",minValue:.12\\\n},id:\"important-letter-spacing\"},{options:{cssProperty:\"word-spacing\",minValue:.16},id:\"important-word-spacing\"},{options:{multiLineOnly:!0,cssProperty:\"line-height\",minValue:1.5,normalValue:1},id:\"important-line-height\"}],any:[],none:[]},{id:\"blink\",impact:\"serious\",selector:\"blink\",excludeHidden:!1,tags:[\"cat.time-and-media\",\"wcag2a\",\"wcag222\",\"section508\",\"section508.22.j\",\"TTv5\",\"TT2.b\",\"EN-301-549\",\"EN-9.2.2.2\",\"RGAAv4\",\"RGAA-13.8.1\"],all:[],any:[],none:[\"is-on-screen\"]},{id:\"button-name\",impact:\"critical\",selector:\"button\",matches:\"no-explicit-name-required-matches\",tags:[\"cat.name-role-value\",\"wcag2a\",\"wcag412\",\"section508\",\"section508.22.a\",\"TTv5\",\"TT6.a\",\"EN-301-549\",\"EN-9.4.1.2\",\"ACT\",\"RGAAv4\",\"RGAA-11.9.1\"],actIds:[\"97a4e1\",\"m6b1q3\"],all:[],any:[\"button-has-visible-text\",\"aria-label\",\"aria-labelledby\",{options:{attribute:\"title\"},id:\"non-empty-title\"},\"implicit-label\",\"explicit-label\",\"presentational-role\"],none:[]},{id:\"bypass\",impact:\"serious\",selector:\"html\",pageLevel:!0,\\\nmatches:\"bypass-matches\",reviewOnFail:!0,tags:[\"cat.keyboard\",\"wcag2a\",\"wcag241\",\"section508\",\"section508.22.o\",\"TTv5\",\"TT9.a\",\"EN-301-549\",\"EN-9.2.4.1\",\"RGAAv4\",\"RGAA-12.7.1\"],actIds:[\"cf77f2\",\"047fe0\",\"b40fd1\",\"3e12e1\",\"ye5d6e\"],all:[],any:[\"internal-link-present\",{options:{selector:\":is(h1, h2, h3, h4, h5, h6):not([role]), [role=heading]\"},id:\"header-present\"},{options:{selector:\"main, [role=main]\"},id:\"landmark\"}],none:[]},{id:\"color-contrast-enhanced\",impact:\"serious\",matches:\"color-contrast-matches\",excludeHidden:!1,enabled:!1,tags:[\"cat.color\",\"wcag2aaa\",\"wcag146\",\"ACT\"],actIds:[\"09o5cg\"],all:[],any:[{options:{ignoreUnicode:!0,ignoreLength:!1,ignorePseudo:!1,boldValue:700,boldTextPt:14,largeTextPt:18,contrastRatio:{normal:{expected:7,minThreshold:4.5},large:{expected:4.5,minThreshold:3}},pseudoSizeThreshold:.25,shadowOutlineEmMax:.1,textStrokeEmMin:.03},id:\"color-contrast-enhanced\"}],none:[]},{id:\"color-contrast\",impact:\"serious\",matches:\"color-contrast-matches\",excludeHidden:!1\\\n,tags:[\"cat.color\",\"wcag2aa\",\"wcag143\",\"TTv5\",\"TT13.c\",\"EN-301-549\",\"EN-9.1.4.3\",\"ACT\",\"RGAAv4\",\"RGAA-3.2.1\"],actIds:[\"afw4f7\",\"09o5cg\"],all:[],any:[{options:{ignoreUnicode:!0,ignoreLength:!1,ignorePseudo:!1,boldValue:700,boldTextPt:14,largeTextPt:18,contrastRatio:{normal:{expected:4.5},large:{expected:3}},pseudoSizeThreshold:.25,shadowOutlineEmMax:.2,textStrokeEmMin:.03},id:\"color-contrast\"}],none:[]},{id:\"css-orientation-lock\",impact:\"serious\",selector:\"html\",tags:[\"cat.structure\",\"wcag134\",\"wcag21aa\",\"EN-301-549\",\"EN-9.1.3.4\",\"RGAAv4\",\"RGAA-13.9.1\",\"experimental\"],actIds:[\"b33eff\"],all:[{options:{degreeThreshold:2},id:\"css-orientation-lock\"}],any:[],none:[],preload:!0},{id:\"definition-list\",impact:\"serious\",selector:\"dl\",matches:\"no-role-matches\",tags:[\"cat.structure\",\"wcag2a\",\"wcag131\",\"EN-301-549\",\"EN-9.1.3.1\",\"RGAAv4\",\"RGAA-9.3.3\"],all:[],any:[],none:[\"structured-dlitems\",{options:{validRoles:[\"definition\",\"term\",\"listitem\"],validNodeNames:[\"dt\",\"dd\"],divGroups:!0},id:\"only-dlite\\\nms\"}]},{id:\"dlitem\",impact:\"serious\",selector:\"dd, dt\",matches:\"no-role-matches\",tags:[\"cat.structure\",\"wcag2a\",\"wcag131\",\"EN-301-549\",\"EN-9.1.3.1\",\"RGAAv4\",\"RGAA-9.3.3\"],all:[],any:[\"dlitem\"],none:[]},{id:\"document-title\",impact:\"serious\",selector:\"html\",matches:\"is-initiator-matches\",tags:[\"cat.text-alternatives\",\"wcag2a\",\"wcag242\",\"TTv5\",\"TT12.a\",\"EN-301-549\",\"EN-9.2.4.2\",\"ACT\",\"RGAAv4\",\"RGAA-8.5.1\"],actIds:[\"2779a5\"],all:[],any:[\"doc-has-title\"],none:[]},{id:\"duplicate-id-active\",impact:\"serious\",selector:\"[id]\",matches:\"duplicate-id-active-matches\",excludeHidden:!1,tags:[\"cat.parsing\",\"wcag2a-obsolete\",\"wcag411\",\"deprecated\"],enabled:!1,actIds:[\"3ea0c8\"],all:[],any:[\"duplicate-id-active\"],none:[]},{id:\"duplicate-id-aria\",impact:\"critical\",selector:\"[id]\",matches:\"duplicate-id-aria-matches\",excludeHidden:!1,tags:[\"cat.parsing\",\"wcag2a\",\"wcag412\",\"EN-301-549\",\"EN-9.4.1.2\",\"RGAAv4\",\"RGAA-8.2.1\"],reviewOnFail:!0,actIds:[\"3ea0c8\"],all:[],any:[\"duplicate-id-aria\"],none:[]},{id:\"duplicat\\\ne-id\",impact:\"minor\",selector:\"[id]\",matches:\"duplicate-id-misc-matches\",excludeHidden:!1,tags:[\"cat.parsing\",\"wcag2a-obsolete\",\"wcag411\",\"deprecated\"],enabled:!1,actIds:[\"3ea0c8\"],all:[],any:[\"duplicate-id\"],none:[]},{id:\"empty-heading\",impact:\"minor\",selector:'h1, h2, h3, h4, h5, h6, [role=\"heading\"]',matches:\"heading-matches\",tags:[\"cat.name-role-value\",\"best-practice\"],actIds:[\"ffd0e9\"],all:[],any:[\"has-visible-text\",\"aria-label\",\"aria-labelledby\",{options:{attribute:\"title\"},id:\"non-empty-title\"}],none:[]},{id:\"empty-table-header\",impact:\"minor\",selector:'th:not([role]), [role=\"rowheader\"], [role=\"columnheader\"]',tags:[\"cat.name-role-value\",\"best-practice\"],all:[],any:[\"has-visible-text\"],none:[]},{id:\"focus-order-semantics\",impact:\"minor\",selector:\"div, h1, h2, h3, h4, h5, h6, [role=heading], p, span\",matches:\"inserted-into-focus-order-matches\",tags:[\"cat.keyboard\",\"best-practice\",\"RGAAv4\",\"RGAA-12.8.1\",\"experimental\"],all:[],any:[{options:[],id:\"has-widget-role\"},{options:{roles\\\n:[\"tooltip\"]},id:\"valid-scrollable-semantics\"}],none:[]},{id:\"form-field-multiple-labels\",impact:\"moderate\",selector:\"input, select, textarea\",matches:\"label-matches\",tags:[\"cat.forms\",\"wcag2a\",\"wcag332\",\"TTv5\",\"TT5.c\",\"EN-301-549\",\"EN-9.3.3.2\",\"RGAAv4\",\"RGAA-11.2.1\"],all:[],any:[],none:[\"multiple-label\"]},{id:\"frame-focusable-content\",impact:\"serious\",selector:\"html\",matches:\"frame-focusable-content-matches\",tags:[\"cat.keyboard\",\"wcag2a\",\"wcag211\",\"TTv5\",\"TT4.a\",\"EN-301-549\",\"EN-9.2.1.1\",\"RGAAv4\",\"RGAA-7.3.2\"],actIds:[\"akn7bn\"],all:[],any:[\"frame-focusable-content\"],none:[]},{id:\"frame-tested\",impact:\"critical\",selector:\"html, frame, iframe\",tags:[\"cat.structure\",\"best-practice\",\"review-item\"],all:[{options:{isViolation:!1},id:\"frame-tested\"}],any:[],none:[]},{id:\"frame-title-unique\",impact:\"serious\",selector:\"frame[title], iframe[title]\",matches:\"frame-title-has-text-matches\",tags:[\"cat.text-alternatives\",\"wcag2a\",\"wcag412\",\"TTv5\",\"TT12.d\",\"EN-301-549\",\"EN-9.4.1.2\",\"RGAAv4\",\"RGAA-2.2\\\n.1\"],actIds:[\"4b1c6c\"],all:[],any:[],none:[\"unique-frame-title\"],reviewOnFail:!0},{id:\"frame-title\",impact:\"serious\",selector:\"frame, iframe\",matches:\"no-negative-tabindex-matches\",tags:[\"cat.text-alternatives\",\"wcag2a\",\"wcag412\",\"section508\",\"section508.22.i\",\"TTv5\",\"TT12.d\",\"EN-301-549\",\"EN-9.4.1.2\",\"RGAAv4\",\"RGAA-2.1.1\"],actIds:[\"cae760\"],all:[],any:[{options:{attribute:\"title\"},id:\"non-empty-title\"},\"aria-label\",\"aria-labelledby\",\"presentational-role\"],none:[]},{id:\"heading-order\",impact:\"moderate\",selector:\"h1, h2, h3, h4, h5, h6, [role=heading]\",matches:\"heading-matches\",tags:[\"cat.semantics\",\"best-practice\"],all:[],any:[\"heading-order\"],none:[]},{id:\"hidden-content\",impact:\"minor\",selector:\"*\",excludeHidden:!1,tags:[\"cat.structure\",\"best-practice\",\"experimental\",\"review-item\"],all:[],any:[\"hidden-content\"],none:[]},{id:\"html-has-lang\",impact:\"serious\",selector:\"html\",matches:\"is-initiator-matches\",tags:[\"cat.language\",\"wcag2a\",\"wcag311\",\"TTv5\",\"TT11.a\",\"EN-301-549\",\"EN-9.3.1.1\",\\\n\"ACT\",\"RGAAv4\",\"RGAA-8.3.1\"],actIds:[\"b5c3f8\"],all:[],any:[{options:{attributes:[\"lang\",\"xml:lang\"]},id:\"has-lang\"}],none:[]},{id:\"html-lang-valid\",impact:\"serious\",selector:'html[lang]:not([lang=\"\"]), html[xml\\\\\\\\:lang]:not([xml\\\\\\\\:lang=\"\"])',tags:[\"cat.language\",\"wcag2a\",\"wcag311\",\"TTv5\",\"TT11.a\",\"EN-301-549\",\"EN-9.3.1.1\",\"ACT\",\"RGAAv4\",\"RGAA-8.4.1\"],actIds:[\"bf051a\"],all:[],any:[],none:[{options:{attributes:[\"lang\",\"xml:lang\"]},id:\"valid-lang\"}]},{id:\"html-xml-lang-mismatch\",impact:\"moderate\",selector:\"html[lang][xml\\\\\\\\:lang]\",matches:\"xml-lang-mismatch-matches\",tags:[\"cat.language\",\"wcag2a\",\"wcag311\",\"EN-301-549\",\"EN-9.3.1.1\",\"ACT\",\"RGAAv4\",\"RGAA-8.3.1\"],actIds:[\"5b7ae0\"],all:[\"xml-lang-mismatch\"],any:[],none:[]},{id:\"identical-links-same-purpose\",impact:\"minor\",selector:'a[href], area[href], [role=\"link\"]',excludeHidden:!1,enabled:!1,matches:\"identical-links-same-purpose-matches\",tags:[\"cat.semantics\",\"wcag2aaa\",\"wcag249\"],actIds:[\"b20e66\"],all:[\"identical-links-same-purpose\"],any:[],\\\nnone:[]},{id:\"image-alt\",impact:\"critical\",selector:\"img\",matches:\"no-explicit-name-required-matches\",tags:[\"cat.text-alternatives\",\"wcag2a\",\"wcag111\",\"section508\",\"section508.22.a\",\"TTv5\",\"TT7.a\",\"TT7.b\",\"EN-301-549\",\"EN-9.1.1.1\",\"ACT\",\"RGAAv4\",\"RGAA-1.1.1\"],actIds:[\"23a2a8\"],all:[],any:[\"has-alt\",\"aria-label\",\"aria-labelledby\",{options:{attribute:\"title\"},id:\"non-empty-title\"},\"presentational-role\"],none:[\"alt-space-value\"]},{id:\"image-redundant-alt\",impact:\"minor\",selector:\"img\",tags:[\"cat.text-alternatives\",\"best-practice\"],all:[],any:[],none:[{options:{parentSelector:\"button, [role=button], a[href], p, li, td, th\"},id:\"duplicate-img-label\"}]},{id:\"input-button-name\",impact:\"critical\",selector:'input[type=\"button\"], input[type=\"submit\"], input[type=\"reset\"]',matches:\"no-explicit-name-required-matches\",tags:[\"cat.name-role-value\",\"wcag2a\",\"wcag412\",\"section508\",\"section508.22.a\",\"TTv5\",\"TT5.c\",\"EN-301-549\",\"EN-9.4.1.2\",\"ACT\",\"RGAAv4\",\"RGAA-11.9.1\"],actIds:[\"97a4e1\"],all:[],any:[\"non\\\n-empty-if-present\",{options:{attribute:\"value\"},id:\"non-empty-value\"},\"aria-label\",\"aria-labelledby\",{options:{attribute:\"title\"},id:\"non-empty-title\"},\"implicit-label\",\"explicit-label\",\"presentational-role\"],none:[]},{id:\"input-image-alt\",impact:\"critical\",selector:'input[type=\"image\"]',matches:\"no-explicit-name-required-matches\",tags:[\"cat.text-alternatives\",\"wcag2a\",\"wcag111\",\"wcag412\",\"section508\",\"section508.22.a\",\"TTv5\",\"TT7.a\",\"EN-301-549\",\"EN-9.1.1.1\",\"EN-9.4.1.2\",\"ACT\",\"RGAAv4\",\"RGAA-1.1.3\"],actIds:[\"59796f\"],all:[],any:[{options:{attribute:\"alt\"},id:\"non-empty-alt\"},\"aria-label\",\"aria-labelledby\",{options:{attribute:\"title\"},id:\"non-empty-title\"},\"implicit-label\",\"explicit-label\"],none:[]},{id:\"label-content-name-mismatch\",impact:\"serious\",matches:\"label-content-name-mismatch-matches\",tags:[\"cat.semantics\",\"wcag21a\",\"wcag253\",\"EN-301-549\",\"EN-9.2.5.3\",\"RGAAv4\",\"RGAA-6.1.5\",\"experimental\"],actIds:[\"2ee8b8\"],all:[],any:[{options:{pixelThreshold:.1,occurrenceThreshold:3},id:\"lab\\\nel-content-name-mismatch\"}],none:[]},{id:\"label-title-only\",impact:\"serious\",selector:\"input, select, textarea\",matches:\"label-matches\",tags:[\"cat.forms\",\"best-practice\"],all:[],any:[],none:[\"title-only\"]},{id:\"label\",impact:\"critical\",selector:\"input, textarea\",matches:\"label-matches\",tags:[\"cat.forms\",\"wcag2a\",\"wcag412\",\"section508\",\"section508.22.n\",\"TTv5\",\"TT5.c\",\"EN-301-549\",\"EN-9.4.1.2\",\"ACT\",\"RGAAv4\",\"RGAA-11.1.1\"],actIds:[\"e086e5\"],all:[],any:[\"implicit-label\",\"explicit-label\",\"aria-label\",\"aria-labelledby\",{options:{attribute:\"title\"},id:\"non-empty-title\"},{options:{attribute:\"placeholder\"},id:\"non-empty-placeholder\"},\"presentational-role\"],none:[\"hidden-explicit-label\"]},{id:\"landmark-banner-is-top-level\",impact:\"moderate\",selector:\"header:not([role]), [role=banner]\",matches:\"landmark-has-body-context-matches\",tags:[\"cat.semantics\",\"best-practice\"],all:[],any:[\"landmark-is-top-level\"],none:[]},{id:\"landmark-complementary-is-top-level\",impact:\"moderate\",selector:\"aside:not([ro\\\nle]), [role=complementary]\",tags:[\"cat.semantics\",\"best-practice\"],all:[],any:[\"landmark-is-top-level\"],none:[]},{id:\"landmark-contentinfo-is-top-level\",impact:\"moderate\",selector:\"footer:not([role]), [role=contentinfo]\",matches:\"landmark-has-body-context-matches\",tags:[\"cat.semantics\",\"best-practice\"],all:[],any:[\"landmark-is-top-level\"],none:[]},{id:\"landmark-main-is-top-level\",impact:\"moderate\",selector:\"main:not([role]), [role=main]\",tags:[\"cat.semantics\",\"best-practice\"],all:[],any:[\"landmark-is-top-level\"],none:[]},{id:\"landmark-no-duplicate-banner\",impact:\"moderate\",selector:\"header:not([role]), [role=banner]\",tags:[\"cat.semantics\",\"best-practice\"],all:[],any:[{options:{selector:\"header:not([role]), [role=banner]\",role:\"banner\"},id:\"page-no-duplicate-banner\"}],none:[]},{id:\"landmark-no-duplicate-contentinfo\",impact:\"moderate\",selector:\"footer:not([role]), [role=contentinfo]\",tags:[\"cat.semantics\",\"best-practice\"],all:[],any:[{options:{selector:\"footer:not([role]), [role=contenti\\\nnfo]\",role:\"contentinfo\"},id:\"page-no-duplicate-contentinfo\"}],none:[]},{id:\"landmark-no-duplicate-main\",impact:\"moderate\",selector:\"main:not([role]), [role=main]\",tags:[\"cat.semantics\",\"best-practice\"],all:[],any:[{options:{selector:\"main:not([role]), [role='main']\"},id:\"page-no-duplicate-main\"}],none:[]},{id:\"landmark-one-main\",impact:\"moderate\",selector:\"html\",tags:[\"cat.semantics\",\"best-practice\"],all:[{options:{selector:\"main:not([role]), [role='main']\",passForModal:!0},id:\"page-has-main\"}],any:[],none:[]},{id:\"landmark-unique\",impact:\"moderate\",selector:\"[role=banner], [role=complementary], [role=contentinfo], [role=main], [role=navigation], [role=region], [role=search], [role=form], form, footer, header, aside, main, nav, section\",tags:[\"cat.semantics\",\"best-practice\"],matches:\"landmark-unique-matches\",all:[],any:[\"landmark-is-unique\"],none:[]},{id:\"link-in-text-block\",impact:\"serious\",selector:\"a[href], [role=link]\",matches:\"link-in-text-block-matches\",excludeHidden:!1,tags:[\"c\\\nat.color\",\"wcag2a\",\"wcag141\",\"TTv5\",\"TT13.a\",\"EN-301-549\",\"EN-9.1.4.1\",\"RGAAv4\",\"RGAA-10.6.1\"],all:[],any:[{options:{requiredContrastRatio:3,allowSameColor:!0},id:\"link-in-text-block\"},\"link-in-text-block-style\"],none:[]},{id:\"link-name\",impact:\"serious\",selector:\"a[href]\",tags:[\"cat.name-role-value\",\"wcag2a\",\"wcag244\",\"wcag412\",\"section508\",\"section508.22.a\",\"TTv5\",\"TT6.a\",\"EN-301-549\",\"EN-9.2.4.4\",\"EN-9.4.1.2\",\"ACT\",\"RGAAv4\",\"RGAA-6.2.1\"],actIds:[\"c487ae\"],all:[],any:[\"has-visible-text\",\"aria-label\",\"aria-labelledby\",{options:{attribute:\"title\"},id:\"non-empty-title\"}],none:[\"focusable-no-name\"]},{id:\"list\",impact:\"serious\",selector:\"ul, ol\",matches:\"no-role-matches\",tags:[\"cat.structure\",\"wcag2a\",\"wcag131\",\"EN-301-549\",\"EN-9.1.3.1\",\"RGAAv4\",\"RGAA-9.3.1\"],all:[],any:[],none:[{options:{validRoles:[\"listitem\"],validNodeNames:[\"li\"]},id:\"only-listitems\"}]},{id:\"listitem\",impact:\"serious\",selector:\"li\",matches:\"no-role-matches\",tags:[\"cat.structure\",\"wcag2a\",\"wcag131\",\"EN-301-549\",\"EN-9.1\\\n.3.1\",\"RGAAv4\",\"RGAA-9.3.1\"],all:[],any:[\"listitem\"],none:[]},{id:\"marquee\",impact:\"serious\",selector:\"marquee\",excludeHidden:!1,tags:[\"cat.parsing\",\"wcag2a\",\"wcag222\",\"TTv5\",\"TT2.b\",\"EN-301-549\",\"EN-9.2.2.2\",\"RGAAv4\",\"RGAA-13.8.1\"],all:[],any:[],none:[\"is-on-screen\"]},{id:\"meta-refresh-no-exceptions\",impact:\"minor\",selector:'meta[http-equiv=\"refresh\"][content]',excludeHidden:!1,enabled:!1,tags:[\"cat.time-and-media\",\"wcag2aaa\",\"wcag224\",\"wcag325\"],actIds:[\"bisz58\"],all:[],any:[{options:{minDelay:72e3,maxDelay:!1},id:\"meta-refresh-no-exceptions\"}],none:[]},{id:\"meta-refresh\",impact:\"critical\",selector:'meta[http-equiv=\"refresh\"][content]',excludeHidden:!1,tags:[\"cat.time-and-media\",\"wcag2a\",\"wcag221\",\"TTv5\",\"TT8.a\",\"EN-301-549\",\"EN-9.2.2.1\",\"RGAAv4\",\"RGAA-13.1.2\"],actIds:[\"bc659a\",\"bisz58\"],all:[],any:[{options:{minDelay:0,maxDelay:72e3},id:\"meta-refresh\"}],none:[]},{id:\"meta-viewport-large\",impact:\"minor\",selector:'meta[name=\"viewport\"]',matches:\"is-initiator-matches\",excludeHidden:!1,\\\ntags:[\"cat.sensory-and-visual-cues\",\"best-practice\"],all:[],any:[{options:{scaleMinimum:5,lowerBound:2},id:\"meta-viewport-large\"}],none:[]},{id:\"meta-viewport\",impact:\"moderate\",selector:'meta[name=\"viewport\"]',matches:\"is-initiator-matches\",excludeHidden:!1,tags:[\"cat.sensory-and-visual-cues\",\"wcag2aa\",\"wcag144\",\"EN-301-549\",\"EN-9.1.4.4\",\"ACT\",\"RGAAv4\",\"RGAA-10.4.2\"],actIds:[\"b4f0c3\"],all:[],any:[{options:{scaleMinimum:2},id:\"meta-viewport\"}],none:[]},{id:\"nested-interactive\",impact:\"serious\",matches:\"nested-interactive-matches\",tags:[\"cat.keyboard\",\"wcag2a\",\"wcag412\",\"TTv5\",\"TT6.a\",\"EN-301-549\",\"EN-9.4.1.2\",\"RGAAv4\",\"RGAA-7.1.1\"],actIds:[\"307n5z\"],all:[],any:[\"no-focusable-content\"],none:[]},{id:\"no-autoplay-audio\",impact:\"moderate\",excludeHidden:!1,selector:\"audio[autoplay], video[autoplay]\",matches:\"no-autoplay-audio-matches\",reviewOnFail:!0,tags:[\"cat.time-and-media\",\"wcag2a\",\"wcag142\",\"TTv5\",\"TT2.a\",\"EN-301-549\",\"EN-9.1.4.2\",\"ACT\",\"RGAAv4\",\"RGAA-4.10.1\"],actIds:[\"80f0bf\"],preload\\\n:!0,all:[{options:{allowedDuration:3},id:\"no-autoplay-audio\"}],any:[],none:[]},{id:\"object-alt\",impact:\"serious\",selector:\"object[data]\",matches:\"object-is-loaded-matches\",tags:[\"cat.text-alternatives\",\"wcag2a\",\"wcag111\",\"section508\",\"section508.22.a\",\"EN-301-549\",\"EN-9.1.1.1\",\"RGAAv4\",\"RGAA-1.1.6\"],actIds:[\"8fc3b6\"],all:[],any:[\"aria-label\",\"aria-labelledby\",{options:{attribute:\"title\"},id:\"non-empty-title\"},\"presentational-role\"],none:[]},{id:\"p-as-heading\",impact:\"serious\",selector:\"p\",matches:\"p-as-heading-matches\",tags:[\"cat.semantics\",\"wcag2a\",\"wcag131\",\"EN-301-549\",\"EN-9.1.3.1\",\"RGAAv4\",\"RGAA-9.1.3\",\"experimental\"],all:[{options:{margins:[{weight:150,italic:!0},{weight:150,size:1.15},{italic:!0,size:1.15},{size:1.4}],passLength:1,failLength:.5},id:\"p-as-heading\"}],any:[],none:[]},{id:\"page-has-heading-one\",impact:\"moderate\",selector:\"html\",tags:[\"cat.semantics\",\"best-practice\"],all:[{options:{selector:\"h1:not([role], [aria-level]), :is(h1, h2, h3, h4, h5, h6):not([role])[aria-le\\\nvel=1], [role=heading][aria-level=1]\",passForModal:!0},id:\"page-has-heading-one\"}],any:[],none:[]},{id:\"presentation-role-conflict\",impact:\"minor\",selector:'img[alt=\\\\'\\\\'], [role=\"none\"], [role=\"presentation\"]',matches:\"has-implicit-chromium-role-matches\",tags:[\"cat.aria\",\"best-practice\",\"ACT\"],actIds:[\"46ca7f\"],all:[],any:[],none:[\"is-element-focusable\",\"has-global-aria-attribute\"]},{id:\"region\",impact:\"moderate\",selector:\"body *\",tags:[\"cat.keyboard\",\"best-practice\",\"RGAAv4\",\"RGAA-9.2.1\"],all:[],any:[{options:{regionMatcher:\"dialog, [role=dialog], [role=alertdialog], svg\"},id:\"region\"}],none:[]},{id:\"role-img-alt\",impact:\"serious\",selector:\"[role='img']:not(img, area, input, object)\",matches:\"html-namespace-matches\",tags:[\"cat.text-alternatives\",\"wcag2a\",\"wcag111\",\"section508\",\"section508.22.a\",\"TTv5\",\"TT7.a\",\"EN-301-549\",\"EN-9.1.1.1\",\"ACT\",\"RGAAv4\",\"RGAA-1.1.1\"],actIds:[\"23a2a8\"],all:[],any:[\"aria-label\",\"aria-labelledby\",{options:{attribute:\"title\"},id:\"non-empty-title\"}],none:[]},{\\\nid:\"scope-attr-valid\",impact:\"moderate\",selector:\"td[scope], th[scope]\",tags:[\"cat.tables\",\"best-practice\"],all:[\"html5-scope\",{options:{values:[\"row\",\"col\",\"rowgroup\",\"colgroup\"]},id:\"scope-value\"}],any:[],none:[]},{id:\"scrollable-region-focusable\",impact:\"serious\",selector:\"*:not(select,textarea)\",matches:\"scrollable-region-focusable-matches\",tags:[\"cat.keyboard\",\"wcag2a\",\"wcag211\",\"wcag213\",\"TTv5\",\"TT4.a\",\"EN-301-549\",\"EN-9.2.1.1\",\"EN-9.2.1.3\",\"RGAAv4\",\"RGAA-7.3.2\"],actIds:[\"0ssw9k\"],all:[],any:[\"focusable-content\",\"focusable-element\"],none:[]},{id:\"select-name\",impact:\"critical\",selector:\"select\",tags:[\"cat.forms\",\"wcag2a\",\"wcag412\",\"section508\",\"section508.22.n\",\"TTv5\",\"TT5.c\",\"EN-301-549\",\"EN-9.4.1.2\",\"ACT\",\"RGAAv4\",\"RGAA-11.1.1\"],actIds:[\"e086e5\"],all:[],any:[\"implicit-label\",\"explicit-label\",\"aria-label\",\"aria-labelledby\",{options:{attribute:\"title\"},id:\"non-empty-title\"},\"presentational-role\"],none:[\"hidden-explicit-label\"]},{id:\"server-side-image-map\",impact:\"minor\",selector:\\\n\"img[ismap]\",tags:[\"cat.text-alternatives\",\"wcag2a\",\"wcag211\",\"section508\",\"section508.22.f\",\"TTv5\",\"TT4.a\",\"EN-301-549\",\"EN-9.2.1.1\",\"RGAAv4\",\"RGAA-1.1.4\"],all:[],any:[],none:[\"exists\"]},{id:\"skip-link\",impact:\"moderate\",selector:'a[href^=\"#\"], a[href^=\"/#\"]',matches:\"skip-link-matches\",tags:[\"cat.keyboard\",\"best-practice\",\"RGAAv4\",\"RGAA-12.7.1\"],all:[],any:[\"skip-link\"],none:[]},{id:\"summary-name\",impact:\"serious\",selector:\"summary\",matches:\"summary-interactive-matches\",tags:[\"cat.name-role-value\",\"wcag2a\",\"wcag412\",\"section508\",\"section508.22.a\",\"TTv5\",\"TT6.a\",\"EN-301-549\",\"EN-9.4.1.2\"],all:[],any:[\"has-visible-text\",\"aria-label\",\"aria-labelledby\",{options:{attribute:\"title\"},id:\"non-empty-title\"}],none:[]},{id:\"svg-img-alt\",impact:\"serious\",selector:'[role=\"img\"], [role=\"graphics-symbol\"], svg[role=\"graphics-document\"]',matches:\"svg-namespace-matches\",tags:[\"cat.text-alternatives\",\"wcag2a\",\"wcag111\",\"section508\",\"section508.22.a\",\"TTv5\",\"TT7.a\",\"EN-301-549\",\"EN-9.1.1.1\",\"ACT\",\"RGAA\\\nv4\",\"RGAA-1.1.5\"],actIds:[\"7d6734\"],all:[],any:[\"svg-non-empty-title\",\"aria-label\",\"aria-labelledby\",{options:{attribute:\"title\"},id:\"non-empty-title\"}],none:[]},{id:\"tabindex\",impact:\"serious\",selector:\"[tabindex]\",tags:[\"cat.keyboard\",\"best-practice\"],all:[],any:[\"tabindex\"],none:[]},{id:\"table-duplicate-name\",impact:\"minor\",selector:\"table\",tags:[\"cat.tables\",\"best-practice\",\"RGAAv4\",\"RGAA-5.2.1\"],all:[],any:[],none:[\"same-caption-summary\"]},{id:\"table-fake-caption\",impact:\"serious\",selector:\"table\",matches:\"data-table-matches\",tags:[\"cat.tables\",\"experimental\",\"wcag2a\",\"wcag131\",\"section508\",\"section508.22.g\",\"EN-301-549\",\"EN-9.1.3.1\",\"RGAAv4\",\"RGAA-5.4.1\"],all:[\"caption-faked\"],any:[],none:[]},{id:\"target-size\",impact:\"serious\",selector:\"*\",enabled:!1,matches:\"widget-not-inline-matches\",tags:[\"cat.sensory-and-visual-cues\",\"wcag22aa\",\"wcag258\"],all:[],any:[{options:{minSize:24},id:\"target-size\"},{options:{minOffset:24},id:\"target-offset\"}],none:[]},{id:\"td-has-header\",impact:\"criti\\\ncal\",selector:\"table\",matches:\"data-table-large-matches\",tags:[\"cat.tables\",\"experimental\",\"wcag2a\",\"wcag131\",\"section508\",\"section508.22.g\",\"TTv5\",\"TT14.b\",\"EN-301-549\",\"EN-9.1.3.1\",\"RGAAv4\",\"RGAA-5.7.4\"],all:[\"td-has-header\"],any:[],none:[]},{id:\"td-headers-attr\",impact:\"serious\",selector:\"table\",matches:\"table-or-grid-role-matches\",tags:[\"cat.tables\",\"wcag2a\",\"wcag131\",\"section508\",\"section508.22.g\",\"TTv5\",\"TT14.b\",\"EN-301-549\",\"EN-9.1.3.1\",\"RGAAv4\",\"RGAA-5.7.4\"],actIds:[\"a25f45\"],all:[\"td-headers-attr\"],any:[],none:[]},{id:\"th-has-data-cells\",impact:\"serious\",selector:\"table\",matches:\"data-table-matches\",tags:[\"cat.tables\",\"wcag2a\",\"wcag131\",\"section508\",\"section508.22.g\",\"TTv5\",\"TT14.b\",\"EN-301-549\",\"EN-9.1.3.1\",\"RGAAv4\",\"RGAA-5.7.1\"],actIds:[\"d0f69e\"],all:[\"th-has-data-cells\"],any:[],none:[]},{id:\"valid-lang\",impact:\"serious\",selector:\"[lang]:not(html), [xml\\\\\\\\:lang]:not(html)\",tags:[\"cat.language\",\"wcag2aa\",\"wcag312\",\"TTv5\",\"TT11.b\",\"EN-301-549\",\"EN-9.3.1.2\",\"ACT\",\"RGAAv4\",\"RGAA-\\\n8.7.1\"],actIds:[\"de46e4\"],all:[],any:[],none:[{options:{attributes:[\"lang\",\"xml:lang\"]},id:\"valid-lang\"}]},{id:\"video-caption\",impact:\"critical\",selector:\"video\",tags:[\"cat.text-alternatives\",\"wcag2a\",\"wcag122\",\"section508\",\"section508.22.a\",\"TTv5\",\"TT17.a\",\"EN-301-549\",\"EN-9.1.2.2\",\"RGAAv4\",\"RGAA-4.3.1\"],actIds:[\"eac66b\"],all:[],any:[],none:[\"caption\"]}],checks:[{id:\"abstractrole\",evaluate:\"abstractrole-evaluate\"},{id:\"aria-allowed-attr\",evaluate:\"aria-allowed-attr-evaluate\",options:{validTreeRowAttrs:[\"aria-posinset\",\"aria-setsize\",\"aria-expanded\",\"aria-level\"]}},{id:\"aria-allowed-role\",evaluate:\"aria-allowed-role-evaluate\",options:{allowImplicit:!0,ignoredTags:[]}},{id:\"aria-busy\",evaluate:\"aria-busy-evaluate\",deprecated:!0},{id:\"aria-conditional-attr\",evaluate:\"aria-conditional-attr-evaluate\",options:{invalidTableRowAttrs:[\"aria-posinset\",\"aria-setsize\",\"aria-expanded\",\"aria-level\"]}},{id:\"aria-errormessage\",evaluate:\"aria-errormessage-evaluate\"},{id:\"aria-hidden-body\",evaluate:\"ar\\\nia-hidden-body-evaluate\"},{id:\"aria-level\",evaluate:\"aria-level-evaluate\"},{id:\"aria-prohibited-attr\",evaluate:\"aria-prohibited-attr-evaluate\",options:{elementsAllowedAriaLabel:[\"applet\",\"input\"]}},{id:\"aria-required-attr\",evaluate:\"aria-required-attr-evaluate\"},{id:\"aria-required-children\",evaluate:\"aria-required-children-evaluate\",options:{reviewEmpty:[\"doc-bibliography\",\"doc-endnotes\",\"grid\",\"list\",\"listbox\",\"menu\",\"menubar\",\"table\",\"tablist\",\"tree\",\"treegrid\",\"rowgroup\"]}},{id:\"aria-required-parent\",evaluate:\"aria-required-parent-evaluate\",options:{ownGroupRoles:[\"listitem\",\"treeitem\"]}},{id:\"aria-roledescription\",evaluate:\"aria-roledescription-evaluate\",options:{supportedRoles:[\"button\",\"img\",\"checkbox\",\"radio\",\"combobox\",\"menuitemcheckbox\",\"menuitemradio\"]}},{id:\"aria-unsupported-attr\",evaluate:\"aria-unsupported-attr-evaluate\"},{id:\"aria-valid-attr-value\",evaluate:\"aria-valid-attr-value-evaluate\",options:[]},{id:\"aria-valid-attr\",evaluate:\"aria-valid-attr-evaluate\",options:[]},{i\\\nd:\"braille-label-equivalent\",evaluate:\"braille-label-equivalent-evaluate\"},{id:\"braille-roledescription-equivalent\",evaluate:\"braille-roledescription-equivalent-evaluate\"},{id:\"deprecatedrole\",evaluate:\"deprecatedrole-evaluate\"},{id:\"fallbackrole\",evaluate:\"fallbackrole-evaluate\"},{id:\"has-global-aria-attribute\",evaluate:\"has-global-aria-attribute-evaluate\"},{id:\"has-widget-role\",evaluate:\"has-widget-role-evaluate\",options:[]},{id:\"invalidrole\",evaluate:\"invalidrole-evaluate\"},{id:\"is-element-focusable\",evaluate:\"is-element-focusable-evaluate\"},{id:\"no-implicit-explicit-label\",evaluate:\"no-implicit-explicit-label-evaluate\"},{id:\"unsupportedrole\",evaluate:\"unsupportedrole-evaluate\"},{id:\"valid-scrollable-semantics\",evaluate:\"valid-scrollable-semantics-evaluate\",options:{roles:[\"tooltip\"]}},{id:\"color-contrast-enhanced\",evaluate:\"color-contrast-evaluate\",options:{ignoreUnicode:!0,ignoreLength:!1,ignorePseudo:!1,boldValue:700,boldTextPt:14,largeTextPt:18,contrastRatio:{normal:{expected:7,\\\nminThreshold:4.5},large:{expected:4.5,minThreshold:3}},pseudoSizeThreshold:.25,shadowOutlineEmMax:.1,textStrokeEmMin:.03}},{id:\"color-contrast\",evaluate:\"color-contrast-evaluate\",options:{ignoreUnicode:!0,ignoreLength:!1,ignorePseudo:!1,boldValue:700,boldTextPt:14,largeTextPt:18,contrastRatio:{normal:{expected:4.5},large:{expected:3}},pseudoSizeThreshold:.25,shadowOutlineEmMax:.2,textStrokeEmMin:.03}},{id:\"link-in-text-block-style\",evaluate:\"link-in-text-block-style-evaluate\"},{id:\"link-in-text-block\",evaluate:\"link-in-text-block-evaluate\",options:{requiredContrastRatio:3,allowSameColor:!0}},{id:\"autocomplete-appropriate\",evaluate:\"autocomplete-appropriate-evaluate\",deprecated:!0},{id:\"autocomplete-valid\",evaluate:\"autocomplete-valid-evaluate\",options:{stateTerms:[\"none\",\"false\",\"true\",\"disabled\",\"enabled\",\"undefined\",\"null\",\"xoff\",\"xon\"],ignoredValues:[\"text\",\"pronouns\",\"gender\",\"message\",\"content\"]}},{id:\"accesskeys\",evaluate:\"accesskeys-evaluate\",after:\"accesskeys-after\"},{id:\"focus\\\nable-content\",evaluate:\"focusable-content-evaluate\"},{id:\"focusable-disabled\",evaluate:\"focusable-disabled-evaluate\"},{id:\"focusable-element\",evaluate:\"focusable-element-evaluate\"},{id:\"focusable-modal-open\",evaluate:\"focusable-modal-open-evaluate\"},{id:\"focusable-no-name\",evaluate:\"focusable-no-name-evaluate\"},{id:\"focusable-not-tabbable\",evaluate:\"focusable-not-tabbable-evaluate\"},{id:\"frame-focusable-content\",evaluate:\"frame-focusable-content-evaluate\"},{id:\"landmark-is-top-level\",evaluate:\"landmark-is-top-level-evaluate\"},{id:\"no-focusable-content\",evaluate:\"no-focusable-content-evaluate\"},{id:\"page-has-heading-one\",evaluate:\"has-descendant-evaluate\",after:\"has-descendant-after\",options:{selector:\"h1:not([role], [aria-level]), :is(h1, h2, h3, h4, h5, h6):not([role])[aria-level=1], [role=heading][aria-level=1]\",passForModal:!0}},{id:\"page-has-main\",evaluate:\"has-descendant-evaluate\",after:\"has-descendant-after\",options:{selector:\"main:not([role]), [role='main']\",passForModal:!0}},{i\\\nd:\"page-no-duplicate-banner\",evaluate:\"page-no-duplicate-evaluate\",after:\"page-no-duplicate-after\",options:{selector:\"header:not([role]), [role=banner]\",role:\"banner\"}},{id:\"page-no-duplicate-contentinfo\",evaluate:\"page-no-duplicate-evaluate\",after:\"page-no-duplicate-after\",options:{selector:\"footer:not([role]), [role=contentinfo]\",role:\"contentinfo\"}},{id:\"page-no-duplicate-main\",evaluate:\"page-no-duplicate-evaluate\",after:\"page-no-duplicate-after\",options:{selector:\"main:not([role]), [role='main']\"}},{id:\"tabindex\",evaluate:\"tabindex-evaluate\"},{id:\"alt-space-value\",evaluate:\"alt-space-value-evaluate\"},{id:\"duplicate-img-label\",evaluate:\"duplicate-img-label-evaluate\",options:{parentSelector:\"button, [role=button], a[href], p, li, td, th\"}},{id:\"explicit-label\",evaluate:\"explicit-evaluate\"},{id:\"help-same-as-label\",evaluate:\"help-same-as-label-evaluate\"},{id:\"hidden-explicit-label\",evaluate:\"hidden-explicit-label-evaluate\"},{id:\"implicit-label\",evaluate:\"implicit-evaluate\"},{id:\"label\\\n-content-name-mismatch\",evaluate:\"label-content-name-mismatch-evaluate\",options:{pixelThreshold:.1,occurrenceThreshold:3}},{id:\"multiple-label\",evaluate:\"multiple-label-evaluate\"},{id:\"title-only\",evaluate:\"title-only-evaluate\"},{id:\"landmark-is-unique\",evaluate:\"landmark-is-unique-evaluate\",after:\"landmark-is-unique-after\"},{id:\"has-lang\",evaluate:\"has-lang-evaluate\",options:{attributes:[\"lang\",\"xml:lang\"]}},{id:\"valid-lang\",evaluate:\"valid-lang-evaluate\",options:{attributes:[\"lang\",\"xml:lang\"]}},{id:\"xml-lang-mismatch\",evaluate:\"xml-lang-mismatch-evaluate\"},{id:\"dlitem\",evaluate:\"dlitem-evaluate\"},{id:\"listitem\",evaluate:\"listitem-evaluate\"},{id:\"only-dlitems\",evaluate:\"invalid-children-evaluate\",options:{validRoles:[\"definition\",\"term\",\"listitem\"],validNodeNames:[\"dt\",\"dd\"],divGroups:!0}},{id:\"only-listitems\",evaluate:\"invalid-children-evaluate\",options:{validRoles:[\"listitem\"],validNodeNames:[\"li\"]}},{id:\"structured-dlitems\",evaluate:\"structured-dlitems-evaluate\"},{id:\"caption\",eva\\\nluate:\"caption-evaluate\"},{id:\"frame-tested\",evaluate:\"frame-tested-evaluate\",after:\"frame-tested-after\",options:{isViolation:!1}},{id:\"no-autoplay-audio\",evaluate:\"no-autoplay-audio-evaluate\",options:{allowedDuration:3}},{id:\"css-orientation-lock\",evaluate:\"css-orientation-lock-evaluate\",options:{degreeThreshold:2}},{id:\"meta-viewport-large\",evaluate:\"meta-viewport-scale-evaluate\",options:{scaleMinimum:5,lowerBound:2}},{id:\"meta-viewport\",evaluate:\"meta-viewport-scale-evaluate\",options:{scaleMinimum:2}},{id:\"target-offset\",evaluate:\"target-offset-evaluate\",options:{minOffset:24}},{id:\"target-size\",evaluate:\"target-size-evaluate\",options:{minSize:24}},{id:\"header-present\",evaluate:\"has-descendant-evaluate\",after:\"has-descendant-after\",options:{selector:\":is(h1, h2, h3, h4, h5, h6):not([role]), [role=heading]\"}},{id:\"heading-order\",evaluate:\"heading-order-evaluate\",after:\"heading-order-after\"},{id:\"identical-links-same-purpose\",evaluate:\"identical-links-same-purpose-evaluate\",after:\"ide\\\nntical-links-same-purpose-after\"},{id:\"internal-link-present\",evaluate:\"internal-link-present-evaluate\"},{id:\"landmark\",evaluate:\"has-descendant-evaluate\",options:{selector:\"main, [role=main]\"}},{id:\"meta-refresh-no-exceptions\",evaluate:\"meta-refresh-evaluate\",options:{minDelay:72e3,maxDelay:!1}},{id:\"meta-refresh\",evaluate:\"meta-refresh-evaluate\",options:{minDelay:0,maxDelay:72e3}},{id:\"p-as-heading\",evaluate:\"p-as-heading-evaluate\",options:{margins:[{weight:150,italic:!0},{weight:150,size:1.15},{italic:!0,size:1.15},{size:1.4}],passLength:1,failLength:.5}},{id:\"region\",evaluate:\"region-evaluate\",after:\"region-after\",options:{regionMatcher:\"dialog, [role=dialog], [role=alertdialog], svg\"}},{id:\"skip-link\",evaluate:\"skip-link-evaluate\"},{id:\"unique-frame-title\",evaluate:\"unique-frame-title-evaluate\",after:\"unique-frame-title-after\"},{id:\"duplicate-id-active\",evaluate:\"duplicate-id-evaluate\",after:\"duplicate-id-after\"},{id:\"duplicate-id-aria\",evaluate:\"duplicate-id-evaluate\",after:\"dupl\\\nicate-id-after\"},{id:\"duplicate-id\",evaluate:\"duplicate-id-evaluate\",after:\"duplicate-id-after\"},{id:\"aria-label\",evaluate:\"aria-label-evaluate\"},{id:\"aria-labelledby\",evaluate:\"aria-labelledby-evaluate\"},{id:\"avoid-inline-spacing\",evaluate:\"avoid-inline-spacing-evaluate\",options:{cssProperties:[\"line-height\",\"letter-spacing\",\"word-spacing\"]}},{id:\"button-has-visible-text\",evaluate:\"has-text-content-evaluate\"},{id:\"doc-has-title\",evaluate:\"doc-has-title-evaluate\"},{id:\"error-occurred\",evaluate:\"exists-evaluate\"},{id:\"exists\",evaluate:\"exists-evaluate\"},{id:\"has-alt\",evaluate:\"has-alt-evaluate\"},{id:\"has-visible-text\",evaluate:\"has-text-content-evaluate\"},{id:\"important-letter-spacing\",evaluate:\"inline-style-property-evaluate\",options:{cssProperty:\"letter-spacing\",minValue:.12}},{id:\"important-line-height\",evaluate:\"inline-style-property-evaluate\",options:{multiLineOnly:!0,cssProperty:\"line-height\",minValue:1.5,normalValue:1}},{id:\"important-word-spacing\",evaluate:\"inline-style-property\\\n-evaluate\",options:{cssProperty:\"word-spacing\",minValue:.16}},{id:\"is-on-screen\",evaluate:\"is-on-screen-evaluate\"},{id:\"non-empty-alt\",evaluate:\"attr-non-space-content-evaluate\",options:{attribute:\"alt\"}},{id:\"non-empty-if-present\",evaluate:\"non-empty-if-present-evaluate\"},{id:\"non-empty-placeholder\",evaluate:\"attr-non-space-content-evaluate\",options:{attribute:\"placeholder\"}},{id:\"non-empty-title\",evaluate:\"attr-non-space-content-evaluate\",options:{attribute:\"title\"}},{id:\"non-empty-value\",evaluate:\"attr-non-space-content-evaluate\",options:{attribute:\"value\"}},{id:\"presentational-role\",evaluate:\"presentational-role-evaluate\"},{id:\"role-none\",evaluate:\"matches-definition-evaluate\",deprecated:!0,options:{matcher:{attributes:{role:\"none\"}}}},{id:\"role-presentation\",evaluate:\"matches-definition-evaluate\",deprecated:!0,options:{matcher:{attributes:{role:\"presentation\"}}}},{id:\"svg-non-empty-title\",evaluate:\"svg-non-empty-title-evaluate\"},{id:\"caption-faked\",evaluate:\"caption-faked-evaluate\\\n\"},{id:\"html5-scope\",evaluate:\"html5-scope-evaluate\"},{id:\"same-caption-summary\",evaluate:\"same-caption-summary-evaluate\"},{id:\"scope-value\",evaluate:\"scope-value-evaluate\",options:{values:[\"row\",\"col\",\"rowgroup\",\"colgroup\"]}},{id:\"td-has-header\",evaluate:\"td-has-header-evaluate\"},{id:\"td-headers-attr\",evaluate:\"td-headers-attr-evaluate\"},{id:\"th-has-data-cells\",evaluate:\"th-has-data-cells-evaluate\"},{id:\"hidden-content\",evaluate:\"hidden-content-evaluate\"}]})}(\"object\"==typeof window?window:this);`;\n  }\n});\n\n// core/lib/page-functions.js\nfunction wrapRuntimeEvalErrorInBrowser(err) {\n  if (!err || typeof err === \"string\") {\n    err = new Error(err);\n  }\n  return {\n    __failedInBrowser: true,\n    name: err.name || \"Error\",\n    message: err.message || \"unknown error\",\n    stack: err.stack\n  };\n}\nfunction getElementsInDocument2(selector) {\n  const realMatchesFn = window.__ElementMatches || window.Element.prototype.matches;\n  const results = [];\n  const _findAllElements = /* @__PURE__ */ __name((nodes) => {\n    for (const el of nodes) {\n      if (!selector || realMatchesFn.call(el, selector)) {\n        const matchedEl = el;\n        results.push(matchedEl);\n      }\n      if (el.shadowRoot) {\n        _findAllElements(el.shadowRoot.querySelectorAll(\"*\"));\n      }\n    }\n  }, \"_findAllElements\");\n  _findAllElements(document.querySelectorAll(\"*\"));\n  return results;\n}\nfunction getOuterHTMLSnippet(element, ignoreAttrs = [], snippetCharacterLimit = 500) {\n  const ATTRIBUTE_CHAR_LIMIT = 75;\n  const autoFillIgnoreAttrs = [\"autofill-information\", \"autofill-prediction\", \"title\"];\n  if (element instanceof ShadowRoot) {\n    element = element.host;\n  }\n  try {\n    const clone = element.cloneNode();\n    const template = element.ownerDocument.createElement(\"template\");\n    template.content.append(clone);\n    ignoreAttrs.concat(autoFillIgnoreAttrs).forEach((attribute) => {\n      clone.removeAttribute(attribute);\n    });\n    let charCount = 0;\n    for (const attributeName of clone.getAttributeNames()) {\n      if (charCount > snippetCharacterLimit) {\n        clone.removeAttribute(attributeName);\n        continue;\n      }\n      let attributeValue = clone.getAttribute(attributeName);\n      if (attributeValue === null) continue;\n      let dirty = false;\n      if (attributeName === \"src\" && \"currentSrc\" in element) {\n        const elementWithSrc = (\n          /** @type {HTMLImageElement|HTMLMediaElement} */\n          element\n        );\n        const currentSrc = elementWithSrc.currentSrc;\n        const documentHref = elementWithSrc.ownerDocument.location.href;\n        if (new URL(attributeValue, documentHref).toString() !== currentSrc) {\n          attributeValue = currentSrc;\n          dirty = true;\n        }\n      }\n      const truncatedString = truncate(attributeValue, ATTRIBUTE_CHAR_LIMIT);\n      if (truncatedString !== attributeValue) dirty = true;\n      attributeValue = truncatedString;\n      if (dirty) {\n        if (attributeName === \"style\") {\n          const elementWithStyle = (\n            /** @type {HTMLElement} */\n            clone\n          );\n          elementWithStyle.style.cssText = attributeValue;\n        } else {\n          clone.setAttribute(attributeName, attributeValue);\n        }\n      }\n      charCount += attributeName.length + attributeValue.length;\n    }\n    const reOpeningTag = /^[\\s\\S]*?>/;\n    const [match] = clone.outerHTML.match(reOpeningTag) || [];\n    if (match && charCount > snippetCharacterLimit) {\n      return match.slice(0, match.length - 1) + \" …>\";\n    }\n    return match || \"\";\n  } catch (_) {\n    return `<${element.localName}>`;\n  }\n}\nfunction computeBenchmarkIndex() {\n  function benchmarkIndexGC() {\n    const start = Date.now();\n    let iterations = 0;\n    while (Date.now() - start < 500) {\n      let s = \"\";\n      for (let j = 0; j < 1e4; j++) s += \"a\";\n      if (s.length === 1) throw new Error(\"will never happen, but prevents compiler optimizations\");\n      iterations++;\n    }\n    const durationInSeconds = (Date.now() - start) / 1e3;\n    return Math.round(iterations / 10 / durationInSeconds);\n  }\n  __name(benchmarkIndexGC, \"benchmarkIndexGC\");\n  function benchmarkIndexNoGC() {\n    const arrA = [];\n    const arrB = [];\n    for (let i = 0; i < 1e5; i++) arrA[i] = arrB[i] = i;\n    const start = Date.now();\n    let iterations = 0;\n    while (iterations % 10 !== 0 || Date.now() - start < 500) {\n      const src = iterations % 2 === 0 ? arrA : arrB;\n      const tgt = iterations % 2 === 0 ? arrB : arrA;\n      for (let j = 0; j < src.length; j++) tgt[j] = src[j];\n      iterations++;\n    }\n    const durationInSeconds = (Date.now() - start) / 1e3;\n    return Math.round(iterations / 10 / durationInSeconds);\n  }\n  __name(benchmarkIndexNoGC, \"benchmarkIndexNoGC\");\n  return (benchmarkIndexGC() + benchmarkIndexNoGC()) / 2;\n}\nfunction getNodePath(node) {\n  const isShadowRoot = /* @__PURE__ */ __name((node2) => node2.nodeType === Node.DOCUMENT_FRAGMENT_NODE, \"isShadowRoot\");\n  const getNodeParent = /* @__PURE__ */ __name((node2) => isShadowRoot(node2) ? node2.host : node2.parentNode, \"getNodeParent\");\n  function getNodeIndex(node2) {\n    if (isShadowRoot(node2)) {\n      return \"a\";\n    }\n    let index = 0;\n    let prevNode;\n    while (prevNode = node2.previousSibling) {\n      node2 = prevNode;\n      if (node2.nodeType === Node.TEXT_NODE && (node2.nodeValue || \"\").trim().length === 0) continue;\n      index++;\n    }\n    return index;\n  }\n  __name(getNodeIndex, \"getNodeIndex\");\n  let currentNode = node;\n  const path7 = [];\n  while (currentNode && getNodeParent(currentNode)) {\n    const index = getNodeIndex(currentNode);\n    path7.push([index, currentNode.nodeName]);\n    currentNode = getNodeParent(currentNode);\n  }\n  path7.reverse();\n  return path7.join(\",\");\n}\nfunction getNodeSelector(element) {\n  function getSelectorPart(element2) {\n    let part = element2.tagName.toLowerCase();\n    if (element2.id) {\n      part += \"#\" + element2.id;\n    } else if (element2.classList.length > 0) {\n      part += \".\" + element2.classList[0];\n    }\n    return part;\n  }\n  __name(getSelectorPart, \"getSelectorPart\");\n  const parts = [];\n  while (parts.length < 4) {\n    parts.unshift(getSelectorPart(element));\n    if (!element.parentElement) {\n      break;\n    }\n    element = element.parentElement;\n    if (element.tagName === \"HTML\") {\n      break;\n    }\n  }\n  return parts.join(\" > \");\n}\nfunction isPositionFixed(element) {\n  function getStyleAttrValue(element2, attr) {\n    return element2.style[attr] || window.getComputedStyle(element2)[attr];\n  }\n  __name(getStyleAttrValue, \"getStyleAttrValue\");\n  const htmlEl = document.querySelector(\"html\");\n  if (!htmlEl) throw new Error(\"html element not found in document\");\n  if (htmlEl.scrollHeight <= htmlEl.clientHeight || ![\"scroll\", \"auto\", \"visible\"].includes(getStyleAttrValue(htmlEl, \"overflowY\"))) {\n    return false;\n  }\n  let currentEl = element;\n  while (currentEl) {\n    const position = getStyleAttrValue(currentEl, \"position\");\n    if (position === \"fixed\" || position === \"sticky\") {\n      return true;\n    }\n    currentEl = currentEl.parentElement;\n  }\n  return false;\n}\nfunction getNodeLabel(element) {\n  const tagName = element.tagName.toLowerCase();\n  if (tagName !== \"html\" && tagName !== \"body\") {\n    const nodeLabel = element instanceof HTMLElement && element.innerText || element.getAttribute(\"alt\") || element.getAttribute(\"aria-label\");\n    if (nodeLabel) {\n      return truncate(nodeLabel, 80);\n    } else {\n      const nodeToUseForLabel = element.querySelector(\"[alt], [aria-label]\");\n      if (nodeToUseForLabel) {\n        return getNodeLabel(nodeToUseForLabel);\n      }\n    }\n  }\n  return null;\n}\nfunction getBoundingClientRect(element) {\n  const realBoundingClientRect = window.__HTMLElementBoundingClientRect || window.HTMLElement.prototype.getBoundingClientRect;\n  const rect = realBoundingClientRect.call(element);\n  return {\n    top: Math.round(rect.top),\n    bottom: Math.round(rect.bottom),\n    left: Math.round(rect.left),\n    right: Math.round(rect.right),\n    width: Math.round(rect.width),\n    height: Math.round(rect.height)\n  };\n}\nfunction wrapRequestIdleCallback(cpuSlowdownMultiplier) {\n  const safetyAllowanceMs = 10;\n  const maxExecutionTimeMs = Math.floor((50 - safetyAllowanceMs) / cpuSlowdownMultiplier);\n  const nativeRequestIdleCallback = window.requestIdleCallback;\n  window.requestIdleCallback = (cb, options) => {\n    const cbWrap = /* @__PURE__ */ __name((deadline) => {\n      const start = Date.now();\n      deadline.__timeRemaining = deadline.timeRemaining;\n      deadline.timeRemaining = () => {\n        const timeRemaining = deadline.__timeRemaining();\n        return Math.min(\n          timeRemaining,\n          Math.max(0, maxExecutionTimeMs - (Date.now() - start))\n        );\n      };\n      deadline.timeRemaining.toString = () => {\n        return \"function timeRemaining() { [native code] }\";\n      };\n      cb(deadline);\n    }, \"cbWrap\");\n    return nativeRequestIdleCallback(cbWrap, options);\n  };\n  window.requestIdleCallback.toString = () => {\n    return \"function requestIdleCallback() { [native code] }\";\n  };\n}\nfunction getNodeDetails2(element) {\n  if (!window.__lighthouseNodesDontTouchOrAllVarianceGoesAway) {\n    window.__lighthouseNodesDontTouchOrAllVarianceGoesAway = /* @__PURE__ */ new Map();\n  }\n  element = element instanceof ShadowRoot ? element.host : element;\n  const selector = getNodeSelector(element);\n  let lhId = window.__lighthouseNodesDontTouchOrAllVarianceGoesAway.get(element);\n  if (!lhId) {\n    lhId = [\n      window.__lighthouseExecutionContextUniqueIdentifier === void 0 ? \"page\" : window.__lighthouseExecutionContextUniqueIdentifier,\n      window.__lighthouseNodesDontTouchOrAllVarianceGoesAway.size,\n      element.tagName\n    ].join(\"-\");\n    window.__lighthouseNodesDontTouchOrAllVarianceGoesAway.set(element, lhId);\n  }\n  const details = {\n    lhId,\n    devtoolsNodePath: getNodePath(element),\n    selector,\n    boundingRect: getBoundingClientRect(element),\n    snippet: getOuterHTMLSnippet(element),\n    nodeLabel: getNodeLabel(element) || selector\n  };\n  return details;\n}\nfunction truncate(string, characterLimit) {\n  return Util.truncate(string, characterLimit);\n}\nfunction isBundledEnvironment() {\n  if (global.isDevtools || global.isLightrider) return true;\n  const require5 = createRequire({ url: \"core/lib/page-functions.js\" }.url);\n  try {\n    require5.resolve(\"lighthouse-logger\");\n    return false;\n  } catch (err) {\n    return true;\n  }\n}\nfunction createEsbuildFunctionWrapper() {\n  if (!isBundledEnvironment()) {\n    return \"\";\n  }\n  const functionAsString = (() => {\n    const a = /* @__PURE__ */ __name(() => {\n    }, \"a\");\n  }).toString().replace(\"/* @__PURE__ */\", \"\");\n  const functionStringMatch = functionAsString.match(/=\\s*([\\w_]+)\\(/);\n  if (!functionStringMatch) {\n    throw new Error(\"Could not determine esbuild function wrapper name\");\n  }\n  const esbuildFunctionWrapper = /* @__PURE__ */ __name((fn, value) => Object.defineProperty(fn, \"name\", { value, configurable: true }), \"esbuildFunctionWrapper\");\n  const wrapperFnName = functionStringMatch[1];\n  return `let ${wrapperFnName}=${esbuildFunctionWrapper}`;\n}\nfunction getRuntimeFunctionName(fn) {\n  const match = fn.toString().match(/function ([\\w$]+)/);\n  if (!match) throw new Error(`could not find function name for: ${fn}`);\n  return match[1];\n}\nvar esbuildFunctionWrapperString, names, getNodeLabelRawString, getOuterHTMLSnippetRawString, getNodeDetailsRawString, pageFunctions;\nvar init_page_functions = __esm({\n  \"core/lib/page-functions.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_module();\n    init_util();\n    /**\n     * @license\n     * Copyright 2018 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    __name(wrapRuntimeEvalErrorInBrowser, \"wrapRuntimeEvalErrorInBrowser\");\n    __name(getElementsInDocument2, \"getElementsInDocument\");\n    __name(getOuterHTMLSnippet, \"getOuterHTMLSnippet\");\n    __name(computeBenchmarkIndex, \"computeBenchmarkIndex\");\n    __name(getNodePath, \"getNodePath\");\n    __name(getNodeSelector, \"getNodeSelector\");\n    __name(isPositionFixed, \"isPositionFixed\");\n    __name(getNodeLabel, \"getNodeLabel\");\n    __name(getBoundingClientRect, \"getBoundingClientRect\");\n    __name(wrapRequestIdleCallback, \"wrapRequestIdleCallback\");\n    __name(getNodeDetails2, \"getNodeDetails\");\n    __name(truncate, \"truncate\");\n    __name(isBundledEnvironment, \"isBundledEnvironment\");\n    esbuildFunctionWrapperString = createEsbuildFunctionWrapper();\n    __name(createEsbuildFunctionWrapper, \"createEsbuildFunctionWrapper\");\n    __name(getRuntimeFunctionName, \"getRuntimeFunctionName\");\n    names = {\n      truncate: getRuntimeFunctionName(truncate),\n      getNodeLabel: getRuntimeFunctionName(getNodeLabel),\n      getOuterHTMLSnippet: getRuntimeFunctionName(getOuterHTMLSnippet),\n      getNodeDetails: getRuntimeFunctionName(getNodeDetails2)\n    };\n    truncate.toString = () => `function ${names.truncate}(string, characterLimit) {\n  const Util = { ${Util.truncate} };\n  return Util.truncate(string, characterLimit);\n}`;\n    getNodeLabelRawString = getNodeLabel.toString();\n    getNodeLabel.toString = () => `function ${names.getNodeLabel}(element) {\n  ${truncate};\n  return (${getNodeLabelRawString})(element);\n}`;\n    getOuterHTMLSnippetRawString = getOuterHTMLSnippet.toString();\n    getOuterHTMLSnippet.toString = () => `function ${names.getOuterHTMLSnippet}(element, ignoreAttrs = [], snippetCharacterLimit = 500) {\n  ${truncate};\n  return (${getOuterHTMLSnippetRawString})(element, ignoreAttrs, snippetCharacterLimit);\n}`;\n    getNodeDetailsRawString = getNodeDetails2.toString();\n    getNodeDetails2.toString = () => `function ${names.getNodeDetails}(element) {\n  ${truncate};\n  ${getNodePath};\n  ${getNodeSelector};\n  ${getBoundingClientRect};\n  ${getOuterHTMLSnippetRawString};\n  ${getNodeLabelRawString};\n  return (${getNodeDetailsRawString})(element);\n}`;\n    pageFunctions = {\n      wrapRuntimeEvalErrorInBrowser,\n      getElementsInDocument: getElementsInDocument2,\n      getOuterHTMLSnippet,\n      computeBenchmarkIndex,\n      getNodeDetails: getNodeDetails2,\n      getNodePath,\n      getNodeSelector,\n      getNodeLabel,\n      isPositionFixed,\n      wrapRequestIdleCallback,\n      getBoundingClientRect,\n      truncate,\n      esbuildFunctionWrapperString,\n      getRuntimeFunctionName\n    };\n  }\n});\n\n// core/gather/gatherers/accessibility.js\nvar accessibility_exports = {};\n__export(accessibility_exports, {\n  default: () => accessibility_default\n});\nasync function runA11yChecks() {\n  const axe = window.axe;\n  const application = `lighthouse-${Math.random()}`;\n  axe.configure({\n    branding: {\n      application\n    },\n    noHtml: true\n  });\n  const axeResults = await axe.run(document, {\n    elementRef: true,\n    runOnly: {\n      type: \"tag\",\n      values: [\n        \"wcag2a\",\n        \"wcag2aa\"\n      ]\n    },\n    // resultTypes doesn't limit the output of the axeResults object. Instead, if it's defined,\n    // some expensive element identification is done only for the respective types. https://github.com/dequelabs/axe-core/blob/f62f0cf18f7b69b247b0b6362cf1ae71ffbf3a1b/lib/core/reporters/helpers/process-aggregate.js#L61-L97\n    resultTypes: [\"violations\", \"inapplicable\"],\n    rules: {\n      // Consider http://go/prcpg for expert review of the aXe rules.\n      \"accesskeys\": { enabled: true },\n      \"area-alt\": { enabled: false },\n      \"aria-allowed-role\": { enabled: true },\n      \"aria-braille-equivalent\": { enabled: false },\n      \"aria-conditional-attr\": { enabled: true },\n      \"aria-deprecated-role\": { enabled: true },\n      \"aria-dialog-name\": { enabled: true },\n      \"aria-prohibited-attr\": { enabled: true },\n      \"aria-roledescription\": { enabled: false },\n      \"aria-treeitem-name\": { enabled: true },\n      \"aria-text\": { enabled: true },\n      \"audio-caption\": { enabled: false },\n      \"blink\": { enabled: false },\n      \"duplicate-id\": { enabled: false },\n      \"empty-heading\": { enabled: true },\n      \"frame-focusable-content\": { enabled: false },\n      \"frame-title-unique\": { enabled: false },\n      \"heading-order\": { enabled: true },\n      \"html-xml-lang-mismatch\": { enabled: true },\n      \"identical-links-same-purpose\": { enabled: true },\n      \"image-redundant-alt\": { enabled: true },\n      \"input-button-name\": { enabled: true },\n      \"label-content-name-mismatch\": { enabled: true },\n      \"landmark-one-main\": { enabled: true },\n      \"link-in-text-block\": { enabled: true },\n      \"marquee\": { enabled: false },\n      \"meta-viewport\": { enabled: true },\n      // https://github.com/dequelabs/axe-core/issues/2958\n      \"nested-interactive\": { enabled: false },\n      \"no-autoplay-audio\": { enabled: false },\n      \"role-img-alt\": { enabled: false },\n      \"scrollable-region-focusable\": { enabled: false },\n      \"select-name\": { enabled: true },\n      \"server-side-image-map\": { enabled: false },\n      \"skip-link\": { enabled: true },\n      // https://github.com/GoogleChrome/lighthouse/issues/16163\n      \"summary-name\": { enabled: false },\n      \"svg-img-alt\": { enabled: false },\n      \"tabindex\": { enabled: true },\n      \"table-duplicate-name\": { enabled: true },\n      \"table-fake-caption\": { enabled: true },\n      \"target-size\": { enabled: true },\n      \"td-has-header\": { enabled: true }\n    }\n  });\n  document.documentElement.scrollTop = 0;\n  return {\n    violations: axeResults.violations.map(createAxeRuleResultArtifact),\n    incomplete: axeResults.incomplete.map(createAxeRuleResultArtifact),\n    notApplicable: axeResults.inapplicable.map((result) => ({ id: result.id })),\n    // FYI: inapplicable => notApplicable!\n    passes: axeResults.passes.map((result) => ({ id: result.id })),\n    version: axeResults.testEngine.version\n  };\n}\nasync function runA11yChecksAndResetScroll() {\n  const originalScrollPosition = {\n    x: window.scrollX,\n    y: window.scrollY\n  };\n  try {\n    return await runA11yChecks();\n  } finally {\n    window.scrollTo(originalScrollPosition.x, originalScrollPosition.y);\n  }\n}\nfunction createAxeRuleResultArtifact(result) {\n  const nodes = result.nodes.map((node) => {\n    const { target, failureSummary, element } = node;\n    const nodeDetails = getNodeDetails(\n      /** @type {HTMLElement} */\n      element\n    );\n    const relatedNodeElements = /* @__PURE__ */ new Set();\n    const impactToNumber = /* @__PURE__ */ __name((impact) => [null, \"minor\", \"moderate\", \"serious\", \"critical\"].indexOf(impact), \"impactToNumber\");\n    const checkResults = [...node.any, ...node.all, ...node.none].sort((a, b) => impactToNumber(b.impact) - impactToNumber(a.impact));\n    for (const checkResult of checkResults) {\n      for (const relatedNode of checkResult.relatedNodes || []) {\n        const relatedElement = relatedNode.element;\n        if (relatedNodeElements.size >= 3) break;\n        if (!relatedElement) continue;\n        if (element === relatedElement) continue;\n        relatedNodeElements.add(relatedElement);\n      }\n    }\n    const relatedNodeDetails = [...relatedNodeElements].map(getNodeDetails);\n    return {\n      target,\n      failureSummary,\n      node: nodeDetails,\n      relatedNodes: relatedNodeDetails\n    };\n  });\n  const resultError = result.error;\n  let error;\n  if (resultError instanceof Error) {\n    error = {\n      name: resultError.name,\n      message: resultError.message\n    };\n  }\n  return {\n    id: result.id,\n    impact: result.impact || void 0,\n    tags: result.tags,\n    nodes,\n    error\n  };\n}\nvar Accessibility, accessibility_default;\nvar init_accessibility = __esm({\n  \"core/gather/gatherers/accessibility.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_base_gatherer();\n    init_axe();\n    init_page_functions();\n    /**\n     * @license\n     * Copyright 2016 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    __name(runA11yChecks, \"runA11yChecks\");\n    __name(runA11yChecksAndResetScroll, \"runA11yChecksAndResetScroll\");\n    __name(createAxeRuleResultArtifact, \"createAxeRuleResultArtifact\");\n    Accessibility = class extends base_gatherer_default {\n      static {\n        __name(this, \"Accessibility\");\n      }\n      /** @type {LH.Gatherer.GathererMeta} */\n      meta = {\n        supportedModes: [\"snapshot\", \"navigation\"]\n      };\n      static pageFns = {\n        runA11yChecks,\n        createAxeRuleResultArtifact\n      };\n      /**\n       * @param {LH.Gatherer.Context} passContext\n       * @return {Promise<LH.Artifacts.Accessibility>}\n       */\n      getArtifact(passContext) {\n        const driver = passContext.driver;\n        return driver.executionContext.evaluate(runA11yChecksAndResetScroll, {\n          args: [],\n          useIsolation: true,\n          deps: [\n            axeSource,\n            pageFunctions.getNodeDetails,\n            createAxeRuleResultArtifact,\n            runA11yChecks\n          ]\n        });\n      }\n    };\n    accessibility_default = Accessibility;\n  }\n});\n\n// core/gather/driver/dom.js\nfunction handlePotentialMissingNodeError(err) {\n  if (/No node.*found/.test(err.message) || /Node.*does not belong to the document/.test(err.message)) {\n    return void 0;\n  }\n  throw err;\n}\nasync function resolveDevtoolsNodePathToObjectId(session, path7) {\n  try {\n    const { nodeId } = await session.sendCommand(\"DOM.pushNodeByPathToFrontend\", { path: path7 });\n    const { object: { objectId } } = await session.sendCommand(\"DOM.resolveNode\", { nodeId });\n    return objectId;\n  } catch (err) {\n    return handlePotentialMissingNodeError(err);\n  }\n}\nvar init_dom = __esm({\n  \"core/gather/driver/dom.js\"() {\n    \"use strict\";\n    init_process_global();\n    /**\n     * @license\n     * Copyright 2021 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    __name(handlePotentialMissingNodeError, \"handlePotentialMissingNodeError\");\n    __name(resolveDevtoolsNodePathToObjectId, \"resolveDevtoolsNodePathToObjectId\");\n  }\n});\n\n// core/gather/gatherers/anchor-elements.js\nvar anchor_elements_exports = {};\n__export(anchor_elements_exports, {\n  default: () => anchor_elements_default\n});\nfunction collectAnchorElements() {\n  const resolveURLOrEmpty = /* @__PURE__ */ __name((url) => {\n    try {\n      return new URL(url, window.location.href).href;\n    } catch (_) {\n      return \"\";\n    }\n  }, \"resolveURLOrEmpty\");\n  function getTruncatedOnclick(node) {\n    const onclick = node.getAttribute(\"onclick\") || \"\";\n    return onclick.slice(0, 1024);\n  }\n  __name(getTruncatedOnclick, \"getTruncatedOnclick\");\n  function getLangOfInnerText(node) {\n    let curNodeLang = null;\n    for (const child of node.querySelectorAll(\"*\")) {\n      if (!child.textContent) continue;\n      const childLang = child.closest(\"[lang]\")?.getAttribute(\"lang\");\n      if (!childLang) continue;\n      if (!curNodeLang) {\n        curNodeLang = childLang;\n        continue;\n      }\n      if (curNodeLang.split(\"-\")[0] !== childLang.split(\"-\")[0]) {\n        return null;\n      }\n    }\n    return curNodeLang ?? node.closest(\"[lang]\")?.getAttribute(\"lang\") ?? null;\n  }\n  __name(getLangOfInnerText, \"getLangOfInnerText\");\n  const anchorElements = getElementsInDocument(\"a\");\n  const langElements = getElementsInDocument(\"[lang]\");\n  const documentHasSingleLang = langElements.length === 1 && (langElements[0].nodeName === \"BODY\" || langElements[0].nodeName === \"HTML\");\n  const singleLang = documentHasSingleLang ? langElements[0].getAttribute(\"lang\") : null;\n  return anchorElements.map((node) => {\n    if (node instanceof HTMLAnchorElement) {\n      return {\n        href: node.href,\n        rawHref: node.getAttribute(\"href\") || \"\",\n        onclick: getTruncatedOnclick(node),\n        role: node.getAttribute(\"role\") || \"\",\n        name: node.name,\n        text: node.innerText,\n        // we don't want to return hidden text, so use innerText\n        textLang: singleLang ?? getLangOfInnerText(node) ?? void 0,\n        rel: node.rel,\n        target: node.target,\n        id: node.getAttribute(\"id\") || \"\",\n        attributeNames: node.getAttributeNames(),\n        // @ts-expect-error - getNodeDetails put into scope via stringification\n        node: getNodeDetails(node)\n      };\n    }\n    return {\n      href: resolveURLOrEmpty(node.href.baseVal),\n      rawHref: node.getAttribute(\"href\") || \"\",\n      onclick: getTruncatedOnclick(node),\n      role: node.getAttribute(\"role\") || \"\",\n      text: node.textContent || \"\",\n      textLang: singleLang ?? getLangOfInnerText(node) ?? void 0,\n      rel: \"\",\n      target: node.target.baseVal || \"\",\n      id: node.getAttribute(\"id\") || \"\",\n      attributeNames: node.getAttributeNames(),\n      // @ts-expect-error - getNodeDetails put into scope via stringification\n      node: getNodeDetails(node)\n    };\n  });\n}\nasync function getEventListeners(session, devtoolsNodePath) {\n  const objectId = await resolveDevtoolsNodePathToObjectId(session, devtoolsNodePath);\n  if (!objectId) return [];\n  const response = await session.sendCommand(\"DOMDebugger.getEventListeners\", {\n    objectId\n  });\n  return response.listeners.map(({ type }) => ({ type }));\n}\nvar AnchorElements, anchor_elements_default;\nvar init_anchor_elements = __esm({\n  \"core/gather/gatherers/anchor-elements.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_base_gatherer();\n    init_page_functions();\n    init_dom();\n    /**\n     * @license\n     * Copyright 2019 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    __name(collectAnchorElements, \"collectAnchorElements\");\n    __name(getEventListeners, \"getEventListeners\");\n    AnchorElements = class extends base_gatherer_default {\n      static {\n        __name(this, \"AnchorElements\");\n      }\n      /** @type {LH.Gatherer.GathererMeta} */\n      meta = {\n        supportedModes: [\"snapshot\", \"navigation\"]\n      };\n      /**\n       * @param {LH.Gatherer.Context} passContext\n       * @return {Promise<LH.Artifacts['AnchorElements']>}\n       */\n      async getArtifact(passContext) {\n        const session = passContext.driver.defaultSession;\n        const anchors = await passContext.driver.executionContext.evaluate(collectAnchorElements, {\n          args: [],\n          useIsolation: true,\n          deps: [\n            pageFunctions.getElementsInDocument,\n            pageFunctions.getNodeDetails\n          ]\n        });\n        await session.sendCommand(\"DOM.enable\");\n        await session.sendCommand(\"DOM.getDocument\", { depth: -1, pierce: true });\n        const anchorsWithEventListeners = anchors.map((anchor) => {\n          return getEventListeners(session, anchor.node.devtoolsNodePath).then((listeners) => {\n            return {\n              ...anchor,\n              listeners\n            };\n          });\n        });\n        const result = await Promise.all(anchorsWithEventListeners);\n        await session.sendCommand(\"DOM.disable\");\n        return result;\n      }\n    };\n    anchor_elements_default = AnchorElements;\n  }\n});\n\n// core/gather/gatherers/console-messages.js\nvar console_messages_exports = {};\n__export(console_messages_exports, {\n  default: () => console_messages_default\n});\nfunction remoteObjectToString(obj) {\n  if (typeof obj.value !== \"undefined\" || obj.type === \"undefined\") {\n    return String(obj.value);\n  }\n  if (typeof obj.description === \"string\" && obj.description !== obj.className) {\n    return obj.description;\n  }\n  const type = obj.subtype || obj.type;\n  const className = obj.className || \"Object\";\n  return `[${type} ${className}]`;\n}\nvar ConsoleMessages, console_messages_default;\nvar init_console_messages = __esm({\n  \"core/gather/gatherers/console-messages.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_base_gatherer();\n    /**\n     * @license\n     * Copyright 2020 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    __name(remoteObjectToString, \"remoteObjectToString\");\n    ConsoleMessages = class extends base_gatherer_default {\n      static {\n        __name(this, \"ConsoleMessages\");\n      }\n      /** @type {LH.Gatherer.GathererMeta} */\n      meta = {\n        supportedModes: [\"timespan\", \"navigation\"]\n      };\n      constructor() {\n        super();\n        this._logEntries = [];\n        this._onConsoleAPICalled = this.onConsoleAPICalled.bind(this);\n        this._onExceptionThrown = this.onExceptionThrown.bind(this);\n        this._onLogEntryAdded = this.onLogEntry.bind(this);\n      }\n      /**\n       * Handles events for when a script invokes a console API.\n       * @param {LH.Crdp.Runtime.ConsoleAPICalledEvent} event\n       */\n      onConsoleAPICalled(event) {\n        const { type } = event;\n        if (type !== \"warning\" && type !== \"error\") {\n          return;\n        }\n        const args = event.args || [];\n        const text = args.map(remoteObjectToString).join(\" \");\n        if (!text && !event.stackTrace) {\n          return;\n        }\n        const { url, lineNumber, columnNumber } = event.stackTrace?.callFrames[0] || {};\n        const consoleMessage = {\n          eventType: \"consoleAPI\",\n          source: type === \"warning\" ? \"console.warn\" : \"console.error\",\n          level: type,\n          text,\n          stackTrace: event.stackTrace,\n          timestamp: event.timestamp,\n          url,\n          lineNumber,\n          columnNumber\n        };\n        this._logEntries.push(consoleMessage);\n      }\n      /**\n       * Handles exception thrown events.\n       * @param {LH.Crdp.Runtime.ExceptionThrownEvent} event\n       */\n      onExceptionThrown(event) {\n        const text = event.exceptionDetails.exception ? event.exceptionDetails.exception.description : event.exceptionDetails.text;\n        if (!text) {\n          return;\n        }\n        const consoleMessage = {\n          eventType: \"exception\",\n          source: \"exception\",\n          level: \"error\",\n          text,\n          stackTrace: event.exceptionDetails.stackTrace,\n          timestamp: event.timestamp,\n          url: event.exceptionDetails.url,\n          scriptId: event.exceptionDetails.scriptId,\n          lineNumber: event.exceptionDetails.lineNumber,\n          columnNumber: event.exceptionDetails.columnNumber\n        };\n        this._logEntries.push(consoleMessage);\n      }\n      /**\n       * Handles browser reports logged to the console, including interventions,\n       * deprecations, violations, and more.\n       * @param {LH.Crdp.Log.EntryAddedEvent} event\n       */\n      onLogEntry(event) {\n        const { source, level, text, stackTrace, timestamp, url, lineNumber } = event.entry;\n        const firstStackFrame = event.entry.stackTrace?.callFrames[0];\n        this._logEntries.push({\n          eventType: \"protocolLog\",\n          source,\n          level,\n          text,\n          stackTrace,\n          timestamp,\n          url,\n          scriptId: firstStackFrame?.scriptId,\n          lineNumber,\n          columnNumber: firstStackFrame?.columnNumber\n        });\n      }\n      /**\n       * @param {LH.Gatherer.Context} passContext\n       */\n      async startInstrumentation(passContext) {\n        const session = passContext.driver.defaultSession;\n        session.on(\"Log.entryAdded\", this._onLogEntryAdded);\n        await session.sendCommand(\"Log.enable\");\n        await session.sendCommand(\"Log.startViolationsReport\", {\n          config: [{ name: \"discouragedAPIUse\", threshold: -1 }]\n        });\n        session.on(\"Runtime.consoleAPICalled\", this._onConsoleAPICalled);\n        session.on(\"Runtime.exceptionThrown\", this._onExceptionThrown);\n        await session.sendCommand(\"Runtime.enable\");\n      }\n      /**\n       * @param {LH.Gatherer.Context} passContext\n       * @return {Promise<void>}\n       */\n      async stopInstrumentation({ driver }) {\n        await driver.defaultSession.sendCommand(\"Log.stopViolationsReport\");\n        await driver.defaultSession.off(\"Log.entryAdded\", this._onLogEntryAdded);\n        await driver.defaultSession.sendCommand(\"Log.disable\");\n        await driver.defaultSession.off(\"Runtime.consoleAPICalled\", this._onConsoleAPICalled);\n        await driver.defaultSession.off(\"Runtime.exceptionThrown\", this._onExceptionThrown);\n        await driver.defaultSession.sendCommand(\"Runtime.disable\");\n      }\n      /**\n       * @return {Promise<LH.Artifacts['ConsoleMessages']>}\n       */\n      async getArtifact() {\n        return this._logEntries;\n      }\n    };\n    console_messages_default = ConsoleMessages;\n  }\n});\n\n// core/gather/gatherers/devtools-log.js\nvar devtools_log_exports = {};\n__export(devtools_log_exports, {\n  DevtoolsMessageLog: () => DevtoolsMessageLog,\n  default: () => devtools_log_default\n});\nvar DevtoolsLog, DevtoolsMessageLog, devtools_log_default;\nvar init_devtools_log = __esm({\n  \"core/gather/gatherers/devtools-log.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_base_gatherer();\n    /**\n     * @license\n     * Copyright 2021 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    DevtoolsLog = class _DevtoolsLog extends base_gatherer_default {\n      static {\n        __name(this, \"DevtoolsLog\");\n      }\n      static symbol = Symbol(\"DevtoolsLog\");\n      /** @type {LH.Gatherer.GathererMeta} */\n      meta = {\n        symbol: _DevtoolsLog.symbol,\n        supportedModes: [\"timespan\", \"navigation\"]\n      };\n      constructor() {\n        super();\n        this._messageLog = new DevtoolsMessageLog(/^(Page|Network|Target|Runtime)\\./);\n        this._onProtocolMessage = (e) => this._messageLog.record(e);\n      }\n      /**\n       * @param {LH.Gatherer.Context} passContext\n       */\n      async startSensitiveInstrumentation({ driver }) {\n        this._messageLog.reset();\n        this._messageLog.beginRecording();\n        driver.targetManager.on(\"protocolevent\", this._onProtocolMessage);\n        await driver.defaultSession.sendCommand(\"Page.enable\");\n      }\n      /**\n       * @param {LH.Gatherer.Context} passContext\n       */\n      async stopSensitiveInstrumentation({ driver }) {\n        this._messageLog.endRecording();\n        driver.targetManager.off(\"protocolevent\", this._onProtocolMessage);\n      }\n      /**\n       * @return {LH.Artifacts['DevtoolsLog']}\n       */\n      getDebugData() {\n        return this._messageLog.messages;\n      }\n      /**\n       * @return {Promise<LH.Artifacts['DevtoolsLog']>}\n       */\n      async getArtifact() {\n        return this._messageLog.messages;\n      }\n    };\n    DevtoolsMessageLog = class {\n      static {\n        __name(this, \"DevtoolsMessageLog\");\n      }\n      /**\n       * @param {RegExp=} regexFilter\n       */\n      constructor(regexFilter) {\n        this._filter = regexFilter;\n        this._messages = [];\n        this._isRecording = false;\n      }\n      /**\n       * @return {LH.DevtoolsLog}\n       */\n      get messages() {\n        return this._messages;\n      }\n      reset() {\n        this._messages = [];\n      }\n      beginRecording() {\n        this._isRecording = true;\n      }\n      endRecording() {\n        this._isRecording = false;\n      }\n      /**\n       * Records a message if method matches filter and recording has been started.\n       * @param {LH.Protocol.RawEventMessage} message\n       */\n      record(message) {\n        if (!this._isRecording) return;\n        if (typeof message.method !== \"string\") return;\n        if (this._filter && !this._filter.test(message.method)) return;\n        this._messages.push(message);\n      }\n    };\n    devtools_log_default = DevtoolsLog;\n  }\n});\n\n// core/gather/gatherers/dobetterweb/doctype.js\nvar doctype_exports = {};\n__export(doctype_exports, {\n  default: () => doctype_default\n});\nfunction getDoctype() {\n  if (!document.doctype) {\n    return null;\n  }\n  const documentCompatMode = document.compatMode;\n  const { name, publicId, systemId } = document.doctype;\n  return { name, publicId, systemId, documentCompatMode };\n}\nvar Doctype, doctype_default;\nvar init_doctype = __esm({\n  \"core/gather/gatherers/dobetterweb/doctype.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_base_gatherer();\n    /**\n     * @license\n     * Copyright 2018 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    __name(getDoctype, \"getDoctype\");\n    Doctype = class extends base_gatherer_default {\n      static {\n        __name(this, \"Doctype\");\n      }\n      /** @type {LH.Gatherer.GathererMeta} */\n      meta = {\n        supportedModes: [\"snapshot\", \"navigation\"]\n      };\n      /**\n       * @param {LH.Gatherer.Context} passContext\n       * @return {Promise<LH.Artifacts['Doctype']>}\n       */\n      getArtifact(passContext) {\n        const driver = passContext.driver;\n        return driver.executionContext.evaluate(getDoctype, {\n          args: [],\n          useIsolation: true\n        });\n      }\n    };\n    doctype_default = Doctype;\n  }\n});\n\n// core/gather/gatherers/image-elements.js\nvar image_elements_exports = {};\n__export(image_elements_exports, {\n  default: () => image_elements_default\n});\nfunction getClientRect(element) {\n  const clientRect = element.getBoundingClientRect();\n  return {\n    // Just grab the DOMRect properties we want, excluding x/y/width/height\n    top: clientRect.top,\n    bottom: clientRect.bottom,\n    left: clientRect.left,\n    right: clientRect.right\n  };\n}\nfunction getPosition(element, computedStyle) {\n  if (element.parentElement && element.parentElement.tagName === \"PICTURE\") {\n    const parentStyle = window.getComputedStyle(element.parentElement);\n    return parentStyle.getPropertyValue(\"position\");\n  }\n  return computedStyle.getPropertyValue(\"position\");\n}\nfunction getHTMLImages(allElements) {\n  const allImageElements = (\n    /** @type {Array<HTMLImageElement>} */\n    allElements.filter((element) => {\n      return element.localName === \"img\";\n    })\n  );\n  return allImageElements.map((element) => {\n    const computedStyle = window.getComputedStyle(element);\n    const isPicture = !!element.parentElement && element.parentElement.tagName === \"PICTURE\";\n    const canTrustNaturalDimensions = !isPicture && !element.srcset;\n    return {\n      // currentSrc used over src to get the url as determined by the browser\n      // after taking into account srcset/media/sizes/etc.\n      src: element.currentSrc,\n      srcset: element.srcset,\n      displayedWidth: element.width,\n      displayedHeight: element.height,\n      clientRect: getClientRect(element),\n      attributeWidth: element.getAttribute(\"width\"),\n      attributeHeight: element.getAttribute(\"height\"),\n      naturalDimensions: canTrustNaturalDimensions ? { width: element.naturalWidth, height: element.naturalHeight } : void 0,\n      cssRules: void 0,\n      // this will get overwritten below\n      computedStyles: {\n        position: getPosition(element, computedStyle),\n        objectFit: computedStyle.getPropertyValue(\"object-fit\"),\n        imageRendering: computedStyle.getPropertyValue(\"image-rendering\")\n      },\n      isCss: false,\n      isPicture,\n      loading: element.loading,\n      isInShadowDOM: element.getRootNode() instanceof ShadowRoot,\n      fetchPriority: element.fetchPriority,\n      // @ts-expect-error - getNodeDetails put into scope via stringification\n      node: getNodeDetails(element)\n    };\n  });\n}\nfunction getCSSImages(allElements) {\n  const CSS_URL_REGEX = /^url\\(\"([^\"]+)\"\\)$/;\n  const images = [];\n  for (const element of allElements) {\n    const style = window.getComputedStyle(element);\n    if (!style.backgroundImage || !CSS_URL_REGEX.test(style.backgroundImage)) continue;\n    const imageMatch = style.backgroundImage.match(CSS_URL_REGEX);\n    const url = imageMatch[1];\n    images.push({\n      src: url,\n      srcset: \"\",\n      displayedWidth: element.clientWidth,\n      displayedHeight: element.clientHeight,\n      clientRect: getClientRect(element),\n      attributeWidth: null,\n      attributeHeight: null,\n      naturalDimensions: void 0,\n      cssEffectiveRules: void 0,\n      computedStyles: {\n        position: getPosition(element, style),\n        objectFit: \"\",\n        imageRendering: style.getPropertyValue(\"image-rendering\")\n      },\n      isCss: true,\n      isPicture: false,\n      isInShadowDOM: element.getRootNode() instanceof ShadowRoot,\n      // @ts-expect-error - getNodeDetails put into scope via stringification\n      node: getNodeDetails(element)\n    });\n  }\n  return images;\n}\nfunction collectImageElementInfo() {\n  const allElements = getElementsInDocument();\n  return getHTMLImages(allElements).concat(getCSSImages(allElements));\n}\nfunction determineNaturalSize(url) {\n  return new Promise((resolve, reject) => {\n    const img = new Image();\n    img.addEventListener(\"error\", (_) => reject(new Error(\"determineNaturalSize failed img load\")));\n    img.addEventListener(\"load\", () => {\n      resolve({\n        naturalWidth: img.naturalWidth,\n        naturalHeight: img.naturalHeight\n      });\n    });\n    img.src = url;\n  });\n}\nfunction findSizeDeclaration(rule, property) {\n  if (!rule || !rule.cssProperties) return;\n  const definedProp = rule.cssProperties.find(({ name }) => name === property);\n  if (!definedProp) return;\n  return definedProp.value;\n}\nfunction findMostSpecificMatchedCSSRule(matchedCSSRules = [], isDeclarationOfInterest) {\n  let mostSpecificRule;\n  for (let i = matchedCSSRules.length - 1; i >= 0; i--) {\n    if (isDeclarationOfInterest(matchedCSSRules[i].rule.style)) {\n      mostSpecificRule = matchedCSSRules[i].rule;\n      break;\n    }\n  }\n  if (mostSpecificRule) {\n    return {\n      type: \"Regular\",\n      ...mostSpecificRule.style,\n      parentRule: {\n        origin: mostSpecificRule.origin,\n        selectors: mostSpecificRule.selectorList.selectors\n      }\n    };\n  }\n}\nfunction findMostSpecificCSSRule(matchedCSSRules, property) {\n  const isDeclarationofInterest = /* @__PURE__ */ __name((declaration) => findSizeDeclaration(declaration, property), \"isDeclarationofInterest\");\n  const rule = findMostSpecificMatchedCSSRule(matchedCSSRules, isDeclarationofInterest);\n  if (!rule) return;\n  return findSizeDeclaration(rule, property);\n}\nfunction getEffectiveSizingRule({ attributesStyle, inlineStyle, matchedCSSRules }, property) {\n  const inlineRule = findSizeDeclaration(inlineStyle, property);\n  if (inlineRule) return inlineRule;\n  const attributeRule = findSizeDeclaration(attributesStyle, property);\n  if (attributeRule) return attributeRule;\n  const matchedRule = findMostSpecificCSSRule(matchedCSSRules, property);\n  if (matchedRule) return matchedRule;\n  return null;\n}\nfunction getPixelArea(element) {\n  if (element.naturalDimensions) {\n    return element.naturalDimensions.height * element.naturalDimensions.width;\n  }\n  return element.displayedHeight * element.displayedWidth;\n}\nvar ImageElements, image_elements_default;\nvar init_image_elements = __esm({\n  \"core/gather/gatherers/image-elements.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_lighthouse_logger();\n    init_base_gatherer();\n    init_page_functions();\n    /**\n     * @license\n     * Copyright 2017 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    __name(getClientRect, \"getClientRect\");\n    __name(getPosition, \"getPosition\");\n    __name(getHTMLImages, \"getHTMLImages\");\n    __name(getCSSImages, \"getCSSImages\");\n    __name(collectImageElementInfo, \"collectImageElementInfo\");\n    __name(determineNaturalSize, \"determineNaturalSize\");\n    __name(findSizeDeclaration, \"findSizeDeclaration\");\n    __name(findMostSpecificMatchedCSSRule, \"findMostSpecificMatchedCSSRule\");\n    __name(findMostSpecificCSSRule, \"findMostSpecificCSSRule\");\n    __name(getEffectiveSizingRule, \"getEffectiveSizingRule\");\n    __name(getPixelArea, \"getPixelArea\");\n    ImageElements = class extends base_gatherer_default {\n      static {\n        __name(this, \"ImageElements\");\n      }\n      /** @type {LH.Gatherer.GathererMeta} */\n      meta = {\n        supportedModes: [\"snapshot\", \"timespan\", \"navigation\"]\n      };\n      constructor() {\n        super();\n        this._naturalSizeCache = /* @__PURE__ */ new Map();\n      }\n      /**\n       * @param {LH.Gatherer.Driver} driver\n       * @param {LH.Artifacts.ImageElement} element\n       */\n      async fetchElementWithSizeInformation(driver, element) {\n        const url = element.src;\n        let size = this._naturalSizeCache.get(url);\n        if (!size) {\n          try {\n            driver.defaultSession.setNextProtocolTimeout(250);\n            size = await driver.executionContext.evaluate(determineNaturalSize, {\n              args: [url],\n              useIsolation: true\n            });\n            this._naturalSizeCache.set(url, size);\n          } catch (_) {\n          }\n        }\n        if (!size) return;\n        element.naturalDimensions = { width: size.naturalWidth, height: size.naturalHeight };\n      }\n      /**\n       * Images might be sized via CSS. In order to compute unsized-images failures, we need to collect\n       * matched CSS rules to see if this is the case.\n       * @url http://go/dwoqq (googlers only)\n       * @param {LH.Gatherer.ProtocolSession} session\n       * @param {string} devtoolsNodePath\n       * @param {LH.Artifacts.ImageElement} element\n       */\n      async fetchSourceRules(session, devtoolsNodePath, element) {\n        try {\n          const { nodeId } = await session.sendCommand(\"DOM.pushNodeByPathToFrontend\", {\n            path: devtoolsNodePath\n          });\n          if (!nodeId) return;\n          const matchedRules = await session.sendCommand(\"CSS.getMatchedStylesForNode\", {\n            nodeId\n          });\n          const width = getEffectiveSizingRule(matchedRules, \"width\");\n          const height = getEffectiveSizingRule(matchedRules, \"height\");\n          const aspectRatio2 = getEffectiveSizingRule(matchedRules, \"aspect-ratio\");\n          element.cssEffectiveRules = { width, height, aspectRatio: aspectRatio2 };\n        } catch (err) {\n          if (/No node.*found/.test(err.message)) return;\n          throw err;\n        }\n      }\n      /**\n       *\n       * @param {LH.Gatherer.Driver} driver\n       * @param {LH.Artifacts.ImageElement[]} elements\n       */\n      async collectExtraDetails(driver, elements) {\n        let reachedGatheringBudget = false;\n        setTimeout((_) => reachedGatheringBudget = true, 5e3);\n        let skippedCount = 0;\n        for (const element of elements) {\n          if (reachedGatheringBudget) {\n            skippedCount++;\n            continue;\n          }\n          if (!element.isInShadowDOM && !element.isCss) {\n            await this.fetchSourceRules(driver.defaultSession, element.node.devtoolsNodePath, element);\n          }\n          if (element.isPicture || element.isCss || element.srcset) {\n            await this.fetchElementWithSizeInformation(driver, element);\n          }\n        }\n        if (reachedGatheringBudget) {\n          lighthouse_logger_default.warn(\"ImageElements\", `Reached gathering budget of 5s. Skipped extra details for ${skippedCount}/${elements.length}`);\n        }\n      }\n      /**\n       * @param {LH.Gatherer.Context} context\n       * @return {Promise<LH.Artifacts['ImageElements']>}\n       */\n      async getArtifact(context) {\n        const session = context.driver.defaultSession;\n        const executionContext = context.driver.executionContext;\n        const elements = await executionContext.evaluate(collectImageElementInfo, {\n          args: [],\n          useIsolation: true,\n          deps: [\n            pageFunctions.getElementsInDocument,\n            pageFunctions.getBoundingClientRect,\n            pageFunctions.getNodeDetails,\n            getClientRect,\n            getPosition,\n            getHTMLImages,\n            getCSSImages\n          ]\n        });\n        await Promise.all([\n          session.sendCommand(\"DOM.enable\"),\n          session.sendCommand(\"CSS.enable\"),\n          session.sendCommand(\"DOM.getDocument\", { depth: -1, pierce: true })\n        ]);\n        elements.sort((a, b) => getPixelArea(b) - getPixelArea(a));\n        await this.collectExtraDetails(context.driver, elements);\n        await Promise.all([\n          session.sendCommand(\"DOM.disable\"),\n          session.sendCommand(\"CSS.disable\")\n        ]);\n        return elements;\n      }\n    };\n    image_elements_default = ImageElements;\n  }\n});\n\n// core/gather/gatherers/inputs.js\nvar inputs_exports = {};\n__export(inputs_exports, {\n  default: () => inputs_default\n});\nfunction collectElements() {\n  const inputArtifacts = [];\n  const formElToArtifact = /* @__PURE__ */ new Map();\n  const labelElToArtifact = /* @__PURE__ */ new Map();\n  const formEls = getElementsInDocument(\"form\");\n  for (const formEl of formEls) {\n    formElToArtifact.set(formEl, {\n      id: formEl.id,\n      name: formEl.name,\n      autocomplete: formEl.autocomplete,\n      // @ts-expect-error - getNodeDetails put into scope via stringification\n      node: getNodeDetails(formEl)\n    });\n  }\n  const labelEls = getElementsInDocument(\"label\");\n  for (const labelEl of labelEls) {\n    labelElToArtifact.set(labelEl, {\n      for: labelEl.htmlFor,\n      // @ts-expect-error - getNodeDetails put into scope via stringification\n      node: getNodeDetails(labelEl)\n    });\n  }\n  const inputEls = getElementsInDocument(\"textarea, input, select\");\n  for (const inputEl of inputEls) {\n    const parentFormEl = inputEl.form;\n    const parentFormIndex = parentFormEl ? [...formElToArtifact.keys()].indexOf(parentFormEl) : void 0;\n    const labelIndices = [...inputEl.labels || []].map((labelEl) => {\n      return [...labelElToArtifact.keys()].indexOf(labelEl);\n    });\n    let preventsPaste;\n    if (!inputEl.readOnly) {\n      preventsPaste = !inputEl.dispatchEvent(new ClipboardEvent(\"paste\", { cancelable: true }));\n    }\n    inputArtifacts.push({\n      parentFormIndex,\n      labelIndices,\n      id: inputEl.id,\n      name: inputEl.name,\n      type: inputEl.type,\n      placeholder: inputEl instanceof HTMLSelectElement ? void 0 : inputEl.placeholder,\n      autocomplete: {\n        property: inputEl.autocomplete,\n        attribute: inputEl.getAttribute(\"autocomplete\"),\n        // Requires `--enable-features=AutofillShowTypePredictions`.\n        prediction: inputEl.getAttribute(\"autofill-prediction\")\n      },\n      preventsPaste,\n      // @ts-expect-error - getNodeDetails put into scope via stringification\n      node: getNodeDetails(inputEl)\n    });\n  }\n  return {\n    inputs: inputArtifacts,\n    forms: [...formElToArtifact.values()],\n    labels: [...labelElToArtifact.values()]\n  };\n}\nvar Inputs, inputs_default;\nvar init_inputs = __esm({\n  \"core/gather/gatherers/inputs.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_base_gatherer();\n    init_page_functions();\n    /**\n     * @license\n     * Copyright 2020 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    __name(collectElements, \"collectElements\");\n    Inputs = class extends base_gatherer_default {\n      static {\n        __name(this, \"Inputs\");\n      }\n      /** @type {LH.Gatherer.GathererMeta} */\n      meta = {\n        supportedModes: [\"snapshot\", \"navigation\"]\n      };\n      /**\n       * @param {LH.Gatherer.Context} passContext\n       * @return {Promise<LH.Artifacts['Inputs']>}\n       */\n      async getArtifact(passContext) {\n        return passContext.driver.executionContext.evaluate(collectElements, {\n          args: [],\n          useIsolation: true,\n          deps: [\n            pageFunctions.getElementsInDocument,\n            pageFunctions.getNodeDetails\n          ]\n        });\n      }\n    };\n    inputs_default = Inputs;\n  }\n});\n\n// core/gather/gatherers/inspector-issues.js\nvar inspector_issues_exports = {};\n__export(inspector_issues_exports, {\n  default: () => inspector_issues_default\n});\nvar InspectorIssues, inspector_issues_default;\nvar init_inspector_issues = __esm({\n  \"core/gather/gatherers/inspector-issues.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_base_gatherer();\n    init_network_records();\n    init_devtools_log();\n    /**\n     * @license\n     * Copyright 2020 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    InspectorIssues = class extends base_gatherer_default {\n      static {\n        __name(this, \"InspectorIssues\");\n      }\n      /** @type {LH.Gatherer.GathererMeta<'DevtoolsLog'>} */\n      meta = {\n        supportedModes: [\"timespan\", \"navigation\"],\n        dependencies: { DevtoolsLog: devtools_log_default.symbol }\n      };\n      constructor() {\n        super();\n        this._issues = [];\n        this._onIssueAdded = this.onIssueAdded.bind(this);\n      }\n      /**\n       * @param {LH.Crdp.Audits.IssueAddedEvent} entry\n       */\n      onIssueAdded(entry) {\n        this._issues.push(entry.issue);\n      }\n      /**\n       * @param {LH.Gatherer.Context} context\n       */\n      async startInstrumentation(context) {\n        const session = context.driver.defaultSession;\n        session.on(\"Audits.issueAdded\", this._onIssueAdded);\n        await session.sendCommand(\"Audits.enable\");\n      }\n      /**\n       * @param {LH.Gatherer.Context} context\n       */\n      async stopInstrumentation(context) {\n        const session = context.driver.defaultSession;\n        session.off(\"Audits.issueAdded\", this._onIssueAdded);\n        await session.sendCommand(\"Audits.disable\");\n      }\n      /**\n       * @param {LH.Gatherer.Context<'DevtoolsLog'>} context\n       * @return {Promise<LH.Artifacts.InspectorIssues>}\n       */\n      async getArtifact(context) {\n        const devtoolsLog = context.dependencies.DevtoolsLog;\n        const networkRecords = await NetworkRecordsComputed.request(devtoolsLog, context);\n        const artifact = {};\n        for (const issue of this._issues) {\n          const detailsKey = (\n            /** @type {keyof LH.Crdp.Audits.InspectorIssueDetails} */\n            Object.keys(issue.details)[0]\n          );\n          const details = issue.details[detailsKey];\n          if (!details) {\n            continue;\n          }\n          const artifactKey = (\n            /** @type {LH.Artifacts.InspectorIssuesKeyToArtifactKey<typeof detailsKey>} */\n            detailsKey.replace(\"Details\", \"\")\n          );\n          const requestId = \"request\" in details && details.request && details.request.requestId;\n          if (requestId) {\n            if (networkRecords.find((req) => req.requestId === requestId)) {\n              if (!artifact[artifactKey]) {\n                artifact[artifactKey] = [];\n              }\n              artifact[artifactKey].push(details);\n            }\n          } else {\n            if (!artifact[artifactKey]) {\n              artifact[artifactKey] = [];\n            }\n            artifact[artifactKey].push(details);\n          }\n        }\n        return artifact;\n      }\n    };\n    inspector_issues_default = InspectorIssues;\n  }\n});\n\n// node_modules/http-link-header/lib/link.js\nvar require_link = __commonJS({\n  \"node_modules/http-link-header/lib/link.js\"(exports2, module2) {\n    \"use strict\";\n    init_process_global();\n    var COMPATIBLE_ENCODING_PATTERN = /^utf-?8|ascii|utf-?16-?le|ucs-?2|base-?64|latin-?1$/i;\n    var WS_TRIM_PATTERN = /^[\\s\\uFEFF\\xA0]+|[\\s\\uFEFF\\xA0]+$/g;\n    var WS_CHAR_PATTERN = /\\s|\\uFEFF|\\xA0/;\n    var WS_FOLD_PATTERN = /\\r?\\n[\\x20\\x09]+/g;\n    var DELIMITER_PATTERN = /[;,\"]/;\n    var WS_DELIMITER_PATTERN = /[;,\"]|\\s/;\n    var TOKEN_PATTERN = /^[!#$%&'*+\\-\\.^_`|~\\da-zA-Z]+$/;\n    var STATE = {\n      IDLE: 1 << 0,\n      URI: 1 << 1,\n      ATTR: 1 << 2\n    };\n    function trim(value) {\n      return value.replace(WS_TRIM_PATTERN, \"\");\n    }\n    __name(trim, \"trim\");\n    function hasWhitespace(value) {\n      return WS_CHAR_PATTERN.test(value);\n    }\n    __name(hasWhitespace, \"hasWhitespace\");\n    function skipWhitespace(value, offset) {\n      while (hasWhitespace(value[offset])) {\n        offset++;\n      }\n      return offset;\n    }\n    __name(skipWhitespace, \"skipWhitespace\");\n    function needsQuotes(value) {\n      return WS_DELIMITER_PATTERN.test(value) || !TOKEN_PATTERN.test(value);\n    }\n    __name(needsQuotes, \"needsQuotes\");\n    function shallowCompareObjects(object1, object2) {\n      return Object.keys(object1).length === Object.keys(object2).length && Object.keys(object1).every(\n        (key) => key in object2 && object1[key] === object2[key]\n      );\n    }\n    __name(shallowCompareObjects, \"shallowCompareObjects\");\n    var Link = class _Link {\n      static {\n        __name(this, \"Link\");\n      }\n      /**\n       * Link\n       * @constructor\n       * @param {String} [value]\n       * @returns {Link}\n       */\n      constructor(value) {\n        this.refs = [];\n        if (value) {\n          this.parse(value);\n        }\n      }\n      /**\n       * Get refs with given relation type\n       * @param {String} value\n       * @returns {Array<Object>}\n       */\n      rel(value) {\n        var links = [];\n        var type = value.toLowerCase();\n        for (var i = 0; i < this.refs.length; i++) {\n          if (this.refs[i].rel.toLowerCase() === type) {\n            links.push(this.refs[i]);\n          }\n        }\n        return links;\n      }\n      /**\n       * Get refs where given attribute has a given value\n       * @param {String} attr\n       * @param {String} value\n       * @returns {Array<Object>}\n       */\n      get(attr, value) {\n        attr = attr.toLowerCase();\n        var links = [];\n        for (var i = 0; i < this.refs.length; i++) {\n          if (this.refs[i][attr] === value) {\n            links.push(this.refs[i]);\n          }\n        }\n        return links;\n      }\n      /** Sets a reference. */\n      set(link) {\n        this.refs.push(link);\n        return this;\n      }\n      /**\n       * Sets a reference if a reference with similar properties isn’t already set.\n       */\n      setUnique(link) {\n        if (!this.refs.some((ref) => shallowCompareObjects(ref, link))) {\n          this.refs.push(link);\n        }\n        return this;\n      }\n      has(attr, value) {\n        attr = attr.toLowerCase();\n        for (var i = 0; i < this.refs.length; i++) {\n          if (this.refs[i][attr] === value) {\n            return true;\n          }\n        }\n        return false;\n      }\n      parse(value, offset) {\n        offset = offset || 0;\n        value = offset ? value.slice(offset) : value;\n        value = trim(value).replace(WS_FOLD_PATTERN, \"\");\n        var state = STATE.IDLE;\n        var length = value.length;\n        var offset = 0;\n        var ref = null;\n        while (offset < length) {\n          if (state === STATE.IDLE) {\n            if (hasWhitespace(value[offset])) {\n              offset++;\n              continue;\n            } else if (value[offset] === \"<\") {\n              if (ref != null) {\n                ref.rel != null ? this.refs.push(..._Link.expandRelations(ref)) : this.refs.push(ref);\n              }\n              var end = value.indexOf(\">\", offset);\n              if (end === -1) throw new Error(\"Expected end of URI delimiter at offset \" + offset);\n              ref = { uri: value.slice(offset + 1, end) };\n              offset = end;\n              state = STATE.URI;\n            } else {\n              throw new Error('Unexpected character \"' + value[offset] + '\" at offset ' + offset);\n            }\n            offset++;\n          } else if (state === STATE.URI) {\n            if (hasWhitespace(value[offset])) {\n              offset++;\n              continue;\n            } else if (value[offset] === \";\") {\n              state = STATE.ATTR;\n              offset++;\n            } else if (value[offset] === \",\") {\n              state = STATE.IDLE;\n              offset++;\n            } else {\n              throw new Error('Unexpected character \"' + value[offset] + '\" at offset ' + offset);\n            }\n          } else if (state === STATE.ATTR) {\n            if (value[offset] === \";\" || hasWhitespace(value[offset])) {\n              offset++;\n              continue;\n            }\n            var end = value.indexOf(\"=\", offset);\n            if (end === -1) end = value.indexOf(\";\", offset);\n            if (end === -1) end = value.length;\n            var attr = trim(value.slice(offset, end)).toLowerCase();\n            var attrValue = \"\";\n            offset = end + 1;\n            offset = skipWhitespace(value, offset);\n            if (value[offset] === '\"') {\n              offset++;\n              while (offset < length) {\n                if (value[offset] === '\"') {\n                  offset++;\n                  break;\n                }\n                if (value[offset] === \"\\\\\") {\n                  offset++;\n                }\n                attrValue += value[offset];\n                offset++;\n              }\n            } else {\n              var end = offset + 1;\n              while (!DELIMITER_PATTERN.test(value[end]) && end < length) {\n                end++;\n              }\n              attrValue = value.slice(offset, end);\n              offset = end;\n            }\n            if (ref[attr] && _Link.isSingleOccurenceAttr(attr)) {\n            } else if (attr[attr.length - 1] === \"*\") {\n              ref[attr] = _Link.parseExtendedValue(attrValue);\n            } else {\n              attrValue = attr === \"type\" ? attrValue.toLowerCase() : attrValue;\n              if (ref[attr] != null) {\n                if (Array.isArray(ref[attr])) {\n                  ref[attr].push(attrValue);\n                } else {\n                  ref[attr] = [ref[attr], attrValue];\n                }\n              } else {\n                ref[attr] = attrValue;\n              }\n            }\n            switch (value[offset]) {\n              case \",\":\n                state = STATE.IDLE;\n                break;\n              case \";\":\n                state = STATE.ATTR;\n                break;\n            }\n            offset++;\n          } else {\n            throw new Error('Unknown parser state \"' + state + '\"');\n          }\n        }\n        if (ref != null) {\n          ref.rel != null ? this.refs.push(..._Link.expandRelations(ref)) : this.refs.push(ref);\n        }\n        ref = null;\n        return this;\n      }\n      toString() {\n        var refs = [];\n        var link = \"\";\n        var ref = null;\n        for (var i = 0; i < this.refs.length; i++) {\n          ref = this.refs[i];\n          link = Object.keys(this.refs[i]).reduce(function(link2, attr) {\n            if (attr === \"uri\") return link2;\n            return link2 + \"; \" + _Link.formatAttribute(attr, ref[attr]);\n          }, \"<\" + ref.uri + \">\");\n          refs.push(link);\n        }\n        return refs.join(\", \");\n      }\n    };\n    Link.isCompatibleEncoding = function(value) {\n      return COMPATIBLE_ENCODING_PATTERN.test(value);\n    };\n    Link.parse = function(value, offset) {\n      return new Link().parse(value, offset);\n    };\n    Link.isSingleOccurenceAttr = function(attr) {\n      return attr === \"rel\" || attr === \"type\" || attr === \"media\" || attr === \"title\" || attr === \"title*\";\n    };\n    Link.isTokenAttr = function(attr) {\n      return attr === \"rel\" || attr === \"type\" || attr === \"anchor\";\n    };\n    Link.escapeQuotes = function(value) {\n      return value.replace(/\"/g, '\\\\\"');\n    };\n    Link.expandRelations = function(ref) {\n      var rels = ref.rel.split(\" \");\n      return rels.map(function(rel) {\n        var value = Object.assign({}, ref);\n        value.rel = rel;\n        return value;\n      });\n    };\n    Link.parseExtendedValue = function(value) {\n      var parts = /([^']+)?(?:'([^']*)')?(.+)/.exec(value);\n      return {\n        language: parts[2].toLowerCase(),\n        encoding: Link.isCompatibleEncoding(parts[1]) ? null : parts[1].toLowerCase(),\n        value: Link.isCompatibleEncoding(parts[1]) ? decodeURIComponent(parts[3]) : parts[3]\n      };\n    };\n    Link.formatExtendedAttribute = function(attr, data31) {\n      var encoding = (data31.encoding || \"utf-8\").toUpperCase();\n      var language = data31.language || \"en\";\n      var encodedValue = \"\";\n      if (Buffer.isBuffer(data31.value) && Link.isCompatibleEncoding(encoding)) {\n        encodedValue = data31.value.toString(encoding);\n      } else if (Buffer.isBuffer(data31.value)) {\n        encodedValue = data31.value.toString(\"hex\").replace(/[0-9a-f]{2}/gi, \"%$1\");\n      } else {\n        encodedValue = encodeURIComponent(data31.value);\n      }\n      return attr + \"=\" + encoding + \"'\" + language + \"'\" + encodedValue;\n    };\n    Link.formatAttribute = function(attr, value) {\n      if (Array.isArray(value)) {\n        return value.map((item) => {\n          return Link.formatAttribute(attr, item);\n        }).join(\"; \");\n      }\n      if (attr[attr.length - 1] === \"*\" || typeof value !== \"string\") {\n        return Link.formatExtendedAttribute(attr, value);\n      }\n      if (Link.isTokenAttr(attr)) {\n        value = needsQuotes(value) ? '\"' + Link.escapeQuotes(value) + '\"' : Link.escapeQuotes(value);\n      } else if (needsQuotes(value)) {\n        value = encodeURIComponent(value);\n        value = value.replace(/%20/g, \" \").replace(/%2C/g, \",\").replace(/%3B/g, \";\");\n        value = '\"' + value + '\"';\n      }\n      return attr + \"=\" + value;\n    };\n    module2.exports = Link;\n  }\n});\n\n// core/computed/main-resource.js\nvar MainResource, MainResourceComputed;\nvar init_main_resource = __esm({\n  \"core/computed/main-resource.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_lantern2();\n    init_computed_artifact();\n    init_network_records();\n    /**\n     * @license\n     * Copyright 2017 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    MainResource = class {\n      static {\n        __name(this, \"MainResource\");\n      }\n      /**\n       * @param {{URL: LH.Artifacts['URL'], devtoolsLog: LH.DevtoolsLog}} data\n       * @param {LH.Artifacts.ComputedContext} context\n       * @return {Promise<LH.Artifacts.NetworkRequest>}\n       */\n      static async compute_(data31, context) {\n        const { mainDocumentUrl } = data31.URL;\n        if (!mainDocumentUrl) throw new Error(\"mainDocumentUrl must exist to get the main resource\");\n        const records = await NetworkRecordsComputed.request(data31.devtoolsLog, context);\n        const mainResource = core_exports.NetworkAnalyzer.findLastDocumentForUrl(records, mainDocumentUrl);\n        if (!mainResource) {\n          throw new Error(\"Unable to identify the main resource\");\n        }\n        return mainResource;\n      }\n    };\n    MainResourceComputed = makeComputedArtifact(MainResource, [\"URL\", \"devtoolsLog\"]);\n  }\n});\n\n// core/gather/gatherers/link-elements.js\nvar link_elements_exports = {};\n__export(link_elements_exports, {\n  UIStrings: () => UIStrings22,\n  default: () => link_elements_default\n});\nfunction normalizeUrlOrNull(url, finalDisplayedUrl) {\n  try {\n    return new URL(url, finalDisplayedUrl).href;\n  } catch (_) {\n    return null;\n  }\n}\nfunction getCrossoriginFromHeader(value) {\n  if (value === \"anonymous\") return \"anonymous\";\n  if (value === \"use-credentials\") return \"use-credentials\";\n  return null;\n}\nfunction getLinkElementsInDOM() {\n  const browserElements = getElementsInDocument(\"link\");\n  const linkElements = [];\n  for (const link of browserElements) {\n    if (!(link instanceof HTMLLinkElement)) continue;\n    const hrefRaw = link.getAttribute(\"href\") || \"\";\n    const source = link.closest(\"head\") ? \"head\" : \"body\";\n    linkElements.push({\n      rel: link.rel,\n      href: link.href,\n      hreflang: link.hreflang,\n      as: link.as,\n      crossOrigin: link.crossOrigin,\n      hrefRaw,\n      source,\n      fetchPriority: link.fetchPriority,\n      // @ts-expect-error - put into scope via stringification\n      node: getNodeDetails(link)\n    });\n  }\n  return linkElements;\n}\nvar import_http_link_header, UIStrings22, str_3, LinkElements, link_elements_default;\nvar init_link_elements = __esm({\n  \"core/gather/gatherers/link-elements.js\"() {\n    \"use strict\";\n    init_process_global();\n    import_http_link_header = __toESM(require_link(), 1);\n    init_base_gatherer();\n    init_page_functions();\n    init_devtools_log();\n    init_main_resource();\n    init_util();\n    init_i18n();\n    /**\n     * @license\n     * Copyright 2018 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    UIStrings22 = {\n      /**\n       * @description Warning message explaining that there was an error parsing a link header in an HTTP response. `error` will be an english string with more details on the error. `header` will be the value of the header that caused the error. `link` is a type of HTTP header and should not be translated.\n       * @example {Expected attribute delimiter at offset 94} error\n       * @example {<https://assets.calendly.com/assets/booking/css/booking-d0ac32b1.css>; rel=preload; as=style; nopush} error\n       */\n      headerParseWarning: \"Error parsing `link` header ({error}): `{header}`\"\n    };\n    str_3 = createIcuMessageFn({ url: \"core/gather/gatherers/link-elements.js\" }.url, UIStrings22);\n    __name(normalizeUrlOrNull, \"normalizeUrlOrNull\");\n    __name(getCrossoriginFromHeader, \"getCrossoriginFromHeader\");\n    __name(getLinkElementsInDOM, \"getLinkElementsInDOM\");\n    LinkElements = class _LinkElements extends base_gatherer_default {\n      static {\n        __name(this, \"LinkElements\");\n      }\n      /** @type {LH.Gatherer.GathererMeta<'DevtoolsLog'>} */\n      meta = {\n        supportedModes: [\"timespan\", \"navigation\"],\n        dependencies: { DevtoolsLog: devtools_log_default.symbol }\n      };\n      /**\n       * @param {LH.Gatherer.Context} context\n       * @return {Promise<LH.Artifacts['LinkElements']>}\n       */\n      static getLinkElementsInDOM(context) {\n        return context.driver.executionContext.evaluate(getLinkElementsInDOM, {\n          args: [],\n          useIsolation: true,\n          deps: [\n            pageFunctions.getNodeDetails,\n            pageFunctions.getElementsInDocument\n          ]\n        });\n      }\n      /**\n       * @param {LH.Gatherer.Context} context\n       * @param {LH.Artifacts['DevtoolsLog']} devtoolsLog\n       * @return {Promise<LH.Artifacts['LinkElements']>}\n       */\n      static async getLinkElementsInHeaders(context, devtoolsLog) {\n        const mainDocument = await MainResourceComputed.request({ devtoolsLog, URL: context.baseArtifacts.URL }, context);\n        const linkElements = [];\n        for (const header of mainDocument.responseHeaders) {\n          if (header.name.toLowerCase() !== \"link\") continue;\n          let parsedRefs = [];\n          try {\n            parsedRefs = import_http_link_header.default.parse(header.value).refs;\n          } catch (err) {\n            const truncatedHeader = Util.truncate(header.value, 100);\n            const warning = str_3(UIStrings22.headerParseWarning, {\n              error: err.message,\n              header: truncatedHeader\n            });\n            context.baseArtifacts.LighthouseRunWarnings.push(warning);\n          }\n          for (const link of parsedRefs) {\n            linkElements.push({\n              rel: link.rel || \"\",\n              href: normalizeUrlOrNull(link.uri, context.baseArtifacts.URL.finalDisplayedUrl),\n              hrefRaw: link.uri || \"\",\n              hreflang: link.hreflang || \"\",\n              as: link.as || \"\",\n              crossOrigin: getCrossoriginFromHeader(link.crossorigin),\n              source: \"headers\",\n              fetchPriority: link.fetchpriority,\n              node: null\n            });\n          }\n        }\n        return linkElements;\n      }\n      /**\n       * @param {LH.Gatherer.Context<'DevtoolsLog'>} context\n       * @return {Promise<LH.Artifacts['LinkElements']>}\n       */\n      async getArtifact(context) {\n        const devtoolsLog = context.dependencies.DevtoolsLog;\n        const fromDOM = await _LinkElements.getLinkElementsInDOM(context);\n        const fromHeaders = await _LinkElements.getLinkElementsInHeaders(context, devtoolsLog);\n        const linkElements = fromDOM.concat(fromHeaders);\n        for (const link of linkElements) {\n          link.rel = link.rel.toLowerCase();\n        }\n        return linkElements;\n      }\n    };\n    link_elements_default = LinkElements;\n  }\n});\n\n// core/gather/driver/network.js\nasync function fetchResponseBodyFromCache(session, requestId, timeout = 1e3) {\n  requestId = NetworkRequest.getRequestIdForBackend(requestId);\n  session.setNextProtocolTimeout(timeout);\n  const result = await session.sendCommand(\"Network.getResponseBody\", { requestId });\n  return result.body;\n}\nvar init_network = __esm({\n  \"core/gather/driver/network.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_network_request();\n    /**\n     * @license\n     * Copyright 2021 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    __name(fetchResponseBodyFromCache, \"fetchResponseBodyFromCache\");\n  }\n});\n\n// core/gather/gatherers/main-document-content.js\nvar main_document_content_exports = {};\n__export(main_document_content_exports, {\n  default: () => main_document_content_default\n});\nvar MainDocumentContent, main_document_content_default;\nvar init_main_document_content = __esm({\n  \"core/gather/gatherers/main-document-content.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_base_gatherer();\n    init_devtools_log();\n    init_network();\n    init_main_resource();\n    /**\n     * @license\n     * Copyright 2019 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    MainDocumentContent = class extends base_gatherer_default {\n      static {\n        __name(this, \"MainDocumentContent\");\n      }\n      /** @type {LH.Gatherer.GathererMeta<'DevtoolsLog'>} */\n      meta = {\n        supportedModes: [\"navigation\"],\n        dependencies: { DevtoolsLog: devtools_log_default.symbol }\n      };\n      /**\n       * @param {LH.Gatherer.Context<'DevtoolsLog'>} context\n       * @return {Promise<LH.Artifacts['MainDocumentContent']>}\n       */\n      async getArtifact(context) {\n        const devtoolsLog = context.dependencies.DevtoolsLog;\n        const mainResource = await MainResourceComputed.request({ devtoolsLog, URL: context.baseArtifacts.URL }, context);\n        const session = context.driver.defaultSession;\n        return fetchResponseBodyFromCache(session, mainResource.requestId);\n      }\n    };\n    main_document_content_default = MainDocumentContent;\n  }\n});\n\n// core/gather/gatherers/meta-elements.js\nvar meta_elements_exports = {};\n__export(meta_elements_exports, {\n  default: () => meta_elements_default\n});\nfunction collectMetaElements() {\n  const functions = (\n    /** @type {typeof pageFunctions} */\n    {\n      // @ts-expect-error - getElementsInDocument put into scope via stringification\n      getElementsInDocument,\n      // @ts-expect-error - getNodeDetails put into scope via stringification\n      getNodeDetails\n    }\n  );\n  const metas = functions.getElementsInDocument(\"head meta\");\n  return metas.map((meta) => {\n    const getAttribute = /* @__PURE__ */ __name((name) => {\n      const attr = meta.attributes.getNamedItem(name);\n      if (!attr) return;\n      return attr.value;\n    }, \"getAttribute\");\n    return {\n      name: meta.name.toLowerCase(),\n      content: meta.content,\n      property: getAttribute(\"property\"),\n      httpEquiv: meta.httpEquiv ? meta.httpEquiv.toLowerCase() : void 0,\n      charset: getAttribute(\"charset\"),\n      node: functions.getNodeDetails(meta)\n    };\n  });\n}\nvar MetaElements, meta_elements_default;\nvar init_meta_elements = __esm({\n  \"core/gather/gatherers/meta-elements.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_base_gatherer();\n    init_page_functions();\n    /**\n     * @license\n     * Copyright 2019 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    __name(collectMetaElements, \"collectMetaElements\");\n    MetaElements = class extends base_gatherer_default {\n      static {\n        __name(this, \"MetaElements\");\n      }\n      /** @type {LH.Gatherer.GathererMeta} */\n      meta = {\n        supportedModes: [\"snapshot\", \"navigation\"]\n      };\n      /**\n       * @param {LH.Gatherer.Context} passContext\n       * @return {Promise<LH.Artifacts['MetaElements']>}\n       */\n      getArtifact(passContext) {\n        const driver = passContext.driver;\n        return driver.executionContext.evaluate(collectMetaElements, {\n          args: [],\n          useIsolation: true,\n          deps: [\n            pageFunctions.getElementsInDocument,\n            pageFunctions.getNodeDetails\n          ]\n        });\n      }\n    };\n    meta_elements_default = MetaElements;\n  }\n});\n\n// core/gather/gatherers/scripts.js\nvar scripts_exports = {};\n__export(scripts_exports, {\n  default: () => scripts_default\n});\nasync function runInSeriesOrParallel(values, promiseMapper, runInSeries) {\n  if (runInSeries) {\n    const results = [];\n    for (const value of values) {\n      const result = await promiseMapper(value);\n      results.push(result);\n    }\n    return results;\n  } else {\n    const promises = values.map(promiseMapper);\n    return await Promise.all(promises);\n  }\n}\nfunction isLighthouseRuntimeEvaluateScript(script) {\n  if (!script.embedderName) return true;\n  return script.hasSourceURL && script.url === \"_lighthouse-eval.js\";\n}\nvar Scripts, scripts_default;\nvar init_scripts = __esm({\n  \"core/gather/gatherers/scripts.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_base_gatherer();\n    /**\n     * @license\n     * Copyright 2022 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    __name(runInSeriesOrParallel, \"runInSeriesOrParallel\");\n    __name(isLighthouseRuntimeEvaluateScript, \"isLighthouseRuntimeEvaluateScript\");\n    Scripts = class _Scripts extends base_gatherer_default {\n      static {\n        __name(this, \"Scripts\");\n      }\n      static symbol = Symbol(\"Scripts\");\n      /** @type {LH.Gatherer.GathererMeta} */\n      meta = {\n        symbol: _Scripts.symbol,\n        supportedModes: [\"timespan\", \"navigation\"]\n      };\n      /** @type {LH.Crdp.Debugger.ScriptParsedEvent[]} */\n      _scriptParsedEvents = [];\n      /** @type {Array<string | undefined>} */\n      _scriptContents = [];\n      constructor() {\n        super();\n        this.onScriptParsed = this.onScriptParsed.bind(this);\n      }\n      /**\n       * @param {LH.Crdp.Debugger.ScriptParsedEvent} params\n       */\n      onScriptParsed(params) {\n        if (!isLighthouseRuntimeEvaluateScript(params)) {\n          this._scriptParsedEvents.push(params);\n        }\n      }\n      /**\n       * @param {LH.Gatherer.Context} context\n       */\n      async startInstrumentation(context) {\n        const session = context.driver.defaultSession;\n        session.on(\"Debugger.scriptParsed\", this.onScriptParsed);\n        await session.sendCommand(\"Debugger.enable\");\n      }\n      /**\n       * @param {LH.Gatherer.Context} context\n       */\n      async stopInstrumentation(context) {\n        const session = context.driver.defaultSession;\n        const formFactor = context.baseArtifacts.HostFormFactor;\n        session.off(\"Debugger.scriptParsed\", this.onScriptParsed);\n        this._scriptContents = await runInSeriesOrParallel(\n          this._scriptParsedEvents,\n          ({ scriptId }) => {\n            return session.sendCommand(\"Debugger.getScriptSource\", { scriptId }).then((resp) => resp.scriptSource).catch(() => void 0);\n          },\n          formFactor === \"mobile\"\n          /* runInSeries */\n        );\n        await session.sendCommand(\"Debugger.disable\");\n      }\n      async getArtifact() {\n        const scripts = this._scriptParsedEvents.map((event, i) => {\n          return {\n            name: event.url,\n            ...event,\n            // embedderName is optional on the protocol because backends like Node may not set it.\n            // For our purposes, it is always set. But just in case it isn't... fallback to the url.\n            url: event.embedderName || event.url,\n            content: this._scriptContents[i]\n          };\n        });\n        return scripts;\n      }\n    };\n    scripts_default = Scripts;\n  }\n});\n\n// core/gather/gatherers/seo/robots-txt.js\nvar robots_txt_exports = {};\n__export(robots_txt_exports, {\n  default: () => robots_txt_default\n});\nvar RobotsTxt, robots_txt_default;\nvar init_robots_txt = __esm({\n  \"core/gather/gatherers/seo/robots-txt.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_base_gatherer();\n    /**\n     * @license\n     * Copyright 2018 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    RobotsTxt = class extends base_gatherer_default {\n      static {\n        __name(this, \"RobotsTxt\");\n      }\n      /** @type {LH.Gatherer.GathererMeta} */\n      meta = {\n        supportedModes: [\"snapshot\", \"navigation\"]\n      };\n      /**\n       * @param {LH.Gatherer.Context} passContext\n       * @return {Promise<LH.Artifacts['RobotsTxt']>}\n       */\n      async getArtifact(passContext) {\n        const { finalDisplayedUrl } = passContext.baseArtifacts.URL;\n        const robotsUrl = new URL(\"/robots.txt\", finalDisplayedUrl).href;\n        return passContext.driver.fetcher.fetchResource(robotsUrl).catch((err) => ({ status: null, content: null, errorMessage: err.message }));\n      }\n    };\n    robots_txt_default = RobotsTxt;\n  }\n});\n\n// core/lib/cdt/generated/ParsedURL.js\nvar require_ParsedURL = __commonJS({\n  \"core/lib/cdt/generated/ParsedURL.js\"(exports2) {\n    \"use strict\";\n    init_process_global();\n    Object.defineProperty(exports2, \"__esModule\", { value: true });\n    exports2.ParsedURL = void 0;\n    exports2.normalizePath = normalizePath2;\n    exports2.schemeIs = schemeIs2;\n    function normalizePath2(path7) {\n      if (path7.indexOf(\"..\") === -1 && path7.indexOf(\".\") === -1) {\n        return path7;\n      }\n      const segments = (path7[0] === \"/\" ? path7.substring(1) : path7).split(\"/\");\n      const normalizedSegments = [];\n      for (const segment of segments) {\n        if (segment === \".\") {\n          continue;\n        } else if (segment === \"..\") {\n          normalizedSegments.pop();\n        } else {\n          normalizedSegments.push(segment);\n        }\n      }\n      let normalizedPath = normalizedSegments.join(\"/\");\n      if (path7[0] === \"/\" && normalizedPath) {\n        normalizedPath = \"/\" + normalizedPath;\n      }\n      if (normalizedPath[normalizedPath.length - 1] !== \"/\" && (path7[path7.length - 1] === \"/\" || segments[segments.length - 1] === \".\" || segments[segments.length - 1] === \"..\")) {\n        normalizedPath = normalizedPath + \"/\";\n      }\n      return normalizedPath;\n    }\n    __name(normalizePath2, \"normalizePath\");\n    function schemeIs2(url, scheme) {\n      try {\n        return new URL(url).protocol === scheme;\n      } catch {\n        return false;\n      }\n    }\n    __name(schemeIs2, \"schemeIs\");\n    var ParsedURL3 = class _ParsedURL {\n      static {\n        __name(this, \"ParsedURL\");\n      }\n      isValid;\n      url;\n      scheme;\n      user;\n      host;\n      port;\n      path;\n      queryParams;\n      fragment;\n      folderPathComponents;\n      lastPathComponent;\n      blobInnerScheme;\n      #displayNameInternal;\n      #dataURLDisplayNameInternal;\n      constructor(url) {\n        this.isValid = false;\n        this.url = url;\n        this.scheme = \"\";\n        this.user = \"\";\n        this.host = \"\";\n        this.port = \"\";\n        this.path = \"\";\n        this.queryParams = \"\";\n        this.fragment = \"\";\n        this.folderPathComponents = \"\";\n        this.lastPathComponent = \"\";\n        const isBlobUrl = this.url.startsWith(\"blob:\");\n        const urlToMatch = isBlobUrl ? url.substring(5) : url;\n        const match = urlToMatch.match(_ParsedURL.urlRegex());\n        if (match) {\n          this.isValid = true;\n          if (isBlobUrl) {\n            this.blobInnerScheme = match[2].toLowerCase();\n            this.scheme = \"blob\";\n          } else {\n            this.scheme = match[2].toLowerCase();\n          }\n          this.user = match[3] ?? \"\";\n          this.host = match[4] ?? \"\";\n          this.port = match[5] ?? \"\";\n          this.path = match[6] ?? \"/\";\n          this.queryParams = match[7] ?? \"\";\n          this.fragment = match[8] ?? \"\";\n        } else {\n          if (this.url.startsWith(\"data:\")) {\n            this.scheme = \"data\";\n            return;\n          }\n          if (this.url.startsWith(\"blob:\")) {\n            this.scheme = \"blob\";\n            return;\n          }\n          if (this.url === \"about:blank\") {\n            this.scheme = \"about\";\n            return;\n          }\n          this.path = this.url;\n        }\n        const lastSlashExceptTrailingIndex = this.path.lastIndexOf(\"/\", this.path.length - 2);\n        if (lastSlashExceptTrailingIndex !== -1) {\n          this.lastPathComponent = this.path.substring(lastSlashExceptTrailingIndex + 1);\n        } else {\n          this.lastPathComponent = this.path;\n        }\n        const lastSlashIndex = this.path.lastIndexOf(\"/\");\n        if (lastSlashIndex !== -1) {\n          this.folderPathComponents = this.path.substring(0, lastSlashIndex);\n        }\n      }\n      static concatenate(devToolsPath, ...appendage) {\n        return devToolsPath.concat(...appendage);\n      }\n      static beginsWithWindowsDriveLetter(url) {\n        return /^[A-Za-z]:/.test(url);\n      }\n      static beginsWithScheme(url) {\n        return /^[A-Za-z][A-Za-z0-9+.-]*:/.test(url);\n      }\n      static isRelativeURL(url) {\n        return !this.beginsWithScheme(url) || this.beginsWithWindowsDriveLetter(url);\n      }\n      get displayName() {\n        if (this.#displayNameInternal) {\n          return this.#displayNameInternal;\n        }\n        if (this.isDataURL()) {\n          return this.dataURLDisplayName();\n        }\n        if (this.isBlobURL()) {\n          return this.url;\n        }\n        if (this.isAboutBlank()) {\n          return this.url;\n        }\n        this.#displayNameInternal = this.lastPathComponent;\n        if (!this.#displayNameInternal) {\n          this.#displayNameInternal = (this.host || \"\") + \"/\";\n        }\n        if (this.#displayNameInternal === \"/\") {\n          this.#displayNameInternal = this.url;\n        }\n        return this.#displayNameInternal;\n      }\n      static urlRegexInstance = null;\n    };\n    exports2.ParsedURL = ParsedURL3;\n  }\n});\n\n// core/lib/cdt/Common.js\nvar require_Common = __commonJS({\n  \"core/lib/cdt/Common.js\"(exports2, module2) {\n    \"use strict\";\n    init_process_global();\n    /**\n     * @license\n     * Copyright 2022 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    var ParsedURL3 = require_ParsedURL();\n    module2.exports = {\n      ParsedURL: ParsedURL3\n    };\n  }\n});\n\n// core/lib/cdt/Platform.js\nvar require_Platform = __commonJS({\n  \"core/lib/cdt/Platform.js\"(exports2, module2) {\n    \"use strict\";\n    init_process_global();\n    /**\n     * @license\n     * Copyright 2021 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    function lowerBound2(array, needle, comparator, left, right) {\n      let l = left || 0;\n      let r = right !== void 0 ? right : array.length;\n      while (l < r) {\n        const m = l + r >> 1;\n        if (comparator(needle, array[m]) > 0) {\n          l = m + 1;\n        } else {\n          r = m;\n        }\n      }\n      return r;\n    }\n    __name(lowerBound2, \"lowerBound\");\n    function upperBound2(array, needle, comparator, left, right) {\n      let l = left || 0;\n      let r = right !== void 0 ? right : array.length;\n      while (l < r) {\n        const m = l + r >> 1;\n        if (comparator(needle, array[m]) >= 0) {\n          l = m + 1;\n        } else {\n          r = m;\n        }\n      }\n      return r;\n    }\n    __name(upperBound2, \"upperBound\");\n    module2.exports = {\n      ArrayUtilities: {\n        lowerBound: lowerBound2,\n        upperBound: upperBound2\n      },\n      DevToolsPath: {\n        EmptyUrlString: \"\"\n      }\n    };\n  }\n});\n\n// core/lib/cdt/generated/SourceMap.js\nvar require_SourceMap = __commonJS({\n  \"core/lib/cdt/generated/SourceMap.js\"(exports2, module2) {\n    \"use strict\";\n    init_process_global();\n    var Common = require_Common();\n    var Platform = require_Platform();\n    var BASE64_CHARS = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\";\n    var BASE64_CODES = new Uint8Array(123);\n    for (let index = 0; index < BASE64_CHARS.length; ++index) {\n      BASE64_CODES[BASE64_CHARS.charCodeAt(index)] = index;\n    }\n    Object.defineProperty(exports2, \"__esModule\", { value: true });\n    exports2.TokenIterator = exports2.SourceMap = exports2.SourceMapEntry = void 0;\n    exports2.parseSourceMap = parseSourceMap;\n    function parseSourceMap(content) {\n      if (content.startsWith(\")]}\")) {\n        content = content.substring(content.indexOf(\"\\n\"));\n      }\n      if (content.charCodeAt(0) === 65279) {\n        content = content.slice(1);\n      }\n      return JSON.parse(content);\n    }\n    __name(parseSourceMap, \"parseSourceMap\");\n    var SourceMapEntry = class {\n      static {\n        __name(this, \"SourceMapEntry\");\n      }\n      lineNumber;\n      columnNumber;\n      sourceIndex;\n      sourceURL;\n      sourceLineNumber;\n      sourceColumnNumber;\n      name;\n      constructor(lineNumber, columnNumber, sourceIndex, sourceURL, sourceLineNumber, sourceColumnNumber, name) {\n        this.lineNumber = lineNumber;\n        this.columnNumber = columnNumber;\n        this.sourceIndex = sourceIndex;\n        this.sourceURL = sourceURL;\n        this.sourceLineNumber = sourceLineNumber;\n        this.sourceColumnNumber = sourceColumnNumber;\n        this.name = name;\n      }\n      static compare(entry1, entry2) {\n        if (entry1.lineNumber !== entry2.lineNumber) {\n          return entry1.lineNumber - entry2.lineNumber;\n        }\n        return entry1.columnNumber - entry2.columnNumber;\n      }\n    };\n    exports2.SourceMapEntry = SourceMapEntry;\n    var SourceMap = class {\n      static {\n        __name(this, \"SourceMap\");\n      }\n      #json;\n      #compiledURLInternal;\n      #sourceMappingURL;\n      #baseURL;\n      #mappingsInternal;\n      #sourceInfos = [];\n      #sourceInfoByURL = /* @__PURE__ */ new Map();\n      #scopesInfo = null;\n      /**\n       * @param {string} compiledURL\n       * @param {string} sourceMappingURL\n       * @param {object} payload\n       * Implements Source Map V3 model. See https://github.com/google/closure-compiler/wiki/Source-Maps\n       * for format description.\n       */\n      constructor(compiledURL, sourceMappingURL, payload) {\n        this.#json = payload;\n        this.#compiledURLInternal = compiledURL;\n        this.#sourceMappingURL = sourceMappingURL;\n        this.#baseURL = Common.ParsedURL.schemeIs(sourceMappingURL, \"data:\") ? compiledURL : sourceMappingURL;\n        this.#mappingsInternal = null;\n        if (\"sections\" in this.#json) {\n          if (this.#json.sections.find((section) => \"url\" in section)) {\n            console.warn(`SourceMap \"${sourceMappingURL}\" contains unsupported \"URL\" field in one of its sections.`);\n          }\n        }\n        this.eachSection(this.parseSources.bind(this));\n      }\n      #sourceIndex(sourceURL) {\n        return this.#sourceInfos.findIndex((info) => info.sourceURL === sourceURL);\n      }\n      compiledURL() {\n        return this.#compiledURLInternal;\n      }\n      url() {\n        return this.#sourceMappingURL;\n      }\n      sourceURLs() {\n        return [...this.#sourceInfoByURL.keys()];\n      }\n      embeddedContentByURL(sourceURL) {\n        const entry = this.#sourceInfoByURL.get(sourceURL);\n        if (!entry) {\n          return null;\n        }\n        return entry.content;\n      }\n      hasScopeInfo() {\n        this.#ensureMappingsProcessed();\n        return this.#scopesInfo !== null;\n      }\n      findEntry(lineNumber, columnNumber, inlineFrameIndex) {\n        this.#ensureMappingsProcessed();\n        if (inlineFrameIndex && this.#scopesInfo !== null) {\n          const { inlinedFunctions } = this.#scopesInfo.findInlinedFunctions(lineNumber, columnNumber);\n          const { callsite } = inlinedFunctions[inlineFrameIndex - 1];\n          if (!callsite) {\n            console.error(\"Malformed source map. Expected to have a callsite info for index\", inlineFrameIndex);\n            return null;\n          }\n          return {\n            lineNumber,\n            columnNumber,\n            sourceIndex: callsite.sourceIndex,\n            sourceURL: this.sourceURLs()[callsite.sourceIndex],\n            sourceLineNumber: callsite.line,\n            sourceColumnNumber: callsite.column,\n            name: void 0\n          };\n        }\n        const mappings = this.mappings();\n        const index = Platform.ArrayUtilities.upperBound(mappings, void 0, (unused, entry) => lineNumber - entry.lineNumber || columnNumber - entry.columnNumber);\n        return index ? mappings[index - 1] : null;\n      }\n      findEntryRanges(lineNumber, columnNumber) {\n        const mappings = this.mappings();\n        const endIndex = Platform.ArrayUtilities.upperBound(mappings, void 0, (unused, entry) => lineNumber - entry.lineNumber || columnNumber - entry.columnNumber);\n        if (!endIndex) {\n          return null;\n        }\n        const startIndex = endIndex - 1;\n        const sourceURL = mappings[startIndex].sourceURL;\n        if (!sourceURL) {\n          return null;\n        }\n        const endLine = endIndex < mappings.length ? mappings[endIndex].lineNumber : 2 ** 31 - 1;\n        const endColumn = endIndex < mappings.length ? mappings[endIndex].columnNumber : 2 ** 31 - 1;\n        const range = new TextUtils.TextRange.TextRange(mappings[startIndex].lineNumber, mappings[startIndex].columnNumber, endLine, endColumn);\n        const reverseMappings = this.reversedMappings(sourceURL);\n        const startSourceLine = mappings[startIndex].sourceLineNumber;\n        const startSourceColumn = mappings[startIndex].sourceColumnNumber;\n        const endReverseIndex = Platform.ArrayUtilities.upperBound(reverseMappings, void 0, (unused, i) => startSourceLine - mappings[i].sourceLineNumber || startSourceColumn - mappings[i].sourceColumnNumber);\n        if (!endReverseIndex) {\n          return null;\n        }\n        const endSourceLine = endReverseIndex < reverseMappings.length ? mappings[reverseMappings[endReverseIndex]].sourceLineNumber : 2 ** 31 - 1;\n        const endSourceColumn = endReverseIndex < reverseMappings.length ? mappings[reverseMappings[endReverseIndex]].sourceColumnNumber : 2 ** 31 - 1;\n        const sourceRange = new TextUtils.TextRange.TextRange(startSourceLine, startSourceColumn, endSourceLine, endSourceColumn);\n        return { range, sourceRange, sourceURL };\n      }\n      sourceLineMapping(sourceURL, lineNumber, columnNumber) {\n        const mappings = this.mappings();\n        const reverseMappings = this.reversedMappings(sourceURL);\n        const first = Platform.ArrayUtilities.lowerBound(reverseMappings, lineNumber, lineComparator);\n        const last = Platform.ArrayUtilities.upperBound(reverseMappings, lineNumber, lineComparator);\n        if (first >= reverseMappings.length || mappings[reverseMappings[first]].sourceLineNumber !== lineNumber) {\n          return null;\n        }\n        const columnMappings = reverseMappings.slice(first, last);\n        if (!columnMappings.length) {\n          return null;\n        }\n        const index = Platform.ArrayUtilities.lowerBound(columnMappings, columnNumber, (columnNumber2, i) => columnNumber2 - mappings[i].sourceColumnNumber);\n        return index >= columnMappings.length ? mappings[columnMappings[columnMappings.length - 1]] : mappings[columnMappings[index]];\n        function lineComparator(lineNumber2, i) {\n          return lineNumber2 - mappings[i].sourceLineNumber;\n        }\n        __name(lineComparator, \"lineComparator\");\n      }\n      findReverseIndices(sourceURL, lineNumber, columnNumber) {\n        const mappings = this.mappings();\n        const reverseMappings = this.reversedMappings(sourceURL);\n        const endIndex = Platform.ArrayUtilities.upperBound(reverseMappings, void 0, (unused, i) => lineNumber - mappings[i].sourceLineNumber || columnNumber - mappings[i].sourceColumnNumber);\n        let startIndex = endIndex;\n        while (startIndex > 0 && mappings[reverseMappings[startIndex - 1]].sourceLineNumber === mappings[reverseMappings[endIndex - 1]].sourceLineNumber && mappings[reverseMappings[startIndex - 1]].sourceColumnNumber === mappings[reverseMappings[endIndex - 1]].sourceColumnNumber) {\n          --startIndex;\n        }\n        return reverseMappings.slice(startIndex, endIndex);\n      }\n      findReverseEntries(sourceURL, lineNumber, columnNumber) {\n        const mappings = this.mappings();\n        return this.findReverseIndices(sourceURL, lineNumber, columnNumber).map((i) => mappings[i]);\n      }\n      findReverseRanges(sourceURL, lineNumber, columnNumber) {\n        const mappings = this.mappings();\n        const indices = this.findReverseIndices(sourceURL, lineNumber, columnNumber);\n        const ranges = [];\n        for (let i = 0; i < indices.length; ++i) {\n          const startIndex = indices[i];\n          let endIndex = startIndex + 1;\n          while (i + 1 < indices.length && endIndex === indices[i + 1]) {\n            ++endIndex;\n            ++i;\n          }\n          const startLine = mappings[startIndex].lineNumber;\n          const startColumn = mappings[startIndex].columnNumber;\n          const endLine = endIndex < mappings.length ? mappings[endIndex].lineNumber : 2 ** 31 - 1;\n          const endColumn = endIndex < mappings.length ? mappings[endIndex].columnNumber : 2 ** 31 - 1;\n          ranges.push(new TextUtils.TextRange.TextRange(startLine, startColumn, endLine, endColumn));\n        }\n        return ranges;\n      }\n      /** @return {Array<{lineNumber: number, columnNumber: number, sourceURL?: string, sourceLineNumber: number, sourceColumnNumber: number, name?: string, lastColumnNumber?: number}>} */\n      mappings() {\n        this.#ensureMappingsProcessed();\n        return this.#mappingsInternal ?? [];\n      }\n      reversedMappings(sourceURL) {\n        this.#ensureMappingsProcessed();\n        return this.#sourceInfoByURL.get(sourceURL)?.reverseMappings ?? [];\n      }\n      #ensureMappingsProcessed() {\n        if (this.#mappingsInternal === null) {\n          this.#mappingsInternal = [];\n          try {\n            this.eachSection(this.parseMap.bind(this));\n          } catch (e) {\n            console.error(\"Failed to parse source map\", e);\n            this.#mappingsInternal = [];\n          }\n          this.mappings().sort(SourceMapEntry.compare);\n          this.#computeReverseMappings(this.#mappingsInternal);\n          this.#json = null;\n        }\n      }\n      #computeReverseMappings(mappings) {\n        const reverseMappingsPerUrl = /* @__PURE__ */ new Map();\n        for (let i = 0; i < mappings.length; i++) {\n          const entryUrl = mappings[i].sourceURL;\n          if (!entryUrl) {\n            continue;\n          }\n          let reverseMap = reverseMappingsPerUrl.get(entryUrl);\n          if (!reverseMap) {\n            reverseMap = [];\n            reverseMappingsPerUrl.set(entryUrl, reverseMap);\n          }\n          reverseMap.push(i);\n        }\n        for (const [url, reverseMap] of reverseMappingsPerUrl.entries()) {\n          const info = this.#sourceInfoByURL.get(url);\n          if (!info) {\n            continue;\n          }\n          reverseMap.sort(sourceMappingComparator);\n          info.reverseMappings = reverseMap;\n        }\n        function sourceMappingComparator(indexA, indexB) {\n          const a = mappings[indexA];\n          const b = mappings[indexB];\n          return a.sourceLineNumber - b.sourceLineNumber || a.sourceColumnNumber - b.sourceColumnNumber || a.lineNumber - b.lineNumber || a.columnNumber - b.columnNumber;\n        }\n        __name(sourceMappingComparator, \"sourceMappingComparator\");\n      }\n      eachSection(callback) {\n        if (!this.#json) {\n          return;\n        }\n        if (\"sections\" in this.#json) {\n          let sourcesIndex = 0;\n          for (const section of this.#json.sections) {\n            if (\"map\" in section) {\n              callback(section.map, sourcesIndex, section.offset.line, section.offset.column);\n              sourcesIndex += section.map.sources.length;\n            }\n          }\n        } else {\n          callback(this.#json, 0, 0, 0);\n        }\n      }\n      parseSources(sourceMap) {\n        const sourceRoot = sourceMap.sourceRoot ?? \"\";\n        const ignoreList = new Set(sourceMap.ignoreList ?? sourceMap.x_google_ignoreList);\n        for (let i = 0; i < sourceMap.sources.length; ++i) {\n          let href = sourceMap.sources[i];\n          if (Common.ParsedURL.ParsedURL.isRelativeURL(href)) {\n            if (sourceRoot && !sourceRoot.endsWith(\"/\") && href && !href.startsWith(\"/\")) {\n              href = sourceRoot.concat(\"/\", href);\n            } else {\n              href = sourceRoot.concat(href);\n            }\n          }\n          const url = href;\n          const source = sourceMap.sourcesContent && sourceMap.sourcesContent[i];\n          const sourceInfo = {\n            sourceURL: url,\n            content: source ?? null,\n            ignoreListHint: ignoreList.has(i),\n            reverseMappings: null\n          };\n          this.#sourceInfos.push(sourceInfo);\n          if (!this.#sourceInfoByURL.has(url)) {\n            this.#sourceInfoByURL.set(url, sourceInfo);\n          }\n        }\n      }\n      parseMap(map, baseSourceIndex, baseLineNumber, baseColumnNumber) {\n        let sourceIndex = baseSourceIndex;\n        let lineNumber = baseLineNumber;\n        let columnNumber = baseColumnNumber;\n        let sourceLineNumber = 0;\n        let sourceColumnNumber = 0;\n        let nameIndex = 0;\n        const names2 = map.names ?? [];\n        const tokenIter = new TokenIterator(map.mappings);\n        let sourceURL = this.#sourceInfos[sourceIndex].sourceURL;\n        while (true) {\n          if (tokenIter.peek() === \",\") {\n            tokenIter.next();\n          } else {\n            while (tokenIter.peek() === \";\") {\n              lineNumber += 1;\n              columnNumber = 0;\n              tokenIter.next();\n            }\n            if (!tokenIter.hasNext()) {\n              break;\n            }\n          }\n          columnNumber += tokenIter.nextVLQ();\n          if (!tokenIter.hasNext() || this.isSeparator(tokenIter.peek())) {\n            this.mappings().push(new SourceMapEntry(lineNumber, columnNumber));\n            continue;\n          }\n          const sourceIndexDelta = tokenIter.nextVLQ();\n          if (sourceIndexDelta) {\n            sourceIndex += sourceIndexDelta;\n            sourceURL = this.#sourceInfos[sourceIndex].sourceURL;\n          }\n          sourceLineNumber += tokenIter.nextVLQ();\n          sourceColumnNumber += tokenIter.nextVLQ();\n          if (!tokenIter.hasNext() || this.isSeparator(tokenIter.peek())) {\n            this.mappings().push(new SourceMapEntry(lineNumber, columnNumber, sourceIndex, sourceURL, sourceLineNumber, sourceColumnNumber));\n            continue;\n          }\n          nameIndex += tokenIter.nextVLQ();\n          this.mappings().push(new SourceMapEntry(lineNumber, columnNumber, sourceIndex, sourceURL, sourceLineNumber, sourceColumnNumber, names2[nameIndex]));\n        }\n        if (false) {\n          if (!this.#scopesInfo) {\n            this.#scopesInfo = new SourceMapScopesInfo_js_1.SourceMapScopesInfo(this, [], []);\n          }\n          if (map.originalScopes && map.generatedRanges) {\n            const { originalScopes, generatedRanges } = (0, SourceMapScopes_js_1.decodeScopes)(map, { line: baseLineNumber, column: baseColumnNumber });\n            this.#scopesInfo.addOriginalScopes(originalScopes);\n            this.#scopesInfo.addGeneratedRanges(generatedRanges);\n          } else if (map.x_com_bloomberg_sourcesFunctionMappings) {\n            const originalScopes = this.parseBloombergScopes(map);\n            this.#scopesInfo.addOriginalScopes(originalScopes);\n          } else {\n            this.#scopesInfo.addOriginalScopes(new Array(map.sources.length));\n          }\n        }\n      }\n      isSeparator(char) {\n        return char === \",\" || char === \";\";\n      }\n      mapsOrigin() {\n        const mappings = this.mappings();\n        if (mappings.length > 0) {\n          const firstEntry = mappings[0];\n          return firstEntry?.lineNumber === 0 || firstEntry.columnNumber === 0;\n        }\n        return false;\n      }\n      hasIgnoreListHint(sourceURL) {\n        return this.#sourceInfoByURL.get(sourceURL)?.ignoreListHint ?? false;\n      }\n      /**\n       * Returns a list of ranges in the generated script for original sources that\n       * match a predicate. Each range is a [begin, end) pair, meaning that code at\n       * the beginning location, up to but not including the end location, matches\n       * the predicate.\n       */\n      findRanges(predicate, options) {\n        const mappings = this.mappings();\n        const ranges = [];\n        if (!mappings.length) {\n          return [];\n        }\n        let current = null;\n        if ((mappings[0].lineNumber !== 0 || mappings[0].columnNumber !== 0) && options?.isStartMatching) {\n          current = TextUtils.TextRange.TextRange.createUnboundedFromLocation(0, 0);\n          ranges.push(current);\n        }\n        for (const { sourceURL, lineNumber, columnNumber } of mappings) {\n          const ignoreListHint = sourceURL && predicate(sourceURL);\n          if (!current && ignoreListHint) {\n            current = TextUtils.TextRange.TextRange.createUnboundedFromLocation(lineNumber, columnNumber);\n            ranges.push(current);\n            continue;\n          }\n          if (current && !ignoreListHint) {\n            current.endLine = lineNumber;\n            current.endColumn = columnNumber;\n            current = null;\n          }\n        }\n        return ranges;\n      }\n      expandCallFrame(frame) {\n        this.#ensureMappingsProcessed();\n        if (this.#scopesInfo === null) {\n          return [frame];\n        }\n        return this.#scopesInfo.expandCallFrame(frame);\n      }\n      resolveScopeChain(frame) {\n        this.#ensureMappingsProcessed();\n        if (this.#scopesInfo === null) {\n          return null;\n        }\n        return this.#scopesInfo.resolveMappedScopeChain(frame);\n      }\n      findOriginalFunctionName(position) {\n        this.#ensureMappingsProcessed();\n        return this.#scopesInfo?.findOriginalFunctionName(position) ?? null;\n      }\n    };\n    exports2.SourceMap = SourceMap;\n    var VLQ_BASE_SHIFT = 5;\n    var VLQ_BASE_MASK = (1 << 5) - 1;\n    var VLQ_CONTINUATION_MASK = 1 << 5;\n    var TokenIterator = class {\n      static {\n        __name(this, \"TokenIterator\");\n      }\n      #string;\n      #position;\n      constructor(string) {\n        this.#string = string;\n        this.#position = 0;\n      }\n      next() {\n        return this.#string.charAt(this.#position++);\n      }\n      /** Returns the unicode value of the next character and advances the iterator  */\n      nextCharCode() {\n        return this.#string.charCodeAt(this.#position++);\n      }\n      peek() {\n        return this.#string.charAt(this.#position);\n      }\n      hasNext() {\n        return this.#position < this.#string.length;\n      }\n      nextVLQ() {\n        let result = 0;\n        let shift = 0;\n        let digit = VLQ_CONTINUATION_MASK;\n        while (digit & VLQ_CONTINUATION_MASK) {\n          if (!this.hasNext()) {\n            throw new Error(\"Unexpected end of input while decodling VLQ number!\");\n          }\n          const charCode = this.nextCharCode();\n          digit = BASE64_CODES[charCode];\n          if (charCode !== 65 && digit === 0) {\n            throw new Error(`Unexpected char '${String.fromCharCode(charCode)}' encountered while decoding`);\n          }\n          result += (digit & VLQ_BASE_MASK) << shift;\n          shift += VLQ_BASE_SHIFT;\n        }\n        const negative = result & 1;\n        result >>= 1;\n        return negative ? -result : result;\n      }\n      /**\n       * @returns the next VLQ number without iterating further. Or returns null if\n       * the iterator is at the end or it's not a valid number.\n       */\n      peekVLQ() {\n        const pos = this.#position;\n        try {\n          return this.nextVLQ();\n        } catch {\n          return null;\n        } finally {\n          this.#position = pos;\n        }\n      }\n    };\n    exports2.TokenIterator = TokenIterator;\n    module2.exports = SourceMap;\n    SourceMap.parseSourceMap = parseSourceMap;\n  }\n});\n\n// core/lib/cdt/SDK.js\nvar require_SDK = __commonJS({\n  \"core/lib/cdt/SDK.js\"(exports2, module2) {\n    \"use strict\";\n    init_process_global();\n    /**\n     * @license\n     * Copyright 2020 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    var SDK3 = {\n      SourceMap: require_SourceMap()\n    };\n    SDK3.SourceMap.prototype.computeLastGeneratedColumns = function() {\n      const mappings = this.mappings();\n      if (mappings.length && mappings[0].lastColumnNumber !== void 0) return;\n      for (let i = 0; i < mappings.length - 1; i++) {\n        const mapping = mappings[i];\n        const nextMapping = mappings[i + 1];\n        if (mapping.lineNumber === nextMapping.lineNumber) {\n          mapping.lastColumnNumber = nextMapping.columnNumber;\n        }\n      }\n    };\n    module2.exports = SDK3;\n  }\n});\n\n// core/gather/gatherers/source-maps.js\nvar source_maps_exports = {};\n__export(source_maps_exports, {\n  default: () => source_maps_default\n});\nvar import_SDK, SourceMaps, source_maps_default;\nvar init_source_maps = __esm({\n  \"core/gather/gatherers/source-maps.js\"() {\n    \"use strict\";\n    init_process_global();\n    import_SDK = __toESM(require_SDK(), 1);\n    init_base_gatherer();\n    init_scripts();\n    /**\n     * @license\n     * Copyright 2019 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    SourceMaps = class _SourceMaps extends base_gatherer_default {\n      static {\n        __name(this, \"SourceMaps\");\n      }\n      static symbol = Symbol(\"SourceMaps\");\n      /** @type {LH.Gatherer.GathererMeta<'Scripts'>} */\n      meta = {\n        symbol: _SourceMaps.symbol,\n        supportedModes: [\"timespan\", \"navigation\"],\n        dependencies: { Scripts: scripts_default.symbol }\n      };\n      /**\n       * @param {LH.Gatherer.Driver} driver\n       * @param {string} sourceMapUrl\n       * @return {Promise<LH.Artifacts.RawSourceMap>}\n       */\n      async fetchSourceMap(driver, sourceMapUrl) {\n        const response = await driver.fetcher.fetchResource(sourceMapUrl, { timeout: 1500 });\n        if (response.content === null) {\n          throw new Error(`Failed fetching source map (${response.status})`);\n        }\n        return import_SDK.default.SourceMap.parseSourceMap(response.content);\n      }\n      /**\n       * @param {string} sourceMapURL\n       * @return {LH.Artifacts.RawSourceMap}\n       */\n      parseSourceMapFromDataUrl(sourceMapURL) {\n        const buffer = Buffer.from(sourceMapURL.split(\",\")[1], \"base64\");\n        return import_SDK.default.SourceMap.parseSourceMap(buffer.toString());\n      }\n      /**\n       * @param {string} url\n       * @param {string} base\n       * @return {string|undefined}\n       */\n      _resolveUrl(url, base) {\n        try {\n          return new URL(url, base).href;\n        } catch (e) {\n          return;\n        }\n      }\n      /**\n       * @param {LH.Gatherer.Driver} driver\n       * @param {LH.Artifacts.Script} script\n       * @return {Promise<LH.Artifacts.SourceMap>}\n       */\n      async _retrieveMapFromScript(driver, script) {\n        if (!script.sourceMapURL) {\n          throw new Error(\"precondition failed: event.sourceMapURL should exist\");\n        }\n        const isSourceMapADataUri = script.sourceMapURL.startsWith(\"data:\");\n        const scriptUrl = script.name;\n        const rawSourceMapUrl = isSourceMapADataUri ? script.sourceMapURL : this._resolveUrl(script.sourceMapURL, script.name);\n        if (!rawSourceMapUrl) {\n          return {\n            scriptId: script.scriptId,\n            scriptUrl,\n            errorMessage: `Could not resolve map url: ${script.sourceMapURL}`\n          };\n        }\n        const sourceMapUrl = isSourceMapADataUri ? void 0 : rawSourceMapUrl;\n        try {\n          const map = isSourceMapADataUri ? this.parseSourceMapFromDataUrl(rawSourceMapUrl) : await this.fetchSourceMap(driver, rawSourceMapUrl);\n          if (typeof map.version !== \"number\") throw new Error(\"Map has no numeric `version` field\");\n          if (!Array.isArray(map.sources)) throw new Error(\"Map has no `sources` list\");\n          if (typeof map.mappings !== \"string\") throw new Error(\"Map has no `mappings` field\");\n          if (map.sections) {\n            map.sections = map.sections.filter((section) => section.map);\n          }\n          return {\n            scriptId: script.scriptId,\n            scriptUrl,\n            sourceMapUrl,\n            map\n          };\n        } catch (err) {\n          return {\n            scriptId: script.scriptId,\n            scriptUrl,\n            sourceMapUrl,\n            errorMessage: err.toString()\n          };\n        }\n      }\n      /**\n       * @param {LH.Gatherer.Context<'Scripts'>} context\n       * @return {Promise<LH.Artifacts['SourceMaps']>}\n       */\n      async getArtifact(context) {\n        const eventProcessPromises = context.dependencies.Scripts.filter((script) => script.sourceMapURL).map((script) => this._retrieveMapFromScript(context.driver, script));\n        return Promise.all(eventProcessPromises);\n      }\n    };\n    source_maps_default = SourceMaps;\n  }\n});\n\n// core/gather/gatherers/stacks.js\nvar stacks_exports = {};\n__export(stacks_exports, {\n  default: () => stacks_default\n});\nasync function detectLibraries() {\n  const libraries = [];\n  const libraryDetectorTests = d41d8cd98f00b204e9800998ecf8427e_LibraryDetectorTests;\n  for (const [name, lib] of Object.entries(libraryDetectorTests)) {\n    try {\n      let timeout;\n      const timeoutPromise = new Promise((r) => timeout = setTimeout(() => r(false), 1e3));\n      const result = await Promise.race([lib.test(window), timeoutPromise]);\n      if (timeout) clearTimeout(timeout);\n      if (result) {\n        libraries.push({\n          id: lib.id,\n          name,\n          version: result.version,\n          npm: lib.npm\n        });\n      }\n    } catch (e) {\n    }\n  }\n  return libraries;\n}\nvar require3, libDetectorSource, Stacks, stacks_default;\nvar init_stacks = __esm({\n  \"core/gather/gatherers/stacks.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_module();\n    init_lighthouse_logger();\n    init_base_gatherer();\n    /**\n     * @license\n     * Copyright 2019 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    require3 = /* @__PURE__ */ createRequire({ url: \"core/gather/gatherers/stacks.js\" }.url);\n    libDetectorSource = `function _createTimeoutHelper(){let e;return{timeoutPromise:new Promise(((t,o)=>{e=setTimeout((()=>o(new Error(\"Timed out\"))),5e3)})),clearTimeout:()=>clearTimeout(e)}}var UNKNOWN_VERSION=null,d41d8cd98f00b204e9800998ecf8427e_LibraryDetectorTests={GWT:{id:\"gwt\",icon:\"gwt\",url:\"http://www.gwtproject.org/\",test:function(e){var t=e.document,o=t.getElementById(\"__gwt_historyFrame\"),n=t.gwt_uid,r=t.body.__listener,i=t.body.__eventBits,s=e.__gwt_activeModules,c=e.__gwt_jsonp__,u=e.__gwt_scriptsLoaded||e.__gwt_stylesLoaded||e.__gwt_activeModules;if(o||n||r||i||s||c||u){for(var a=t.getElementsByTagName(\"iframe\"),l=UNKNOWN_VERSION,N=0;N<a.length;N++)try{if(a[N].tabIndex<0&&a[N].contentWindow&&a[N].contentWindow.$gwt_version){l=a[N].contentWindow.$gwt_version;break}}catch(e){}return\"0.0.999\"==l&&(l=\"Google Internal\"),{version:l}}return!1}},Ink:{id:\"ink\",icon:\"ink\",url:\"http://ink.sapo.pt/\",test:function(e){return!(!e.Ink||!e.Ink.createModule)&&{version:UNKNOWN_VERSION}}}\\\n,Vaadin:{id:\"vaadin\",icon:\"vaadin\",url:\"https://vaadin.com/\",test:function(e){return!(!e.vaadin||!e.vaadin.registerWidgetset)&&{version:UNKNOWN_VERSION}}},Bootstrap:{id:\"bootstrap\",icon:\"bootstrap\",url:\"http://getbootstrap.com/\",npm:\"bootstrap\",test:function(e){var t,o=e.$&&e.$.fn;if(o&&([\"affix\",\"alert\",\"button\",\"carousel\",\"collapse\",\"dropdown\",\"modal\",\"popover\",\"scrollspy\",\"tab\",\"tooltip\"].some((function(o){if(e.$.fn[o]){if(e.$.fn[o].Constructor&&e.$.fn[o].Constructor.VERSION)return t=e.$.fn[o].Constructor.VERSION,!0;if(new RegExp(\"\\\\\\\\$this\\\\\\\\.data\\\\\\\\((?:'|\\\\\")(?:bs\\\\\\\\.){1}\"+o).test(e.$.fn[o].toString()))return t=\">= 3.0.0 & <= 3.1.1\",!0;if(new RegExp(\"\\\\\\\\$this\\\\\\\\.data\\\\\\\\((?:'|\\\\\")\"+o).test(e.$.fn[o].toString()))return t=\">= 2.0.0 & <= 2.3.2\",!0}return!1})),t))return{version:t};return!1}},Zurb:{id:\"zurb\",icon:\"zurb\",url:\"https://foundation.zurb.com/\",npm:\"foundation-sites\",test:function(e){return!(!e.Foundation||!e.Foundation.Toggler)&&{version:e.Foundation.version||UNKNOWN_VERSION}}},Polymer\\\n:{id:\"polymer\",icon:\"polymer\",url:\"https://www.polymer-project.org/\",npm:\"@polymer/polymer\",test:function(e){return!(!e.Polymer||!e.Polymer.dom)&&{version:e.Polymer.version||UNKNOWN_VERSION}}},LitElement:{id:\"litelement\",icon:\"polymer\",url:\"https://lit-element.polymer-project.org/\",npm:\"lit-element\",test:function(e){if(e.litElementVersions&&e.litElementVersions.length){var t=[...e.litElementVersions].sort(((e,t)=>e.localeCompare(t,void 0,{numeric:!0})));return{version:t[t.length-1]}}return!1}},\"lit-html\":{id:\"lit-html\",icon:\"polymer\",url:\"https://lit-html.polymer-project.org/\",npm:\"lit-element\",test:function(e){if(e.litHtmlVersions&&e.litHtmlVersions.length){var t=[...e.litHtmlVersions].sort(((e,t)=>e.localeCompare(t,void 0,{numeric:!0})));return{version:t[t.length-1]}}return!1}},Highcharts:{id:\"highcharts\",icon:\"highcharts\",url:\"http://www.highcharts.com\",npm:\"highcharts\",test:function(e){return!(!e.Highcharts||!e.Highcharts.Point)&&{version:e.Highcharts.version||UNKNOWN_VERSION}}},In\\\nfoVis:{id:\"jit\",icon:\"jit\",url:\"http://philogb.github.com/jit/\",test:function(e){return!(!e.$jit||!e.$jit.PieChart)&&{version:e.$jit.version||UNKNOWN_VERSION}}},FlotCharts:{id:\"flotcharts\",icon:\"flotcharts\",url:\"http://www.flotcharts.org/\",npm:\"flot\",test:function(e){return!(!e.$||!e.$.plot)&&{version:e.$.plot.version||UNKNOWN_VERSION}}},CreateJS:{id:\"createjs\",icon:\"createjs\",url:\"https://createjs.com/\",npm:\"createjs\",test:function(e){return!(!e.createjs||!e.createjs.promote)&&{version:UNKNOWN_VERSION}}},\"Google Maps\":{id:\"gmaps\",icon:\"gmaps\",url:\"https://developers.google.com/maps/\",test:function(e){return!(!e.google||!e.google.maps)&&{version:e.google.maps.version||UNKNOWN_VERSION}}},jQuery:{id:\"jquery\",icon:\"jquery\",url:\"http://jquery.com\",npm:\"jquery\",test:function(e){var t=e.jQuery||e.$;return!!(t&&t.fn&&t.fn.jquery)&&{version:t.fn.jquery.replace(/[^\\\\d+\\\\.+]/g,\"\")||UNKNOWN_VERSION}}},\"jQuery (Fast path)\":{id:\"jquery-fast\",icon:\"jquery\",url:\"http://jquery.com\",npm:\"jquery\",test:fun\\\nction(e){var t=e.jQuery||e.$;return!(!t||!t.fn)&&{version:UNKNOWN_VERSION}}},\"jQuery UI\":{id:\"jquery_ui\",icon:\"jquery_ui\",url:\"http://jqueryui.com\",npm:\"jquery-ui\",test:function(e){var t=e.jQuery||e.$||e.$jq||e.$j;if(t&&t.fn&&t.fn.jquery&&t.ui){for(var o=\"accordion,datepicker,dialog,draggable,droppable,progressbar,resizable,selectable,slider,menu,grid,tabs\".split(\",\"),n=[],r=0;r<o.length;r++)t.ui[o[r]]&&n.push(o[r].substr(0,1).toUpperCase()+o[r].substr(1));return{version:t.ui.version||UNKNOWN_VERSION,details:n.length?\"Plugins used: \"+n.join(\",\"):\"\"}}return!1}},Dojo:{id:\"dojo\",icon:\"dojo\",url:\"http://dojotoolkit.org\",npm:\"dojo\",test:function(e){return!(!e.dojo||!e.dojo.delegate)&&{version:e.dojo.version?e.dojo.version.toString():UNKNOWN_VERSION,details:\"Details: \"+(e.dijit?\"Uses Dijit\":\"none\")}}},Prototype:{id:\"prototype\",icon:\"prototype\",url:\"http://prototypejs.org\",test:function(e){return!(!e.Prototype||!e.Prototype.BrowserFeatures)&&{version:e.Prototype.Version||UNKNOWN_VERSION}}},Sc\\\nriptaculous:{id:\"scriptaculous\",icon:\"scriptaculous\",url:\"http://script.aculo.us\",test:function(e){return!(!e.Scriptaculous||!e.Scriptaculous.load)&&{version:e.Scriptaculous.Version||UNKNOWN_VERSION}}},MooTools:{id:\"mootools\",icon:\"mootools\",url:\"https://mootools.net/\",test:function(e){return!(!e.MooTools||!e.MooTools.build)&&{version:e.MooTools.version||UNKNOWN_VERSION}}},Spry:{id:\"spry\",icon:\"spry\",url:\"http://labs.adobe.com/technologies/spry\",test:function(e){return!(!e.Spry||!e.Spry.Data)&&{version:UNKNOWN_VERSION}}},\"YUI 2\":{id:\"yui\",icon:\"yui\",url:\"http://developer.yahoo.com/yui/2/\",test:function(e){return!(!e.YAHOO||!e.YAHOO.util)&&{version:e.YAHOO.VERSION||UNKNOWN_VERSION}}},\"YUI 3\":{id:\"yui3\",icon:\"yui3\",url:\"https://yuilibrary.com/\",npm:\"yui\",test:function(e){return!(!e.YUI||!e.YUI.Env)&&{version:e.YUI.version||UNKNOWN_VERSION}}},Qooxdoo:{id:\"qooxdoo\",icon:\"qooxdoo\",url:\"http://www.qooxdoo.org/\",npm:\"qooxdoo\",test:function(e){return!(!e.qx||!e.qx.Bootstrap)&&{version:UNKNOWN_\\\nVERSION}}},\"Ext JS\":{id:\"extjs\",icon:\"extjs\",url:\"https://www.sencha.com/products/extjs/\",test:function(e){return e.Ext&&e.Ext.versions?{version:e.Ext.versions.core.version}:!!e.Ext&&{version:e.Ext.version||UNKNOWN_VERSION}}},Ezoic:{id:\"ezoic\",icon:\"ezoic\",url:\"https://www.ezoic.com/\",test:function(e){return!(!e.__ez||!e.__ez.template)&&{version:UNKNOWN_VERSION}}},base2:{id:\"base2\",icon:\"base2\",url:\"http://code.google.com/p/base2\",test:function(e){return!(!e.base2||!e.base2.dom)&&{version:e.base2.version||UNKNOWN_VERSION}}},\"Closure Library\":{id:\"closure\",icon:\"closure\",url:\"https://developers.google.com/closure/library/\",npm:\"google-closure-library\",test:function(e){return!(!e.goog||!e.goog.provide)&&{version:UNKNOWN_VERSION}}},\"Rapha&euml;l\":{id:\"raphael\",icon:\"raphael\",url:\"http://dmitrybaranovskiy.github.io/raphael/\",test:function(e){return!(!e.Raphael||!e.Raphael.circle)&&{version:e.Raphael.version||UNKNOWN_VERSION}}},React:{id:\"react\",icon:\"react\",url:\"https://reactjs.org/\",npm:\"\\\nreact\",test:function(e){function t(e){return null!=e&&null!=e._reactRootContainer}var o=document.getElementById(\"react-root\"),n=document.querySelector(\"*[data-reactroot]\");return!!(t(document.body)||t(document.body.firstElementChild)||null!=document.createTreeWalker(document.body,NodeFilter.SHOW_ELEMENT,(function(e){return t(e)?NodeFilter.FILTER_ACCEPT:NodeFilter.FILTER_SKIP})).nextNode()||o&&o.innerText.length>0||n||e.React&&e.React.Component)&&{version:e.React&&e.React.version||UNKNOWN_VERSION}}},\"React (Fast path)\":{id:\"react-fast\",icon:\"react\",url:\"https://reactjs.org/\",npm:\"react\",test:function(e){function t(e){return null!=e&&null!=e._reactRootContainer}var o=document.getElementById(\"react-root\"),n=document.querySelector(\"*[data-reactroot]\");return!!(t(document.body)||t(document.body.firstElementChild)||o||n||e.React)&&{version:e.React&&e.React.version||UNKNOWN_VERSION}}},\"Next.js\":{id:\"next\",icon:\"next\",url:\"https://nextjs.org/\",npm:\"next\",test:function(e){return!(!e.__NEXT_DATA\\\n__||!e.__NEXT_DATA__.buildId)&&{version:window.next&&window.next.version||UNKNOWN_VERSION}}},\"Next.js (Fast path)\":{id:\"next-fast\",icon:\"next\",url:\"https://nextjs.org/\",npm:\"next\",test:function(e){return!!e.__NEXT_DATA__&&{version:UNKNOWN_VERSION}}},Preact:{id:\"preact\",icon:\"preact\",url:\"https://preactjs.com/\",npm:\"preact\",test:function(e){var t=\"undefined\"!=typeof Symbol&&Symbol.for&&Symbol.for(\"preactattr\");function o(e){return\"__k\"in e&&\"props\"in e.__k&&\"type\"in e.__k||(\"_component\"in e||\"__preactattr_\"in e||t&&null!=e[t])}function n(e){return null!=e&&o(e)&&e}var r=n(document.body)||n(document.body.firstElementChild);if(r||(r=document.createTreeWalker(document.body,NodeFilter.SHOW_ELEMENT,(function(e){return o(e)?NodeFilter.FILTER_ACCEPT:NodeFilter.FILTER_SKIP})).nextNode()),r||e.preact){var i=UNKNOWN_VERSION;return r&&(\"__k\"in r&&(i=\"10\"),\"__preactattr_\"in r&&(i=\"8\"),t&&null!=r[t]&&(i=\"7\")),{version:i}}return!1}},\"Preact (Fast path)\":{id:\"preact-fast\",icon:\"preact\",url:\"https://pr\\\neactjs.com/\",npm:\"preact\",test:function(e){var t=UNKNOWN_VERSION;function o(e){return null!=e&&function(e){return null!=e.__k?(t=\"10\",!0):null!=e._component||null!=e.__preactattr_}(e)}return!(!o(document.body)&&!o(document.body.firstElementChild)&&!e.preact)&&{version:t}}},Modernizr:{id:\"modernizr\",icon:\"modernizr\",url:\"https://modernizr.com/\",npm:\"modernizr\",test:function(e){return!(!e.Modernizr||!e.Modernizr.addTest)&&{version:e.Modernizr._version||UNKNOWN_VERSION}}},\"Processing.js\":{id:\"processingjs\",icon:\"processingjs\",url:\"http://processingjs.org\",npm:\"processing-js\",test:function(e){return!(!e.Processing||!e.Processing.box)&&{version:Processing.version||UNKNOWN_VERSION}}},Backbone:{id:\"backbone\",icon:\"backbone\",url:\"http://backbonejs.org/\",npm:\"backbone\",test:function(e){return!(!e.Backbone||!e.Backbone.Model.extend)&&{version:e.Backbone.VERSION||UNKNOWN_VERSION}}},Leaflet:{id:\"leaflet\",icon:\"leaflet\",url:\"http://leafletjs.com\",npm:\"leaflet\",test:function(e){return!(!e.L||!e.L.Ge\\\noJSON||!e.L.marker&&!e.L.Marker)&&{version:e.L.version||e.L.VERSION||UNKNOWN_VERSION}}},Mapbox:{id:\"mapbox\",icon:\"mapbox\",url:\"https://www.mapbox.com/\",npm:\"mapbox-gl\",test:function(e){return!!(e.L&&e.L.mapbox&&e.L.mapbox.geocoder)&&{version:e.L.mapbox.VERSION||UNKNOWN_VERSION}}},\"Lo-Dash\":{id:\"lodash\",icon:\"lodash\",url:\"https://lodash.com/\",npm:\"lodash\",test:function(e){var t=\"function\"==typeof(t=e._)&&t,o=\"function\"==typeof(o=t&&t.chain)&&o,n=(o||t||function(){return{}})(1);return!(!t||!n.__wrapped__)&&{version:t.VERSION||UNKNOWN_VERSION}}},Underscore:{id:\"underscore\",icon:\"underscore\",url:\"http://underscorejs.org/\",npm:\"underscore\",test:function(e){return!(!e._||\"function\"!=typeof e._.tap||d41d8cd98f00b204e9800998ecf8427e_LibraryDetectorTests[\"Lo-Dash\"].test(e))&&{version:e._.VERSION||UNKNOWN_VERSION}}},Sammy:{id:\"sammy\",icon:\"sammy\",url:\"http://sammyjs.org\",test:function(e){return!(!e.Sammy||!e.Sammy.Application.curry)&&{version:e.Sammy.VERSION||UNKNOWN_VERSION}}},Rico:{id:\"rico\",i\\\ncon:\"rico\",url:\"http://openrico.sourceforge.net/examples/index.html\",test:function(e){return!(!e.Rico||!window.Rico.checkIfComplete)&&{version:e.Rico.Version||UNKNOWN_VERSION}}},MochiKit:{id:\"mochikit\",icon:\"mochikit\",url:\"https://mochi.github.io/mochikit/\",test:function(e){return!(!e.MochiKit||!e.MochiKit.Base.module)&&{version:MochiKit.VERSION||UNKNOWN_VERSION}}},\"gRapha&euml;l\":{id:\"graphael\",icon:\"graphael\",url:\"https://github.com/DmitryBaranovskiy/g.raphael\",test:function(e){return!(!e.Raphael||!e.Raphael.fn.g)&&{version:UNKNOWN_VERSION}}},Glow:{id:\"glow\",icon:\"glow\",url:\"http://www.bbc.co.uk/glow/\",test:function(e){return e.gloader&&e.gloader.getRequests?{version:UNKNOWN_VERSION}:e.glow&&e.glow.dom?{version:e.glow.VERSION||UNKNOWN_VERSION}:!!e.Glow&&{version:e.Glow.version||UNKNOWN_VERSION}}},\"Socket.IO\":{id:\"socketio\",icon:\"socketio\",url:\"https://socket.io/\",npm:\"socket.io\",test:function(e){return!(!e.io||!e.io.sockets&&!e.io.Socket)&&{version:e.io.version||UNKNOWN_VERSION}}},Mu\\\nstache:{id:\"mustache\",icon:\"mustache\",url:\"http://mustache.github.io/\",npm:\"mustache\",test:function(e){return!(!e.Mustache||!e.Mustache.to_html)&&{version:e.Mustache.version||UNKNOWN_VERSION}}},\"Fabric.js\":{id:\"fabricjs\",icon:\"icon38\",url:\"http://fabricjs.com/\",npm:\"fabric\",test:function(e){return!(!e.fabric||!e.fabric.util)&&{version:e.fabric.version||UNKNOWN_VERSION}}},FuseJS:{id:\"fusejs\",icon:\"fusejs\",url:\"http://fusejs.io/\",npm:\"fuse.js\",test:function(e){return!!e.Fuse&&{version:UNKNOWN_VERSION}}},\"Tween.js\":{id:\"tweenjs\",icon:\"icon38\",url:\"https://github.com/tweenjs/tween.js\",npm:\"tween.js\",test:function(e){return!(!e.TWEEN||!e.TWEEN.Easing)&&{version:UNKNOWN_VERSION}}},SproutCore:{id:\"sproutcore\",icon:\"sproutcore\",url:\"http://sproutcore.com/\",test:function(e){return!(!e.SC||!e.SC.Application)&&{version:UNKNOWN_VERSION}}},\"Zepto.js\":{id:\"zepto\",icon:\"zepto\",url:\"http://zeptojs.com\",npm:\"zepto\",test:function(e){return!(!e.Zepto||!e.Zepto.fn)&&{version:UNKNOWN_VERSION}}},\"three.js\":\\\n{id:\"threejs\",icon:\"icon38\",url:\"https://threejs.org/\",npm:\"three\",test:function(e){return e.THREE&&e.THREE.REVISION?{version:\"r\"+e.THREE.REVISION}:!!e.THREE&&{version:UNKNOWN_VERSION}}},PhiloGL:{id:\"philogl\",icon:\"philogl\",url:\"http://www.senchalabs.org/philogl/\",npm:\"philogl\",test:function(e){return!(!e.PhiloGL||!e.PhiloGL.Camera)&&{version:e.PhiloGL.version||UNKNOWN_VERSION}}},CamanJS:{id:\"camanjs\",icon:\"camanjs\",url:\"http://camanjs.com/\",npm:\"caman\",test:function(e){return e.Caman&&e.Caman.version?{version:e.Caman.version.release}:!!e.Caman&&{version:UNKNOWN_VERSION}}},yepnope:{id:\"yepnope\",icon:\"yepnope\",url:\"http://yepnopejs.com/\",test:function(e){return!(!e.yepnope||!e.yepnope.injectJs)&&{version:UNKNOWN_VERSION}}},LABjs:{id:\"labjs\",icon:\"icon38\",url:\"https://github.com/getify/LABjs\",test:function(e){return!(!e.$LAB||!e.$LAB.setOptions)&&{version:UNKNOWN_VERSION}}},\"Head JS\":{id:\"headjs\",icon:\"headjs\",url:\"http://headjs.com/\",npm:\"headjs\",test:function(e){return!(!e.head||!e.hea\\\nd.js)&&{version:UNKNOWN_VERSION}}},ControlJS:{id:\"controljs\",icon:\"icon38\",url:\"http://stevesouders.com/controljs/\",test:function(e){return!(!e.CJS||!e.CJS.start)&&{version:UNKNOWN_VERSION}}},RequireJS:{id:\"requirejs\",icon:\"requirejs\",url:\"http://requirejs.org/\",npm:\"requirejs\",test:function(e){var t=e.require||e.requirejs;return!(!t||!(t.load||t.s&&t.s.contexts&&t.s.contexts._&&(t.s.contexts._.loaded||t.s.contexts._.load)))&&{version:t.version||UNKNOWN_VERSION}}},RightJS:{id:\"rightjs\",icon:\"rightjs\",url:\"http://rightjs.org/\",test:function(e){return!(!e.RightJS||!e.RightJS.isNode)&&{version:e.RightJS.version||UNKNOWN_VERSION}}},\"jQuery Tools\":{id:\"jquerytools\",icon:\"jquerytools\",url:\"http://jquerytools.github.io/\",test:function(e){var t=e.jQuery||e.$;return!(!t||!t.tools)&&{version:t.tools.version||UNKNOWN_VERSION}}},Pusher:{id:\"pusher\",icon:\"pusher\",url:\"https://pusher.com/docs/\",npm:\"pusher-js\",test:function(e){return!(!e.Pusher||!e.Pusher.Channel)&&{version:e.Pusher.VERSION||UNKNOWN\\\n_VERSION}}},\"Paper.js\":{id:\"paperjs\",icon:\"paperjs\",url:\"http://paperjs.org/\",npm:\"paper\",test:function(e){return!(!e.paper||!e.paper.Point)&&{version:e.paper.version||UNKNOWN_VERSION}}},Swiffy:{id:\"swiffy\",icon:\"icon38\",url:\"https://developers.google.com/swiffy/\",test:function(e){return!(!e.swiffy||!e.swiffy.Stage)&&{version:UNKNOWN_VERSION}}},Move:{id:\"move\",icon:\"move\",url:\"https://github.com/rsms/move\",npm:\"move\",test:function(e){return!(!e.move||!e.move.compile)&&{version:e.move.version()||UNKNOWN_VERSION}}},AmplifyJS:{id:\"amplifyjs\",icon:\"amplifyjs\",url:\"http://amplifyjs.com/\",npm:\"amplifyjs\",test:function(e){return!(!e.amplify||!e.amplify.publish)&&{version:UNKNOWN_VERSION}}},\"Popcorn.js\":{id:\"popcornjs\",icon:\"popcornjs\",url:\"https://github.com/mozilla/popcorn-js/\",test:function(e){return!(!e.Popcorn||!e.Popcorn.Events)&&{version:e.Popcorn.version||UNKNOWN_VERSION}}},D3:{id:\"d3\",icon:\"d3\",url:\"https://d3js.org/\",npm:\"d3\",test:function(e){return!(!e.d3||!e.d3.select)&&{version:e.\\\nd3.version||UNKNOWN_VERSION}}},Handlebars:{id:\"handlebars\",icon:\"handlebars\",url:\"http://handlebarsjs.com/\",npm:\"handlebars\",test:function(e){return!(!e.Handlebars||!e.Handlebars.compile)&&{version:e.Handlebars.VERSION||UNKNOWN_VERSION}}},Handsontable:{id:\"handsontable\",icon:\"handsontable\",url:\"https://handsontable.com/\",npm:\"handsontable\",test:function(e){return!(!e.Handsontable||!e.Handsontable.Core)&&{version:e.Handsontable.version||UNKNOWN_VERSION}}},Knockout:{id:\"knockout\",icon:\"knockout\",url:\"http://knockoutjs.com/\",npm:\"knockout\",test:function(e){return!(!e.ko||!e.ko.applyBindings)&&{version:e.ko.version||UNKNOWN_VERSION}}},Spine:{id:\"spine\",icon:\"icon38\",url:\"http://spine.github.io/\",test:function(e){return!(!e.Spine||!e.Spine.Controller)&&{version:e.Spine.version||UNKNOWN_VERSION}}},\"jQuery Mobile\":{id:\"jquery-mobile\",icon:\"jquery_mobile\",url:\"http://jquerymobile.com/\",npm:\"jquery-mobile\",test:function(e){var t=e.jQuery||e.$||e.$jq||e.$j;return!!(t&&t.fn&&t.fn.jquery&&t.mobile\\\n)&&{version:t.mobile.version||UNKNOWN_VERSION}}},\"WebFont Loader\":{id:\"webfontloader\",icon:\"icon38\",url:\"https://github.com/typekit/webfontloader\",npm:\"webfontloader\",test:function(e){return!(!e.WebFont||!e.WebFont.load)&&{version:UNKNOWN_VERSION}}},Angular:{id:\"angular\",icon:\"angular\",url:\"https://angular.io/\",npm:\"@angular/core\",test:function(e){var t=e.document.querySelector(\"[ng-version]\");return t?{version:t.getAttribute(\"ng-version\")||UNKNOWN_VERSION}:!!(e.ng&&e.ng.probe instanceof Function)&&{version:UNKNOWN_VERSION}}},AngularJS:{id:\"angularjs\",icon:\"angularjs\",url:\"https://angularjs.org/\",npm:\"angular\",test:function(e){var t=e.angular;return!!(t&&t.version&&t.version.full)&&{version:t.version.full}}},Ionic:{id:\"ionic\",icon:\"ionic\",url:\"https://ionicframework.com/\",npm:\"@ionic/cli\",test:function(e){var t=e.document.querySelector(\"ion-app\");return!(!t||\"ION-APP\"!==t.nodeName)&&{version:UNKNOWN_VERSION}}},\"Ember.js\":{id:\"emberjs\",icon:\"emberjs\",url:\"https://emberjs.com/\",npm:\"embe\\\nr-source\",test:function(e){var t=e.Ember||e.Em;return!(!t||!t.GUID_KEY)&&{version:t.VERSION||UNKNOWN_VERSION}}},\"Hammer.js\":{id:\"hammerjs\",icon:\"hammerjs\",url:\"http://eightmedia.github.io/hammer.js/\",npm:\"hammerjs\",test:function(e){return!(!e.Hammer||!e.Hammer.Pinch)&&{version:e.Hammer.VERSION||\"&lt; 1.0.10\"}}},\"Visibility.js\":{id:\"visibilityjs\",icon:\"icon38\",url:\"https://github.com/ai/visibilityjs\",npm:\"visibilityjs\",test:function(e){return!(!e.Visibility||!e.Visibility.every)&&{version:UNKNOWN_VERSION}}},\"Velocity.js\":{id:\"velocityjs\",icon:\"icon38\",url:\"http://velocityjs.org/\",npm:\"velocity-animate\",test:function(e){var t=e.jQuery||e.$,o=t?t.Velocity:e.Velocity;return o&&o.RegisterEffect&&o.version?{version:o.version.major+\".\"+o.version.minor+\".\"+o.version.patch}:!(!o||!o.RegisterEffect)&&{version:UNKNOWN_VERSION}}},\"IfVisible.js\":{id:\"ifvisiblejs\",icon:\"icon38\",url:\"http://serkanyersen.github.io/ifvisible.js/\",npm:\"ifvisible.js\",test:function(e){var t=e.ifvisible;return!(!t||\"ifvisi\\\nble.object.event.identifier\"!==t.__ceGUID)&&{version:UNKNOWN_VERSION}}},\"Pixi.js\":{id:\"pixi\",icon:\"pixi\",url:\"http://www.pixijs.com/\",npm:\"pixi.js\",test:function(e){var t=e.PIXI;return!!(t&&t.WebGLRenderer&&t.VERSION)&&{version:t.VERSION.replace(\"v\",\"\")||UNKNOWN_VERSION}}},\"DC.js\":{id:\"dcjs\",icon:\"dcjs\",url:\"http://dc-js.github.io/dc.js/\",npm:\"dc\",test:function(e){var t=e.dc;return!(!t||!t.registerChart)&&{version:t.version||UNKNOWN_VERSION}}},\"GreenSock JS\":{id:\"greensock\",icon:\"greensock\",url:\"https://greensock.com/gsap\",npm:\"gsap\",test:function(e){return!(!e.TweenMax||!e.TweenMax.pauseAll)&&{version:e.TweenMax.version||UNKNOWN_VERSION}}},FastClick:{id:\"fastclick\",icon:\"fastclick\",url:\"https://github.com/ftlabs/fastclick\",npm:\"fastclick\",test:function(e){return!(!e.FastClick||!e.FastClick.notNeeded)&&{version:UNKNOWN_VERSION}}},Isotope:{id:\"isotope\",icon:\"isotope\",url:\"https://isotope.metafizzy.co/\",npm:\"isotope-layout\",test:function(e){return!!(e.Isotope||null!=e.$&&e.$.Isotope)&&{v\\\nersion:UNKNOWN_VERSION}}},Marionette:{id:\"marionette\",icon:\"marionette\",url:\"https://marionettejs.com/\",npm:\"backbone.marionette\",test:function(e){return!(!e.Marionette||!e.Marionette.Application)&&{version:e.Marionette.VERSION||UNKNOWN_VERSION}}},Can:{id:\"canjs\",icon:\"canjs\",url:\"https://canjs.com/\",npm:\"can\",test:function(e){return!(!e.can||!e.can.Construct)&&{version:e.can.VERSION||UNKNOWN_VERSION}}},Vue:{id:\"vue\",icon:\"vue\",url:\"https://vuejs.org/\",npm:\"vue\",test:function(e){return!(null===document.createTreeWalker(document.body,NodeFilter.SHOW_ELEMENT,(function(e){return null!=e.__vue__?NodeFilter.FILTER_ACCEPT:NodeFilter.FILTER_SKIP})).nextNode()&&!e.Vue)&&{version:e.Vue&&e.Vue.version||UNKNOWN_VERSION}}},\"Vue (Fast path)\":{id:\"vue-fast\",icon:\"vue\",url:\"https://vuejs.org/\",npm:\"vue\",test:function(e){return!!e.Vue&&{version:e.Vue&&e.Vue.version||UNKNOWN_VERSION}}},\"Nuxt.js\":{id:\"nuxt\",icon:\"nuxt\",url:\"https://nuxtjs.org/\",npm:\"nuxt\",test:function(e){return!!(e.__NUXT__||e.$nuxt||[\\\n...e.document.querySelectorAll(\"*\")].some((e=>e.__vue__?.nuxt)))&&{version:UNKNOWN_VERSION}}},\"Nuxt.js (Fast path)\":{id:\"nuxt-fast\",icon:\"nuxt\",url:\"https://nuxtjs.org/\",npm:\"nuxt\",test:function(e){return!(!e.__NUXT__&&!e.$nuxt)&&{version:UNKNOWN_VERSION}}},Two:{id:\"two\",icon:\"two\",url:\"https://two.js.org/\",npm:\"two.js\",test:function(e){return!(!e.Two||!e.Two.Utils)&&{version:e.Two.Version||UNKNOWN_VERSION}}},Brewser:{id:\"brewser\",icon:\"brewser\",url:\"https://robertpataki.github.io/brewser/\",npm:\"brewser\",test:function(e){return!(!e.BREWSER||!e.BREWSER.ua)&&{version:BREWSER.VERSION||UNKNOWN_VERSION}}},\"Material Design Lite\":{id:\"materialdesignlite\",icon:\"mdl\",url:\"https://getmdl.io/\",npm:\"material-design-lite\",test:function(e){return!(!e.componentHandler||!e.componentHandler.upgradeElement)&&{version:UNKNOWN_VERSION}}},\"Kendo UI\":{id:\"kendoui\",icon:\"kendoui\",url:\"https://github.com/telerik/kendo-ui-core\",npm:\"kendo-ui-core\",test:function(e){return!!(e.kendo&&e.kendo.View&&e.kendo.View.e\\\nxtend)&&{version:e.kendo.version||UNKNOWN_VERSION}}},\"Matter.js\":{id:\"matterjs\",icon:\"matter-js\",url:\"http://brm.io/matter-js/\",npm:\"matter-js\",test:function(e){return!(!e.Matter||!e.Matter.Engine)&&{version:UNKNOWN_VERSION}}},Riot:{id:\"riot\",icon:\"riot\",url:\"http://riotjs.com/\",npm:\"riot\",test:function(e){return!(!e.riot||!e.riot.mixin)&&{version:e.riot.version||UNKNOWN_VERSION}}},\"Sea.js\":{id:\"seajs\",icon:\"icon38\",url:\"https://seajs.github.io/seajs/docs/\",npm:\"seajs\",test:function(e){return!(!e.seajs||!e.seajs.use)&&{version:e.seajs.version||UNKNOWN_VERSION}}},\"Moment.js\":{id:\"momentjs\",icon:\"momentjs\",url:\"http://momentjs.com/\",npm:\"moment\",test:function(e){return!(!e.moment||!e.moment.isMoment&&!e.moment.lang)&&{version:e.moment.version||UNKNOWN_VERSION}}},\"Moment Timezone\":{id:\"moment-timezone\",icon:\"momentjs\",url:\"http://momentjs.com/timezone/\",npm:\"moment-timezone\",test:function(e){return!(!e.moment||!e.moment.tz)&&{version:e.moment.tz.version||UNKNOWN_VERSION}}},ScrollMagic:{id\\\n:\"scrollmagic\",icon:\"scrollmagic\",url:\"http://scrollmagic.io/\",npm:\"scrollmagic\",test:function(e){return!(!e.ScrollMagic||!e.ScrollMagic.Controller)&&{version:ScrollMagic.version||UNKNOWN_VERSION}}},SWFObject:{id:\"swfobject\",icon:\"icon38\",url:\"https://github.com/swfobject/swfobject\",test:function(e){return e.swfobject&&e.swfobject.embedSWF?{version:e.swfobject.version||UNKNOWN_VERSION}:!(!e.deconcept||!e.deconcept.SWFObject)&&{version:UNKNOWN_VERSION}}},FlexSlider:{id:\"flexslider\",icon:\"icon38\",url:\"https://woocommerce.com/flexslider/\",npm:\"flexslider\",test:function(e){var t=e.jQuery||e.$||e.$jq||e.$j;return!!(t&&t.fn&&t.fn.jquery&&t.flexslider)&&{version:UNKNOWN_VERSION}}},SPF:{id:\"spf\",icon:\"icon38\",url:\"https://youtube.github.io/spfjs/\",npm:\"spf\",test:function(e){return!(!e.spf||!e.spf.init)&&{version:UNKNOWN_VERSION}}},\"Numeral.js\":{id:\"numeraljs\",icon:\"icon38\",url:\"http://numeraljs.com/\",npm:\"numeraljs\",test:function(e){return!(!e.numeral||!e.isNumeral)&&{version:e.numeral.version\\\n||UNKNOWN_VERSION}}},\"boomerang.js\":{id:\"boomerangjs\",icon:\"icon38\",url:\"https://soasta.github.io/boomerang/\",npm:\"boomerangjs\",test:function(e){return!!(e.BOOMR&&e.BOOMR.utils&&e.BOOMR.init)&&{version:e.BOOMR.version||UNKNOWN_VERSION}}},Framer:{id:\"framer\",icon:\"framer\",url:\"https://framer.com/\",npm:\"framerjs\",test:function(e){return!(!e.Framer||!e.Framer.Layer)&&{version:e.Framer.Version.build||UNKNOWN_VERSION}}},Marko:{id:\"marko\",icon:\"marko\",url:\"https://markojs.com/\",npm:\"marko\",test:function(e){return!!document.querySelector(\"[data-marko-key], [data-marko]\")&&{version:UNKNOWN_VERSION}}},AMP:{id:\"amp\",icon:\"amp\",url:\"https://amp.dev/\",npm:\"https://www.npmjs.com/org/ampproject\",test:function(e){var t=e.document.documentElement.getAttribute(\"amp-version\");return!!t&&{version:t}}},Gatsby:{id:\"gatsby\",icon:\"gatsby\",url:\"https://www.gatsbyjs.org/\",npm:\"gatsby\",test:function(e){return!!document.getElementById(\"___gatsby\")&&{version:UNKNOWN_VERSION}}},Shopify:{id:\"shopify\",icon:\"shopify\"\\\n,url:\"https://www.shopify.com/\",npm:null,test:function(e){return!(!e.Shopify||!e.Shopify.shop)&&{version:UNKNOWN_VERSION}}},Magento:{id:\"magento\",icon:\"magento\",url:\"https://magento.com/\",npm:null,test:function(e){const t=/\\\\/static(?:\\\\/version\\\\d+)?\\\\/frontend\\\\/.+\\\\/.+\\\\/requirejs\\\\/require(?:\\\\.min)?\\\\.js/;return!!Array.from(document.querySelectorAll(\"script[src]\")||[]).some((e=>t.test(e.src)))&&{version:2}}},WordPress:{id:\"wordpress\",icon:\"wordpress\",url:\"https://wordpress.org/\",npm:null,test:function(e){const t=!!document.querySelector('link[rel=\"https://api.w.org/\"]'),o=!!document.querySelectorAll('link[href*=\"wp-includes\"], script[src*=\"wp-includes\"]').length;if(!t&&!o)return!1;const n=document.querySelector('meta[name=generator][content^=\"WordPress\"]');return{version:n?n.getAttribute(\"content\").replace(/^\\\\w+\\\\s/,\"\"):UNKNOWN_VERSION}}},Wix:{id:\"wix\",icon:\"wix\",url:\"https://www.wix.com/\",npm:null,test:function(e){return(e.wixPerformanceMeasurements&&e.wixPerformanceMeasurements.info||!(!e.\\\nwixBiSession||!e.wixBiSession.info))&&{version:UNKNOWN_VERSION}}},Workbox:{id:\"workbox\",icon:\"workbox\",url:\"https://developers.google.com/web/tools/workbox/\",npm:\"workbox-sw\",test:async function(e){var t=e.navigator;if(!(\"serviceWorker\"in t))return!1;const{timeoutPromise:o,clearTimeout:n}=_createTimeoutHelper(),r=t.serviceWorker.getRegistration().then((function(e){var o=t.serviceWorker.controller?t.serviceWorker.controller.scriptURL:e.active.scriptURL;return fetch(o,{credentials:\"include\",headers:{\"service-worker\":\"script\"}}).then((function(e){return e.text()})).then((function(e){if(/new Workbox|new workbox|workbox\\\\.precaching\\\\.|workbox\\\\.strategies/gm.test(e)){var t=/workbox.*?\\\\b((0|[1-9]\\\\d*)\\\\.(0|[1-9]\\\\d*)\\\\.(0|[1-9]\\\\d*)(-(0|[1-9]\\\\d*|\\\\d*[a-zA-Z-][0-9a-zA-Z-]*)(\\\\.(0|[1-9]\\\\d*|\\\\d*[a-zA-Z-][0-9a-zA-Z-]*))*)?(\\\\+[0-9a-zA-Z-]+(\\\\.[0-9a-zA-Z-]+)*)?)\\\\b/gim.exec(e),o=UNKNOWN_VERSION;return Array.isArray(t)&&t.length>1&&t[1]&&(o=t[1]),{version:o}}return!1}))})).catch((function(e){return!1}));return\\\n Promise.race([r,o]).catch((function(e){return!1})).finally((e=>(n(),e)))}},Boq:{id:\"boq\",icon:\"icon38\",url:\"https://github.com/johnmichel/Library-Detector-for-Chrome/pull/143\",npm:null,test:function(e){return!!e.WIZ_global_data&&{version:UNKNOWN_VERSION}}},Wiz:{id:\"wiz\",icon:\"icon38\",url:\"https://github.com/johnmichel/Library-Detector-for-Chrome/pull/147\",npm:null,test:function(e){return!!document.__wizdispatcher&&{version:UNKNOWN_VERSION}}},\"core-js\":{id:\"corejs\",icon:\"icon38\",url:\"https://github.com/zloirock/core-js\",npm:\"core-js\",test:function(e){const t=e[\"__core-js_shared__\"],o=e.core;if(t){const e=t.versions;return{version:Array.isArray(e)?e.map((e=>\\`core-js-\\${e.mode}@\\${e.version}\\`)).join(\"; \"):UNKNOWN_VERSION}}return!!o&&{version:o.version||UNKNOWN_VERSION}}},Drupal:{id:\"drupal\",icon:\"drupal\",url:\"https://www.drupal.org/\",npm:null,test:function(e){const t=document.querySelector('meta[name=\"generator\"][content^=\"Drupal\"]'),o=t?t.getAttribute(\"content\").replace(/\\\\D+/gi,\"\"):UNKNOW\\\nN_VERSION,n=/\\\\/sites\\\\/(?:default|all)\\\\/(?:themes|modules|files)/,r=Array.from(document.querySelectorAll(\"link,style,script\")||[]);return!!(r.some((e=>n.test(e.src)))||r.some((e=>n.test(e.href)))||t||e.Drupal&&e.Drupal.behaviors)&&{version:o}}},TYPO3:{id:\"typo3\",icon:\"typo3\",url:\"https://typo3.org/\",npm:null,test:function(e){const t=document.querySelector('meta[name=\"generator\"][content^=\"TYPO3\"]'),o=/\\\\/(typo3conf|typo3temp|fileadmin)/,n=Array.from(document.querySelectorAll(\"link,style,script\")||[]);return!!(t||n.some((e=>o.test(e.src)))||n.some((e=>o.test(e.href))))&&{version:UNKNOWN_VERSION}}},\"Create React App\":{id:\"create-react-app\",icon:\"cra\",url:\"https://create-react-app.dev/\",npm:\"react-scripts\",test:function(e){let t,o,n=e.document.body.firstElementChild;do{\"noscript\"===n.localName?t=n:\"root\"===n.id&&(o=n)}while(n=n.nextElementSibling);return!!(o&&t&&/You need to enable JavaScript to run this app/.test(t.textContent))&&{version:UNKNOWN_VERSION}}},\"Guess.js\":{id:\"guessjs\",icon:\"g\\\nuessjs\",url:\"https://guess-js.github.io/\",test:function(e){return!(!e.__GUESS__||!e.__GUESS__.guess)&&{version:UNKNOWN_VERSION}}},\"October CMS\":{id:\"octobercms\",icon:\"october\",url:\"https://octobercms.com/\",npm:null,test:function(e){const t=document.querySelector('meta[name=\"generator\"][content^=\"OctoberCMS\"]'),o=document.querySelector('meta[name=\"generator\"][content^=\"October CMS\"]'),n=/\\\\/modules\\\\/system\\\\/assets\\\\/(css|js)\\\\/framework(\\\\.extras|\\\\.combined)?(-min)?/,r=Array.from(document.querySelectorAll(\"link,style,script\")||[]);return!!(t||o||r.some((e=>n.test(e.src||e.href))))&&{version:UNKNOWN_VERSION}}},Joomla:{id:\"joomla\",icon:\"joomla\",url:\"https://www.joomla.org/\",npm:null,test:function(e){const t=document.querySelector('meta[name=generator][content^=\"Joomla\"]'),o=!!document.querySelectorAll('script[src*=\"/media/jui/js/bootstrap.min.js\"]').length;return t?{version:t.getAttribute(\"content\").replace(/^\\\\w+\\\\s/,\"\")}:!(!e.Joomla&&!o)&&{version:UNKNOWN_VERSION}}},Sugar:{id:\"sugar\",icon:\"su\\\ngar\",url:\"https://sugarjs.com\",npm:\"sugar\",test:function(e){return e.Sugar?{version:e.Sugar.VERSION||UNKNOWN_VERSION}:!!e.Array.SugarMethods&&{version:UNKNOWN_VERSION}}},Bento:{id:\"bentojs\",icon:\"bentojs\",url:\"https://bentojs.dev\",npm:\"https://www.npmjs.com/org/bentoproject\",test:function(e){return!(!e.BENTO||!e.BENTO.push)&&{version:UNKNOWN_VERSION}}},\"WP Rocket\":{id:\"wp-rocket\",icon:\"wp-rocket\",url:\"https://wp-rocket.me/\",npm:null,test:async function(e){const t=\"undefined\"!=typeof RocketLazyLoadScripts||\"undefined\"!=typeof RocketPreloadLinksConfig||\"undefined\"!=typeof rocket_lazy,o=!!document.querySelector(\"style#wpr-usedcss\"),n=document.lastChild.nodeType===Node.COMMENT_NODE&&document.lastChild.textContent.includes(\"WP Rocket\");return!!(o||t||n)&&{version:UNKNOWN_VERSION}}},NitroPack:{id:\"nitropack\",icon:\"nitropack\",url:\"https://nitropack.io/\",npm:null,test:async function(e){return!!document.querySelector('meta[name=\"generator\"][content=\"NitroPack\"]')&&{version:UNKNOWN_VERSION}}},Re\\\nmix:{id:\"remix\",icon:\"remix\",url:\"https://remix.run/\",npm:\"remix\",test:function(e){return!!e.__remixContext&&{version:UNKNOWN_VERSION}}}};`;\n    __name(detectLibraries, \"detectLibraries\");\n    Stacks = class _Stacks extends base_gatherer_default {\n      static {\n        __name(this, \"Stacks\");\n      }\n      constructor() {\n        super();\n        this.meta = {\n          supportedModes: [\"snapshot\", \"navigation\"]\n        };\n      }\n      /**\n       * @param {LH.Gatherer.Driver['executionContext']} executionContext\n       * @return {Promise<LH.Artifacts['Stacks']>}\n       */\n      static async collectStacks(executionContext) {\n        const status = { msg: \"Collect stacks\", id: \"lh:gather:collectStacks\" };\n        lighthouse_logger_default.time(status);\n        const jsLibraries = await executionContext.evaluate(detectLibraries, {\n          args: [],\n          deps: [libDetectorSource]\n        });\n        const stacks = jsLibraries.map((lib) => ({\n          detector: \"js\",\n          id: lib.id,\n          name: lib.name,\n          version: typeof lib.version === \"number\" ? String(lib.version) : lib.version || void 0,\n          npm: lib.npm || void 0\n        }));\n        lighthouse_logger_default.timeEnd(status);\n        return stacks;\n      }\n      /**\n       * @param {LH.Gatherer.Context} context\n       * @return {Promise<LH.Artifacts['Stacks']>}\n       */\n      async getArtifact(context) {\n        try {\n          return await _Stacks.collectStacks(context.driver.executionContext);\n        } catch {\n          return [];\n        }\n      }\n    };\n    stacks_default = Stacks;\n  }\n});\n\n// core/gather/gatherers/viewport-dimensions.js\nvar viewport_dimensions_exports = {};\n__export(viewport_dimensions_exports, {\n  default: () => viewport_dimensions_default\n});\nfunction getViewportDimensions() {\n  return {\n    innerWidth: window.innerWidth,\n    innerHeight: window.innerHeight,\n    outerWidth: window.outerWidth,\n    outerHeight: window.outerHeight,\n    devicePixelRatio: window.devicePixelRatio\n  };\n}\nvar ViewportDimensions, viewport_dimensions_default;\nvar init_viewport_dimensions = __esm({\n  \"core/gather/gatherers/viewport-dimensions.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_base_gatherer();\n    /**\n     * @license\n     * Copyright 2016 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    __name(getViewportDimensions, \"getViewportDimensions\");\n    ViewportDimensions = class extends base_gatherer_default {\n      static {\n        __name(this, \"ViewportDimensions\");\n      }\n      /** @type {LH.Gatherer.GathererMeta} */\n      meta = {\n        supportedModes: [\"snapshot\", \"timespan\", \"navigation\"]\n      };\n      /**\n       * @param {LH.Gatherer.Context} passContext\n       * @return {Promise<LH.Artifacts.ViewportDimensions>}\n       */\n      async getArtifact(passContext) {\n        const driver = passContext.driver;\n        const dimensions = await driver.executionContext.evaluate(getViewportDimensions, {\n          args: [],\n          useIsolation: true\n        });\n        const allNumeric = Object.values(dimensions).every(Number.isFinite);\n        if (!allNumeric) {\n          const results = JSON.stringify(dimensions);\n          throw new Error(`ViewportDimensions results were not numeric: ${results}`);\n        }\n        return dimensions;\n      }\n    };\n    viewport_dimensions_default = ViewportDimensions;\n  }\n});\n\n// core/audits/accessibility/axe-audit.js\nvar UIStrings23, str_4, AxeAudit, axe_audit_default;\nvar init_axe_audit = __esm({\n  \"core/audits/accessibility/axe-audit.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_audit();\n    init_i18n();\n    /**\n     * @license\n     * Copyright 2017 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    UIStrings23 = {\n      /** Label of a table column that identifies HTML elements that have failed an audit. */\n      failingElementsHeader: \"Failing Elements\"\n    };\n    str_4 = createIcuMessageFn({ url: \"core/audits/accessibility/axe-audit.js\" }.url, UIStrings23);\n    AxeAudit = class extends Audit {\n      static {\n        __name(this, \"AxeAudit\");\n      }\n      /**\n       * Base class for audit rules which reflect assessment performed by the aXe accessibility library\n       * See https://github.com/dequelabs/axe-core/blob/6b444546cff492a62a70a74a8fc3c62bd4729400/doc/API.md#results-object for result type and format details\n       *\n       * @param {LH.Artifacts} artifacts Accessibility gatherer artifacts. Note that AxeAudit\n       * expects the meta name for the class to match the rule id from aXe.\n       * @return {LH.Audit.Product}\n       */\n      static audit(artifacts) {\n        const notApplicables = artifacts.Accessibility.notApplicable || [];\n        const isNotApplicable = notApplicables.find((result) => result.id === this.meta.id);\n        if (isNotApplicable) {\n          return {\n            score: null,\n            notApplicable: true\n          };\n        }\n        const incomplete = artifacts.Accessibility.incomplete || [];\n        const incompleteResult = incomplete.find((result) => result.id === this.meta.id);\n        if (incompleteResult?.error) {\n          return {\n            score: null,\n            errorMessage: `axe-core Error: ${incompleteResult.error.message || \"Unknown error\"}`\n          };\n        }\n        const isInformative = this.meta.scoreDisplayMode === Audit.SCORING_MODES.INFORMATIVE;\n        const violations = artifacts.Accessibility.violations || [];\n        const failureCases = isInformative ? violations.concat(incomplete) : violations;\n        const rule = failureCases.find((result) => result.id === this.meta.id);\n        const impact = rule?.impact;\n        const tags = rule?.tags;\n        if (isInformative && !rule) {\n          return {\n            score: null,\n            notApplicable: true\n          };\n        }\n        let items = [];\n        if (rule?.nodes) {\n          items = rule.nodes.map((axeNode) => ({\n            node: {\n              ...Audit.makeNodeItem(axeNode.node),\n              explanation: axeNode.failureSummary\n            },\n            subItems: axeNode.relatedNodes.length ? {\n              type: \"subitems\",\n              items: axeNode.relatedNodes.map((node) => ({ relatedNode: Audit.makeNodeItem(node) }))\n            } : void 0\n          }));\n        }\n        const headings = [\n          /* eslint-disable max-len */\n          { key: \"node\", valueType: \"node\", subItemsHeading: { key: \"relatedNode\", valueType: \"node\" }, label: str_4(UIStrings23.failingElementsHeader) }\n          /* eslint-enable max-len */\n        ];\n        let debugData;\n        if (impact || tags) {\n          debugData = {\n            type: \"debugdata\",\n            impact,\n            tags\n          };\n        }\n        return {\n          score: Number(rule === void 0),\n          details: { ...Audit.makeTableDetails(headings, items), debugData }\n        };\n      }\n    };\n    axe_audit_default = AxeAudit;\n  }\n});\n\n// core/audits/accessibility/accesskeys.js\nvar accesskeys_exports = {};\n__export(accesskeys_exports, {\n  UIStrings: () => UIStrings24,\n  default: () => accesskeys_default\n});\nvar UIStrings24, str_5, Accesskeys, accesskeys_default;\nvar init_accesskeys = __esm({\n  \"core/audits/accessibility/accesskeys.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_axe_audit();\n    init_i18n();\n    /**\n     * @license\n     * Copyright 2017 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    UIStrings24 = {\n      /** Title of an accessibility audit that evaluates if the accesskey HTML attribute values are unique across all elements. This title is descriptive of the successful state and is shown to users when no user action is required. */\n      title: \"`[accesskey]` values are unique\",\n      /** Title of an accessibility audit that evaluates if the ARIA HTML attributes are misaligned with the aria-role HTML attribute specificed on the element, such mismatches are invalid. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed. */\n      failureTitle: \"`[accesskey]` values are not unique\",\n      /** Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */\n      description: \"Access keys let users quickly focus a part of the page. For proper navigation, each access key must be unique. [Learn more about access keys](https://dequeuniversity.com/rules/axe/4.11/accesskeys).\"\n    };\n    str_5 = createIcuMessageFn({ url: \"core/audits/accessibility/accesskeys.js\" }.url, UIStrings24);\n    Accesskeys = class extends axe_audit_default {\n      static {\n        __name(this, \"Accesskeys\");\n      }\n      /**\n       * @return {LH.Audit.Meta}\n       */\n      static get meta() {\n        return {\n          id: \"accesskeys\",\n          title: str_5(UIStrings24.title),\n          failureTitle: str_5(UIStrings24.failureTitle),\n          description: str_5(UIStrings24.description),\n          requiredArtifacts: [\"Accessibility\"]\n        };\n      }\n    };\n    accesskeys_default = Accesskeys;\n  }\n});\n\n// core/audits/accessibility/aria-allowed-attr.js\nvar aria_allowed_attr_exports = {};\n__export(aria_allowed_attr_exports, {\n  UIStrings: () => UIStrings25,\n  default: () => aria_allowed_attr_default\n});\nvar UIStrings25, str_6, ARIAAllowedAttr, aria_allowed_attr_default;\nvar init_aria_allowed_attr = __esm({\n  \"core/audits/accessibility/aria-allowed-attr.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_axe_audit();\n    init_i18n();\n    /**\n     * @license\n     * Copyright 2017 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    UIStrings25 = {\n      /** Title of an accessibility audit that evaluates if the ARIA HTML attributes are misaligned with the aria-role HTML attribute specificed on the element, such mismatches are invalid. This title is descriptive of the successful state and is shown to users when no user action is required. */\n      title: \"`[aria-*]` attributes match their roles\",\n      /** Title of an accessibility audit that evaluates if the ARIA HTML attributes are misaligned with the aria-role HTML attribute specificed on the element, such mismatches are invalid. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed. */\n      failureTitle: \"`[aria-*]` attributes do not match their roles\",\n      /** Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */\n      description: \"Each ARIA `role` supports a specific subset of `aria-*` attributes. Mismatching these invalidates the `aria-*` attributes. [Learn how to match ARIA attributes to their roles](https://dequeuniversity.com/rules/axe/4.11/aria-allowed-attr).\"\n    };\n    str_6 = createIcuMessageFn({ url: \"core/audits/accessibility/aria-allowed-attr.js\" }.url, UIStrings25);\n    ARIAAllowedAttr = class extends axe_audit_default {\n      static {\n        __name(this, \"ARIAAllowedAttr\");\n      }\n      /**\n       * @return {LH.Audit.Meta}\n       */\n      static get meta() {\n        return {\n          id: \"aria-allowed-attr\",\n          title: str_6(UIStrings25.title),\n          failureTitle: str_6(UIStrings25.failureTitle),\n          description: str_6(UIStrings25.description),\n          requiredArtifacts: [\"Accessibility\"]\n        };\n      }\n    };\n    aria_allowed_attr_default = ARIAAllowedAttr;\n  }\n});\n\n// core/audits/accessibility/aria-allowed-role.js\nvar aria_allowed_role_exports = {};\n__export(aria_allowed_role_exports, {\n  UIStrings: () => UIStrings26,\n  default: () => aria_allowed_role_default\n});\nvar UIStrings26, str_7, ARIAAllowedRole, aria_allowed_role_default;\nvar init_aria_allowed_role = __esm({\n  \"core/audits/accessibility/aria-allowed-role.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_axe_audit();\n    init_i18n();\n    /**\n     * @license\n     * Copyright 2023 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    UIStrings26 = {\n      /** Title of an accessibility audit that evaluates if the ARIA role attributes are valid for the HTML element. This title is descriptive of the successful state and is shown to users when no user action is required. */\n      title: \"Uses ARIA roles only on compatible elements\",\n      /** Title of an accessibility audit that evaluates if the ARIA role attributes are valid for the HTML element. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed. */\n      failureTitle: \"Uses ARIA roles on incompatible elements\",\n      /** Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */\n      description: \"Many HTML elements can only be assigned certain ARIA roles. Using ARIA roles where they are not allowed can interfere with the accessibility of the web page. [Learn more about ARIA roles](https://dequeuniversity.com/rules/axe/4.11/aria-allowed-role).\"\n    };\n    str_7 = createIcuMessageFn({ url: \"core/audits/accessibility/aria-allowed-role.js\" }.url, UIStrings26);\n    ARIAAllowedRole = class extends axe_audit_default {\n      static {\n        __name(this, \"ARIAAllowedRole\");\n      }\n      /**\n       * @return {LH.Audit.Meta}\n       */\n      static get meta() {\n        return {\n          id: \"aria-allowed-role\",\n          title: str_7(UIStrings26.title),\n          failureTitle: str_7(UIStrings26.failureTitle),\n          description: str_7(UIStrings26.description),\n          scoreDisplayMode: axe_audit_default.SCORING_MODES.INFORMATIVE,\n          requiredArtifacts: [\"Accessibility\"]\n        };\n      }\n    };\n    aria_allowed_role_default = ARIAAllowedRole;\n  }\n});\n\n// core/audits/accessibility/aria-command-name.js\nvar aria_command_name_exports = {};\n__export(aria_command_name_exports, {\n  UIStrings: () => UIStrings27,\n  default: () => aria_command_name_default\n});\nvar UIStrings27, str_8, AriaCommandName, aria_command_name_default;\nvar init_aria_command_name = __esm({\n  \"core/audits/accessibility/aria-command-name.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_axe_audit();\n    init_i18n();\n    /**\n     * @license\n     * Copyright 2020 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    UIStrings27 = {\n      /** Title of an accessibility audit that evaluates if important HTML elements have an accessible name. This title is descriptive of the successful state and is shown to users when no user action is required. */\n      title: \"`button`, `link`, and `menuitem` elements have accessible names\",\n      /** Title of an accessibility audit that evaluates if important HTML elements do not have accessible names. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed. */\n      failureTitle: \"`button`, `link`, and `menuitem` elements do not have accessible names.\",\n      /** Description of a Lighthouse audit that tells the user *why* they should have accessible names for HTML elements. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */\n      description: \"When an element doesn't have an accessible name, screen readers announce it with a generic name, making it unusable for users who rely on screen readers. [Learn how to make command elements more accessible](https://dequeuniversity.com/rules/axe/4.11/aria-command-name).\"\n    };\n    str_8 = createIcuMessageFn({ url: \"core/audits/accessibility/aria-command-name.js\" }.url, UIStrings27);\n    AriaCommandName = class extends axe_audit_default {\n      static {\n        __name(this, \"AriaCommandName\");\n      }\n      /**\n       * @return {LH.Audit.Meta}\n       */\n      static get meta() {\n        return {\n          id: \"aria-command-name\",\n          title: str_8(UIStrings27.title),\n          failureTitle: str_8(UIStrings27.failureTitle),\n          description: str_8(UIStrings27.description),\n          requiredArtifacts: [\"Accessibility\"]\n        };\n      }\n    };\n    aria_command_name_default = AriaCommandName;\n  }\n});\n\n// core/audits/accessibility/aria-conditional-attr.js\nvar aria_conditional_attr_exports = {};\n__export(aria_conditional_attr_exports, {\n  UIStrings: () => UIStrings28,\n  default: () => aria_conditional_attr_default\n});\nvar UIStrings28, str_9, AriaConditionalAttr, aria_conditional_attr_default;\nvar init_aria_conditional_attr = __esm({\n  \"core/audits/accessibility/aria-conditional-attr.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_axe_audit();\n    init_i18n();\n    /**\n     * @license\n     * Copyright 2024 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    UIStrings28 = {\n      /** Title of an accessibility audit that checks if ARIA attributes are used as specified for element roles. This title is descriptive of the successful state and is shown to users when no user action is required. */\n      title: \"ARIA attributes are used as specified for the element's role\",\n      /** Title of an accessibility audit that checks if ARIA attributes are used as specified for element roles. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed. */\n      failureTitle: \"ARIA attributes are not used as specified for the element's role\",\n      /** Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */\n      description: \"Some ARIA attributes are only allowed on an element under certain conditions. [Learn more about conditional ARIA attributes](https://dequeuniversity.com/rules/axe/4.11/aria-conditional-attr).\"\n    };\n    str_9 = createIcuMessageFn({ url: \"core/audits/accessibility/aria-conditional-attr.js\" }.url, UIStrings28);\n    AriaConditionalAttr = class extends axe_audit_default {\n      static {\n        __name(this, \"AriaConditionalAttr\");\n      }\n      /**\n       * @return {LH.Audit.Meta}\n       */\n      static get meta() {\n        return {\n          id: \"aria-conditional-attr\",\n          title: str_9(UIStrings28.title),\n          failureTitle: str_9(UIStrings28.failureTitle),\n          description: str_9(UIStrings28.description),\n          requiredArtifacts: [\"Accessibility\"]\n        };\n      }\n    };\n    aria_conditional_attr_default = AriaConditionalAttr;\n  }\n});\n\n// core/audits/accessibility/aria-deprecated-role.js\nvar aria_deprecated_role_exports = {};\n__export(aria_deprecated_role_exports, {\n  UIStrings: () => UIStrings29,\n  default: () => aria_deprecated_role_default\n});\nvar UIStrings29, str_10, AriaDeprecatedRole, aria_deprecated_role_default;\nvar init_aria_deprecated_role = __esm({\n  \"core/audits/accessibility/aria-deprecated-role.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_axe_audit();\n    init_i18n();\n    /**\n     * @license\n     * Copyright 2024 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    UIStrings29 = {\n      /** Title of an accessibility audit that checks if deprecated ARIA roles are used. This title is descriptive of the successful state and is shown to users when no user action is required. */\n      title: \"Deprecated ARIA roles were not used\",\n      /** Title of an accessibility audit that checks if deprecated ARIA roles are used. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed. */\n      failureTitle: \"Deprecated ARIA roles were used\",\n      /** Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */\n      description: \"Deprecated ARIA roles may not be processed correctly by assistive technology. [Learn more about deprecated ARIA roles](https://dequeuniversity.com/rules/axe/4.11/aria-deprecated-role).\"\n    };\n    str_10 = createIcuMessageFn({ url: \"core/audits/accessibility/aria-deprecated-role.js\" }.url, UIStrings29);\n    AriaDeprecatedRole = class extends axe_audit_default {\n      static {\n        __name(this, \"AriaDeprecatedRole\");\n      }\n      /**\n       * @return {LH.Audit.Meta}\n       */\n      static get meta() {\n        return {\n          id: \"aria-deprecated-role\",\n          title: str_10(UIStrings29.title),\n          failureTitle: str_10(UIStrings29.failureTitle),\n          description: str_10(UIStrings29.description),\n          requiredArtifacts: [\"Accessibility\"]\n        };\n      }\n    };\n    aria_deprecated_role_default = AriaDeprecatedRole;\n  }\n});\n\n// core/audits/accessibility/aria-dialog-name.js\nvar aria_dialog_name_exports = {};\n__export(aria_dialog_name_exports, {\n  UIStrings: () => UIStrings30,\n  default: () => aria_dialog_name_default\n});\nvar UIStrings30, str_11, AriaDialogName, aria_dialog_name_default;\nvar init_aria_dialog_name = __esm({\n  \"core/audits/accessibility/aria-dialog-name.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_axe_audit();\n    init_i18n();\n    /**\n     * @license\n     * Copyright 2023 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    UIStrings30 = {\n      /** Title of an accessibility audit that evaluates if ARIA dialog elements have an accessible name. This title is descriptive of the successful state and is shown to users when no user action is required. */\n      title: 'Elements with `role=\"dialog\"` or `role=\"alertdialog\"` have accessible names.',\n      /** Title of an accessibility audit that evaluates if ARIA dialog elements do not have accessible names. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed. */\n      failureTitle: 'Elements with `role=\"dialog\"` or `role=\"alertdialog\"` do not have accessible names.',\n      /** Description of a Lighthouse audit that tells the user *why* they should have accessible names for ARIA dialog elements. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */\n      description: \"ARIA dialog elements without accessible names may prevent screen readers users from discerning the purpose of these elements. [Learn how to make ARIA dialog elements more accessible](https://dequeuniversity.com/rules/axe/4.11/aria-dialog-name).\"\n    };\n    str_11 = createIcuMessageFn({ url: \"core/audits/accessibility/aria-dialog-name.js\" }.url, UIStrings30);\n    AriaDialogName = class extends axe_audit_default {\n      static {\n        __name(this, \"AriaDialogName\");\n      }\n      /**\n       * @return {LH.Audit.Meta}\n       */\n      static get meta() {\n        return {\n          id: \"aria-dialog-name\",\n          title: str_11(UIStrings30.title),\n          failureTitle: str_11(UIStrings30.failureTitle),\n          description: str_11(UIStrings30.description),\n          requiredArtifacts: [\"Accessibility\"]\n        };\n      }\n    };\n    aria_dialog_name_default = AriaDialogName;\n  }\n});\n\n// core/audits/accessibility/aria-hidden-body.js\nvar aria_hidden_body_exports = {};\n__export(aria_hidden_body_exports, {\n  UIStrings: () => UIStrings31,\n  default: () => aria_hidden_body_default\n});\nvar UIStrings31, str_12, AriaHiddenBody, aria_hidden_body_default;\nvar init_aria_hidden_body = __esm({\n  \"core/audits/accessibility/aria-hidden-body.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_axe_audit();\n    init_i18n();\n    /**\n     * @license\n     * Copyright 2019 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    UIStrings31 = {\n      /** Title of an accessibility audit that checks if the html <body> element does not have an aria-hidden attribute set on it. This title is descriptive of the successful state and is shown to users when no user action is required. */\n      title: '`[aria-hidden=\"true\"]` is not present on the document `<body>`',\n      /** Title of an accessibility audit that checks if the html <body> element does not have an aria-hidden attribute set on it. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed. */\n      failureTitle: '`[aria-hidden=\"true\"]` is present on the document `<body>`',\n      /** Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */\n      description: 'Assistive technologies, like screen readers, work inconsistently when `aria-hidden=\"true\"` is set on the document `<body>`. [Learn how `aria-hidden` affects the document body](https://dequeuniversity.com/rules/axe/4.11/aria-hidden-body).'\n    };\n    str_12 = createIcuMessageFn({ url: \"core/audits/accessibility/aria-hidden-body.js\" }.url, UIStrings31);\n    AriaHiddenBody = class extends axe_audit_default {\n      static {\n        __name(this, \"AriaHiddenBody\");\n      }\n      /**\n       * @return {LH.Audit.Meta}\n       */\n      static get meta() {\n        return {\n          id: \"aria-hidden-body\",\n          title: str_12(UIStrings31.title),\n          failureTitle: str_12(UIStrings31.failureTitle),\n          description: str_12(UIStrings31.description),\n          requiredArtifacts: [\"Accessibility\"]\n        };\n      }\n    };\n    aria_hidden_body_default = AriaHiddenBody;\n  }\n});\n\n// core/audits/accessibility/aria-hidden-focus.js\nvar aria_hidden_focus_exports = {};\n__export(aria_hidden_focus_exports, {\n  UIStrings: () => UIStrings32,\n  default: () => aria_hidden_focus_default\n});\nvar UIStrings32, str_13, AriaHiddenFocus, aria_hidden_focus_default;\nvar init_aria_hidden_focus = __esm({\n  \"core/audits/accessibility/aria-hidden-focus.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_axe_audit();\n    init_i18n();\n    /**\n     * @license\n     * Copyright 2019 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    UIStrings32 = {\n      /** Title of an accessibility audit that checks if all elements that have an aria-hidden attribute do not contain focusable descendent elements. This title is descriptive of the successful state and is shown to users when no user action is required. */\n      title: '`[aria-hidden=\"true\"]` elements do not contain focusable descendents',\n      /** Title of an accessibility audit that checks if all elements that have an aria-hidden attribute do not contain focusable descendent elements. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed. */\n      failureTitle: '`[aria-hidden=\"true\"]` elements contain focusable descendents',\n      /** Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */\n      description: 'Focusable descendents within an `[aria-hidden=\"true\"]` element prevent those interactive elements from being available to users of assistive technologies like screen readers. [Learn how `aria-hidden` affects focusable elements](https://dequeuniversity.com/rules/axe/4.11/aria-hidden-focus).'\n    };\n    str_13 = createIcuMessageFn({ url: \"core/audits/accessibility/aria-hidden-focus.js\" }.url, UIStrings32);\n    AriaHiddenFocus = class extends axe_audit_default {\n      static {\n        __name(this, \"AriaHiddenFocus\");\n      }\n      /**\n       * @return {LH.Audit.Meta}\n       */\n      static get meta() {\n        return {\n          id: \"aria-hidden-focus\",\n          title: str_13(UIStrings32.title),\n          failureTitle: str_13(UIStrings32.failureTitle),\n          description: str_13(UIStrings32.description),\n          requiredArtifacts: [\"Accessibility\"]\n        };\n      }\n    };\n    aria_hidden_focus_default = AriaHiddenFocus;\n  }\n});\n\n// core/audits/accessibility/aria-input-field-name.js\nvar aria_input_field_name_exports = {};\n__export(aria_input_field_name_exports, {\n  UIStrings: () => UIStrings33,\n  default: () => aria_input_field_name_default\n});\nvar UIStrings33, str_14, AriaInputFieldName, aria_input_field_name_default;\nvar init_aria_input_field_name = __esm({\n  \"core/audits/accessibility/aria-input-field-name.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_axe_audit();\n    init_i18n();\n    /**\n     * @license\n     * Copyright 2019 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    UIStrings33 = {\n      /** Title of an accessibility audit that checks that all ARIA input fields have an accessible name. This title is descriptive of the successful state and is shown to users when no user action is required. */\n      title: \"ARIA input fields have accessible names\",\n      /** Title of an accessibility audit that checks that all ARIA input fields have an accessible name. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed. */\n      failureTitle: \"ARIA input fields do not have accessible names\",\n      /** Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */\n      description: \"When an input field doesn't have an accessible name, screen readers announce it with a generic name, making it unusable for users who rely on screen readers. [Learn more about input field labels](https://dequeuniversity.com/rules/axe/4.11/aria-input-field-name).\"\n    };\n    str_14 = createIcuMessageFn({ url: \"core/audits/accessibility/aria-input-field-name.js\" }.url, UIStrings33);\n    AriaInputFieldName = class extends axe_audit_default {\n      static {\n        __name(this, \"AriaInputFieldName\");\n      }\n      /**\n       * @return {LH.Audit.Meta}\n       */\n      static get meta() {\n        return {\n          id: \"aria-input-field-name\",\n          title: str_14(UIStrings33.title),\n          failureTitle: str_14(UIStrings33.failureTitle),\n          description: str_14(UIStrings33.description),\n          requiredArtifacts: [\"Accessibility\"]\n        };\n      }\n    };\n    aria_input_field_name_default = AriaInputFieldName;\n  }\n});\n\n// core/audits/accessibility/aria-meter-name.js\nvar aria_meter_name_exports = {};\n__export(aria_meter_name_exports, {\n  UIStrings: () => UIStrings34,\n  default: () => aria_meter_name_default\n});\nvar UIStrings34, str_15, AriaMeterName, aria_meter_name_default;\nvar init_aria_meter_name = __esm({\n  \"core/audits/accessibility/aria-meter-name.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_axe_audit();\n    init_i18n();\n    /**\n     * @license\n     * Copyright 2020 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    UIStrings34 = {\n      /** Title of an accessibility audit that evaluates if meter HTML elements have an accessible name. This title is descriptive of the successful state and is shown to users when no user action is required. */\n      title: \"ARIA `meter` elements have accessible names\",\n      /** Title of an accessibility audit that evaluates if meter HTML elements do not have accessible names. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed. */\n      failureTitle: \"ARIA `meter` elements do not have accessible names.\",\n      /** Description of a Lighthouse audit that tells the user *why* they should have accessible names for HTML 'meter' elements. This is displayed after a user expands the section to see more. No character length limits. 'Learn how...' becomes link text to additional documentation. */\n      description: \"When a meter element doesn't have an accessible name, screen readers announce it with a generic name, making it unusable for users who rely on screen readers. [Learn how to name `meter` elements](https://dequeuniversity.com/rules/axe/4.11/aria-meter-name).\"\n    };\n    str_15 = createIcuMessageFn({ url: \"core/audits/accessibility/aria-meter-name.js\" }.url, UIStrings34);\n    AriaMeterName = class extends axe_audit_default {\n      static {\n        __name(this, \"AriaMeterName\");\n      }\n      /**\n       * @return {LH.Audit.Meta}\n       */\n      static get meta() {\n        return {\n          id: \"aria-meter-name\",\n          title: str_15(UIStrings34.title),\n          failureTitle: str_15(UIStrings34.failureTitle),\n          description: str_15(UIStrings34.description),\n          requiredArtifacts: [\"Accessibility\"]\n        };\n      }\n    };\n    aria_meter_name_default = AriaMeterName;\n  }\n});\n\n// core/audits/accessibility/aria-progressbar-name.js\nvar aria_progressbar_name_exports = {};\n__export(aria_progressbar_name_exports, {\n  UIStrings: () => UIStrings35,\n  default: () => aria_progressbar_name_default\n});\nvar UIStrings35, str_16, AriaProgressbarName, aria_progressbar_name_default;\nvar init_aria_progressbar_name = __esm({\n  \"core/audits/accessibility/aria-progressbar-name.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_axe_audit();\n    init_i18n();\n    /**\n     * @license\n     * Copyright 2020 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    UIStrings35 = {\n      /** Title of an accessibility audit that evaluates if progressbar HTML elements have an accessible name. This title is descriptive of the successful state and is shown to users when no user action is required. */\n      title: \"ARIA `progressbar` elements have accessible names\",\n      /** Title of an accessibility audit that evaluates if progressbar HTML elements do not have accessible names. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed. */\n      failureTitle: \"ARIA `progressbar` elements do not have accessible names.\",\n      /** Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */\n      description: \"When a `progressbar` element doesn't have an accessible name, screen readers announce it with a generic name, making it unusable for users who rely on screen readers. [Learn how to label `progressbar` elements](https://dequeuniversity.com/rules/axe/4.11/aria-progressbar-name).\"\n    };\n    str_16 = createIcuMessageFn({ url: \"core/audits/accessibility/aria-progressbar-name.js\" }.url, UIStrings35);\n    AriaProgressbarName = class extends axe_audit_default {\n      static {\n        __name(this, \"AriaProgressbarName\");\n      }\n      /**\n       * @return {LH.Audit.Meta}\n       */\n      static get meta() {\n        return {\n          id: \"aria-progressbar-name\",\n          title: str_16(UIStrings35.title),\n          failureTitle: str_16(UIStrings35.failureTitle),\n          description: str_16(UIStrings35.description),\n          requiredArtifacts: [\"Accessibility\"]\n        };\n      }\n    };\n    aria_progressbar_name_default = AriaProgressbarName;\n  }\n});\n\n// core/audits/accessibility/aria-prohibited-attr.js\nvar aria_prohibited_attr_exports = {};\n__export(aria_prohibited_attr_exports, {\n  UIStrings: () => UIStrings36,\n  default: () => aria_prohibited_attr_default\n});\nvar UIStrings36, str_17, AriaProhibitedAttr, aria_prohibited_attr_default;\nvar init_aria_prohibited_attr = __esm({\n  \"core/audits/accessibility/aria-prohibited-attr.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_axe_audit();\n    init_i18n();\n    /**\n     * @license\n     * Copyright 2024 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    UIStrings36 = {\n      /** Title of an accessibility audit that checks if elements use prohibited ARIA attributes. This title is descriptive of the successful state and is shown to users when no user action is required. */\n      title: \"Elements use only permitted ARIA attributes\",\n      /** Title of an accessibility audit that checks if elements use prohibited ARIA attributes. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed. */\n      failureTitle: \"Elements use prohibited ARIA attributes\",\n      /** Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */\n      description: \"Using ARIA attributes in roles where they are prohibited can mean that important information is not communicated to users of assistive technologies. [Learn more about prohibited ARIA roles](https://dequeuniversity.com/rules/axe/4.11/aria-prohibited-attr).\"\n    };\n    str_17 = createIcuMessageFn({ url: \"core/audits/accessibility/aria-prohibited-attr.js\" }.url, UIStrings36);\n    AriaProhibitedAttr = class extends axe_audit_default {\n      static {\n        __name(this, \"AriaProhibitedAttr\");\n      }\n      /**\n       * @return {LH.Audit.Meta}\n       */\n      static get meta() {\n        return {\n          id: \"aria-prohibited-attr\",\n          title: str_17(UIStrings36.title),\n          failureTitle: str_17(UIStrings36.failureTitle),\n          description: str_17(UIStrings36.description),\n          requiredArtifacts: [\"Accessibility\"]\n        };\n      }\n    };\n    aria_prohibited_attr_default = AriaProhibitedAttr;\n  }\n});\n\n// core/audits/accessibility/aria-required-attr.js\nvar aria_required_attr_exports = {};\n__export(aria_required_attr_exports, {\n  UIStrings: () => UIStrings37,\n  default: () => aria_required_attr_default\n});\nvar UIStrings37, str_18, ARIARequiredAttr, aria_required_attr_default;\nvar init_aria_required_attr = __esm({\n  \"core/audits/accessibility/aria-required-attr.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_axe_audit();\n    init_i18n();\n    /**\n     * @license\n     * Copyright 2017 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    UIStrings37 = {\n      /** Title of an accessibility audit that evaluates if all elements with the aria-role attribute have the other corresponding ARIA attributes set as well. This title is descriptive of the successful state and is shown to users when no user action is required. */\n      title: \"`[role]`s have all required `[aria-*]` attributes\",\n      /** Title of an accessibility audit that evaluates if all elements with the aria-role attribute have the other corresponding ARIA attributes set as well. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed. */\n      failureTitle: \"`[role]`s do not have all required `[aria-*]` attributes\",\n      /** Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */\n      description: \"Some ARIA roles have required attributes that describe the state of the element to screen readers. [Learn more about roles and required attributes](https://dequeuniversity.com/rules/axe/4.11/aria-required-attr).\"\n    };\n    str_18 = createIcuMessageFn({ url: \"core/audits/accessibility/aria-required-attr.js\" }.url, UIStrings37);\n    ARIARequiredAttr = class extends axe_audit_default {\n      static {\n        __name(this, \"ARIARequiredAttr\");\n      }\n      /**\n       * @return {LH.Audit.Meta}\n       */\n      static get meta() {\n        return {\n          id: \"aria-required-attr\",\n          title: str_18(UIStrings37.title),\n          failureTitle: str_18(UIStrings37.failureTitle),\n          description: str_18(UIStrings37.description),\n          requiredArtifacts: [\"Accessibility\"]\n        };\n      }\n    };\n    aria_required_attr_default = ARIARequiredAttr;\n  }\n});\n\n// core/audits/accessibility/aria-required-children.js\nvar aria_required_children_exports = {};\n__export(aria_required_children_exports, {\n  UIStrings: () => UIStrings38,\n  default: () => aria_required_children_default\n});\nvar UIStrings38, str_19, AriaRequiredChildren, aria_required_children_default;\nvar init_aria_required_children = __esm({\n  \"core/audits/accessibility/aria-required-children.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_axe_audit();\n    init_i18n();\n    /**\n     * @license\n     * Copyright 2017 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    UIStrings38 = {\n      /** Title of an accessibility audit that evaluates if the elements with an aria-role that require child elements have the required children. This title is descriptive of the successful state and is shown to users when no user action is required. */\n      title: \"Elements with an ARIA `[role]` that require children to contain a specific `[role]` have all required children.\",\n      /** Title of an accessibility audit that evaluates if the elements with an aria-role that require child elements have the required children. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed. */\n      failureTitle: \"Elements with an ARIA `[role]` that require children to contain a specific `[role]` are missing some or all of those required children.\",\n      /** Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */\n      description: \"Some ARIA parent roles must contain specific child roles to perform their intended accessibility functions. [Learn more about roles and required children elements](https://dequeuniversity.com/rules/axe/4.11/aria-required-children).\"\n    };\n    str_19 = createIcuMessageFn({ url: \"core/audits/accessibility/aria-required-children.js\" }.url, UIStrings38);\n    AriaRequiredChildren = class extends axe_audit_default {\n      static {\n        __name(this, \"AriaRequiredChildren\");\n      }\n      /**\n       * @return {LH.Audit.Meta}\n       */\n      static get meta() {\n        return {\n          id: \"aria-required-children\",\n          title: str_19(UIStrings38.title),\n          failureTitle: str_19(UIStrings38.failureTitle),\n          description: str_19(UIStrings38.description),\n          requiredArtifacts: [\"Accessibility\"]\n        };\n      }\n    };\n    aria_required_children_default = AriaRequiredChildren;\n  }\n});\n\n// core/audits/accessibility/aria-required-parent.js\nvar aria_required_parent_exports = {};\n__export(aria_required_parent_exports, {\n  UIStrings: () => UIStrings39,\n  default: () => aria_required_parent_default\n});\nvar UIStrings39, str_20, AriaRequiredParent, aria_required_parent_default;\nvar init_aria_required_parent = __esm({\n  \"core/audits/accessibility/aria-required-parent.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_axe_audit();\n    init_i18n();\n    /**\n     * @license\n     * Copyright 2017 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    UIStrings39 = {\n      /** Title of an accessibility audit that evaluates valid aria-role usage. Some ARIA roles require that elements must be a child of specific parent element. This audit checks that when those roles are used, the element with the role is in fact a child of the required parent. This title is descriptive of the successful state and is shown to users when no user action is required. */\n      title: \"`[role]`s are contained by their required parent element\",\n      /** Title of an accessibility audit that evaluates valid aria-role usage. Some ARIA roles require that elements must be a child of specific parent element. This audit checks that when those roles are used, the element with the role is in fact a child of the required parent. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed. */\n      failureTitle: \"`[role]`s are not contained by their required parent element\",\n      /** Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */\n      description: \"Some ARIA child roles must be contained by specific parent roles to properly perform their intended accessibility functions. [Learn more about ARIA roles and required parent element](https://dequeuniversity.com/rules/axe/4.11/aria-required-parent).\"\n    };\n    str_20 = createIcuMessageFn({ url: \"core/audits/accessibility/aria-required-parent.js\" }.url, UIStrings39);\n    AriaRequiredParent = class extends axe_audit_default {\n      static {\n        __name(this, \"AriaRequiredParent\");\n      }\n      /**\n       * @return {LH.Audit.Meta}\n       */\n      static get meta() {\n        return {\n          id: \"aria-required-parent\",\n          title: str_20(UIStrings39.title),\n          failureTitle: str_20(UIStrings39.failureTitle),\n          description: str_20(UIStrings39.description),\n          requiredArtifacts: [\"Accessibility\"]\n        };\n      }\n    };\n    aria_required_parent_default = AriaRequiredParent;\n  }\n});\n\n// core/audits/accessibility/aria-roles.js\nvar aria_roles_exports = {};\n__export(aria_roles_exports, {\n  UIStrings: () => UIStrings40,\n  default: () => aria_roles_default\n});\nvar UIStrings40, str_21, AriaRoles, aria_roles_default;\nvar init_aria_roles = __esm({\n  \"core/audits/accessibility/aria-roles.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_axe_audit();\n    init_i18n();\n    /**\n     * @license\n     * Copyright 2017 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    UIStrings40 = {\n      /** Title of an accessibility audit that evaluates if all elements have valid aria-role HTML attributes. This title is descriptive of the successful state and is shown to users when no user action is required. */\n      title: \"`[role]` values are valid\",\n      /** Title of an accessibility audit that evaluates if all elements have valid aria-role HTML attributes. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed. */\n      failureTitle: \"`[role]` values are not valid\",\n      /** Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */\n      description: \"ARIA roles must have valid values in order to perform their intended accessibility functions. [Learn more about valid ARIA roles](https://dequeuniversity.com/rules/axe/4.11/aria-roles).\"\n    };\n    str_21 = createIcuMessageFn({ url: \"core/audits/accessibility/aria-roles.js\" }.url, UIStrings40);\n    AriaRoles = class extends axe_audit_default {\n      static {\n        __name(this, \"AriaRoles\");\n      }\n      /**\n       * @return {LH.Audit.Meta}\n       */\n      static get meta() {\n        return {\n          id: \"aria-roles\",\n          title: str_21(UIStrings40.title),\n          failureTitle: str_21(UIStrings40.failureTitle),\n          description: str_21(UIStrings40.description),\n          requiredArtifacts: [\"Accessibility\"]\n        };\n      }\n    };\n    aria_roles_default = AriaRoles;\n  }\n});\n\n// core/audits/accessibility/aria-text.js\nvar aria_text_exports = {};\n__export(aria_text_exports, {\n  UIStrings: () => UIStrings41,\n  default: () => aria_text_default\n});\nvar UIStrings41, str_22, AriaText, aria_text_default;\nvar init_aria_text = __esm({\n  \"core/audits/accessibility/aria-text.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_axe_audit();\n    init_i18n();\n    /**\n     * @license\n     * Copyright 2023 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    UIStrings41 = {\n      /** Title of an accessibility audit that evaluates if elements with `role=text` have no focusable descendents. This title is descriptive of the successful state and is shown to users when no user action is required. */\n      title: \"Elements with the `role=text` attribute do not have focusable descendents.\",\n      /** Title of an accessibility audit that evaluates if elements with `role=text` have focusable descendents. This title is descriptive of the successful state and is shown to users when no user action is required. */\n      failureTitle: \"Elements with the `role=text` attribute do have focusable descendents.\",\n      /** Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */\n      description: \"Adding `role=text` around a text node split by markup enables VoiceOver to treat it as one phrase, but the element's focusable descendents will not be announced. [Learn more about the `role=text` attribute](https://dequeuniversity.com/rules/axe/4.11/aria-text).\"\n    };\n    str_22 = createIcuMessageFn({ url: \"core/audits/accessibility/aria-text.js\" }.url, UIStrings41);\n    AriaText = class extends axe_audit_default {\n      static {\n        __name(this, \"AriaText\");\n      }\n      /**\n       * @return {LH.Audit.Meta}\n       */\n      static get meta() {\n        return {\n          id: \"aria-text\",\n          title: str_22(UIStrings41.title),\n          failureTitle: str_22(UIStrings41.failureTitle),\n          description: str_22(UIStrings41.description),\n          requiredArtifacts: [\"Accessibility\"]\n        };\n      }\n    };\n    aria_text_default = AriaText;\n  }\n});\n\n// core/audits/accessibility/aria-toggle-field-name.js\nvar aria_toggle_field_name_exports = {};\n__export(aria_toggle_field_name_exports, {\n  UIStrings: () => UIStrings42,\n  default: () => aria_toggle_field_name_default\n});\nvar UIStrings42, str_23, AriaToggleFieldName, aria_toggle_field_name_default;\nvar init_aria_toggle_field_name = __esm({\n  \"core/audits/accessibility/aria-toggle-field-name.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_axe_audit();\n    init_i18n();\n    /**\n     * @license\n     * Copyright 2019 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    UIStrings42 = {\n      /** Title of an accessibility audit that checks that all ARIA toggle fields have an accessible name. This title is descriptive of the successful state and is shown to users when no user action is required. */\n      title: \"ARIA toggle fields have accessible names\",\n      /** Title of an accessibility audit that checks that all ARIA toggle fields have an accessible name. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed. */\n      failureTitle: \"ARIA toggle fields do not have accessible names\",\n      /** Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */\n      description: \"When a toggle field doesn't have an accessible name, screen readers announce it with a generic name, making it unusable for users who rely on screen readers. [Learn more about toggle fields](https://dequeuniversity.com/rules/axe/4.11/aria-toggle-field-name).\"\n    };\n    str_23 = createIcuMessageFn({ url: \"core/audits/accessibility/aria-toggle-field-name.js\" }.url, UIStrings42);\n    AriaToggleFieldName = class extends axe_audit_default {\n      static {\n        __name(this, \"AriaToggleFieldName\");\n      }\n      /**\n       * @return {LH.Audit.Meta}\n       */\n      static get meta() {\n        return {\n          id: \"aria-toggle-field-name\",\n          title: str_23(UIStrings42.title),\n          failureTitle: str_23(UIStrings42.failureTitle),\n          description: str_23(UIStrings42.description),\n          requiredArtifacts: [\"Accessibility\"]\n        };\n      }\n    };\n    aria_toggle_field_name_default = AriaToggleFieldName;\n  }\n});\n\n// core/audits/accessibility/aria-tooltip-name.js\nvar aria_tooltip_name_exports = {};\n__export(aria_tooltip_name_exports, {\n  UIStrings: () => UIStrings43,\n  default: () => aria_tooltip_name_default\n});\nvar UIStrings43, str_24, AriaTooltipName, aria_tooltip_name_default;\nvar init_aria_tooltip_name = __esm({\n  \"core/audits/accessibility/aria-tooltip-name.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_axe_audit();\n    init_i18n();\n    /**\n     * @license\n     * Copyright 2020 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    UIStrings43 = {\n      /** Title of an accessibility audit that evaluates if tooltip HTML elements have an accessible name. This title is descriptive of the successful state and is shown to users when no user action is required. */\n      title: \"ARIA `tooltip` elements have accessible names\",\n      /** Title of an accessibility audit that evaluates if tooltip HTML elements do not have accessible names. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed. */\n      failureTitle: \"ARIA `tooltip` elements do not have accessible names.\",\n      /** Description of a Lighthouse audit that tells the user *why* they should have accessible names for HTML 'tooltip' elements. This is displayed after a user expands the section to see more. No character length limits. 'Learn how...' becomes link text to additional documentation. */\n      description: \"When a tooltip element doesn't have an accessible name, screen readers announce it with a generic name, making it unusable for users who rely on screen readers. [Learn how to name `tooltip` elements](https://dequeuniversity.com/rules/axe/4.11/aria-tooltip-name).\"\n    };\n    str_24 = createIcuMessageFn({ url: \"core/audits/accessibility/aria-tooltip-name.js\" }.url, UIStrings43);\n    AriaTooltipName = class extends axe_audit_default {\n      static {\n        __name(this, \"AriaTooltipName\");\n      }\n      /**\n       * @return {LH.Audit.Meta}\n       */\n      static get meta() {\n        return {\n          id: \"aria-tooltip-name\",\n          title: str_24(UIStrings43.title),\n          failureTitle: str_24(UIStrings43.failureTitle),\n          description: str_24(UIStrings43.description),\n          requiredArtifacts: [\"Accessibility\"]\n        };\n      }\n    };\n    aria_tooltip_name_default = AriaTooltipName;\n  }\n});\n\n// core/audits/accessibility/aria-treeitem-name.js\nvar aria_treeitem_name_exports = {};\n__export(aria_treeitem_name_exports, {\n  UIStrings: () => UIStrings44,\n  default: () => aria_treeitem_name_default\n});\nvar UIStrings44, str_25, AriaTreeitemName, aria_treeitem_name_default;\nvar init_aria_treeitem_name = __esm({\n  \"core/audits/accessibility/aria-treeitem-name.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_axe_audit();\n    init_i18n();\n    /**\n     * @license\n     * Copyright 2020 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    UIStrings44 = {\n      /** Title of an accessibility audit that evaluates if treeitem HTML elements have an accessible name. This title is descriptive of the successful state and is shown to users when no user action is required. */\n      title: \"ARIA `treeitem` elements have accessible names\",\n      /** Title of an accessibility audit that evaluates if treeitem HTML elements do not have accessible names. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed. */\n      failureTitle: \"ARIA `treeitem` elements do not have accessible names.\",\n      /** Description of a Lighthouse audit that tells the user *why* they should have accessible names for HTML elements. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */\n      description: \"When a `treeitem` element doesn't have an accessible name, screen readers announce it with a generic name, making it unusable for users who rely on screen readers. [Learn more about labeling `treeitem` elements](https://dequeuniversity.com/rules/axe/4.11/aria-treeitem-name).\"\n    };\n    str_25 = createIcuMessageFn({ url: \"core/audits/accessibility/aria-treeitem-name.js\" }.url, UIStrings44);\n    AriaTreeitemName = class extends axe_audit_default {\n      static {\n        __name(this, \"AriaTreeitemName\");\n      }\n      /**\n       * @return {LH.Audit.Meta}\n       */\n      static get meta() {\n        return {\n          id: \"aria-treeitem-name\",\n          title: str_25(UIStrings44.title),\n          failureTitle: str_25(UIStrings44.failureTitle),\n          description: str_25(UIStrings44.description),\n          requiredArtifacts: [\"Accessibility\"]\n        };\n      }\n    };\n    aria_treeitem_name_default = AriaTreeitemName;\n  }\n});\n\n// core/audits/accessibility/aria-valid-attr-value.js\nvar aria_valid_attr_value_exports = {};\n__export(aria_valid_attr_value_exports, {\n  UIStrings: () => UIStrings45,\n  default: () => aria_valid_attr_value_default\n});\nvar UIStrings45, str_26, ARIAValidAttr, aria_valid_attr_value_default;\nvar init_aria_valid_attr_value = __esm({\n  \"core/audits/accessibility/aria-valid-attr-value.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_axe_audit();\n    init_i18n();\n    /**\n     * @license\n     * Copyright 2017 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    UIStrings45 = {\n      /** Title of an accessibility audit that evaluates if all elements that have an ARIA HTML attribute have a valid value for that attribute. This title is descriptive of the successful state and is shown to users when no user action is required. */\n      title: \"`[aria-*]` attributes have valid values\",\n      /** Title of an accessibility audit that evaluates if all elements that have an ARIA HTML attribute have a valid value for that attribute. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed. */\n      failureTitle: \"`[aria-*]` attributes do not have valid values\",\n      /** Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */\n      description: \"Assistive technologies, like screen readers, can't interpret ARIA attributes with invalid values. [Learn more about valid values for ARIA attributes](https://dequeuniversity.com/rules/axe/4.11/aria-valid-attr-value).\"\n    };\n    str_26 = createIcuMessageFn({ url: \"core/audits/accessibility/aria-valid-attr-value.js\" }.url, UIStrings45);\n    ARIAValidAttr = class extends axe_audit_default {\n      static {\n        __name(this, \"ARIAValidAttr\");\n      }\n      /**\n       * @return {LH.Audit.Meta}\n       */\n      static get meta() {\n        return {\n          id: \"aria-valid-attr-value\",\n          title: str_26(UIStrings45.title),\n          failureTitle: str_26(UIStrings45.failureTitle),\n          description: str_26(UIStrings45.description),\n          requiredArtifacts: [\"Accessibility\"]\n        };\n      }\n    };\n    aria_valid_attr_value_default = ARIAValidAttr;\n  }\n});\n\n// core/audits/accessibility/aria-valid-attr.js\nvar aria_valid_attr_exports = {};\n__export(aria_valid_attr_exports, {\n  UIStrings: () => UIStrings46,\n  default: () => aria_valid_attr_default\n});\nvar UIStrings46, str_27, ARIAValidAttr2, aria_valid_attr_default;\nvar init_aria_valid_attr = __esm({\n  \"core/audits/accessibility/aria-valid-attr.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_axe_audit();\n    init_i18n();\n    /**\n     * @license\n     * Copyright 2017 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    UIStrings46 = {\n      /** Title of an accessibility audit that evaluates if all elements with ARIA HTML attributes have spelled the name of attribute correctly. This title is descriptive of the successful state and is shown to users when no user action is required. */\n      title: \"`[aria-*]` attributes are valid and not misspelled\",\n      /** Title of an accessibility audit that evaluates if all elements with ARIA HTML attributes have spelled the name of attribute correctly. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed. */\n      failureTitle: \"`[aria-*]` attributes are not valid or misspelled\",\n      /** Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */\n      description: \"Assistive technologies, like screen readers, can't interpret ARIA attributes with invalid names. [Learn more about valid ARIA attributes](https://dequeuniversity.com/rules/axe/4.11/aria-valid-attr).\"\n    };\n    str_27 = createIcuMessageFn({ url: \"core/audits/accessibility/aria-valid-attr.js\" }.url, UIStrings46);\n    ARIAValidAttr2 = class extends axe_audit_default {\n      static {\n        __name(this, \"ARIAValidAttr\");\n      }\n      /**\n       * @return {LH.Audit.Meta}\n       */\n      static get meta() {\n        return {\n          id: \"aria-valid-attr\",\n          title: str_27(UIStrings46.title),\n          failureTitle: str_27(UIStrings46.failureTitle),\n          description: str_27(UIStrings46.description),\n          requiredArtifacts: [\"Accessibility\"]\n        };\n      }\n    };\n    aria_valid_attr_default = ARIAValidAttr2;\n  }\n});\n\n// core/audits/accessibility/button-name.js\nvar button_name_exports = {};\n__export(button_name_exports, {\n  UIStrings: () => UIStrings47,\n  default: () => button_name_default\n});\nvar UIStrings47, str_28, ButtonName, button_name_default;\nvar init_button_name = __esm({\n  \"core/audits/accessibility/button-name.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_axe_audit();\n    init_i18n();\n    /**\n     * @license\n     * Copyright 2017 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    UIStrings47 = {\n      /** Title of an accessibility audit that evaluates if all button elements have names accessible to screen readers. This title is descriptive of the successful state and is shown to users when no user action is required. */\n      title: \"Buttons have an accessible name\",\n      /** Title of an accessibility audit that evaluates if all button elements have names accessible to screen readers. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed. */\n      failureTitle: \"Buttons do not have an accessible name\",\n      /** Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */\n      description: `When a button doesn't have an accessible name, screen readers announce it as \"button\", making it unusable for users who rely on screen readers. [Learn how to make buttons more accessible](https://dequeuniversity.com/rules/axe/4.11/button-name).`\n    };\n    str_28 = createIcuMessageFn({ url: \"core/audits/accessibility/button-name.js\" }.url, UIStrings47);\n    ButtonName = class extends axe_audit_default {\n      static {\n        __name(this, \"ButtonName\");\n      }\n      /**\n       * @return {LH.Audit.Meta}\n       */\n      static get meta() {\n        return {\n          id: \"button-name\",\n          title: str_28(UIStrings47.title),\n          failureTitle: str_28(UIStrings47.failureTitle),\n          description: str_28(UIStrings47.description),\n          requiredArtifacts: [\"Accessibility\"]\n        };\n      }\n    };\n    button_name_default = ButtonName;\n  }\n});\n\n// core/audits/accessibility/bypass.js\nvar bypass_exports = {};\n__export(bypass_exports, {\n  UIStrings: () => UIStrings48,\n  default: () => bypass_default\n});\nvar UIStrings48, str_29, Bypass, bypass_default;\nvar init_bypass = __esm({\n  \"core/audits/accessibility/bypass.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_axe_audit();\n    init_i18n();\n    /**\n     * @license\n     * Copyright 2017 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    UIStrings48 = {\n      /** Title of an accessibility audit that evaluates if the page has elements that let screen reader users skip over repetitive content. `heading`, `skip link`, and `landmark region` are technical terms for the elements that enable quick page navigation. This title is descriptive of the successful state and is shown to users when no user action is required. */\n      title: \"The page contains a heading, skip link, or landmark region\",\n      /** Title of an accessibility audit that evaluates if the page has elements that let screen reader users skip over repetitive content. `heading`, `skip link`, and `landmark region` are technical terms for the elements that enable quick page navigation. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed. */\n      failureTitle: \"The page does not contain a heading, skip link, or landmark region\",\n      /** Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */\n      description: \"Adding ways to bypass repetitive content lets keyboard users navigate the page more efficiently. [Learn more about bypass blocks](https://dequeuniversity.com/rules/axe/4.11/bypass).\"\n    };\n    str_29 = createIcuMessageFn({ url: \"core/audits/accessibility/bypass.js\" }.url, UIStrings48);\n    Bypass = class extends axe_audit_default {\n      static {\n        __name(this, \"Bypass\");\n      }\n      /**\n       * @return {LH.Audit.Meta}\n       */\n      static get meta() {\n        return {\n          id: \"bypass\",\n          title: str_29(UIStrings48.title),\n          failureTitle: str_29(UIStrings48.failureTitle),\n          description: str_29(UIStrings48.description),\n          scoreDisplayMode: axe_audit_default.SCORING_MODES.INFORMATIVE,\n          requiredArtifacts: [\"Accessibility\"]\n        };\n      }\n    };\n    bypass_default = Bypass;\n  }\n});\n\n// core/audits/accessibility/color-contrast.js\nvar color_contrast_exports = {};\n__export(color_contrast_exports, {\n  UIStrings: () => UIStrings49,\n  default: () => color_contrast_default\n});\nvar UIStrings49, str_30, ColorContrast, color_contrast_default;\nvar init_color_contrast = __esm({\n  \"core/audits/accessibility/color-contrast.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_axe_audit();\n    init_i18n();\n    /**\n     * @license\n     * Copyright 2017 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    UIStrings49 = {\n      /** Title of an accessibility audit that evaluates if all foreground colors are distinct enough from their background colors to be legible for users. This title is descriptive of the successful state and is shown to users when no user action is required. */\n      title: \"Background and foreground colors have a sufficient contrast ratio\",\n      /** Title of an accessibility audit that evaluates if all foreground colors are distinct enough from their background colors to be legible for users. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed. */\n      failureTitle: \"Background and foreground colors do not have a sufficient contrast ratio.\",\n      /** Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */\n      description: \"Low-contrast text is difficult or impossible for many users to read. [Learn how to provide sufficient color contrast](https://dequeuniversity.com/rules/axe/4.11/color-contrast).\"\n    };\n    str_30 = createIcuMessageFn({ url: \"core/audits/accessibility/color-contrast.js\" }.url, UIStrings49);\n    ColorContrast = class extends axe_audit_default {\n      static {\n        __name(this, \"ColorContrast\");\n      }\n      /**\n       * @return {LH.Audit.Meta}\n       */\n      static get meta() {\n        return {\n          id: \"color-contrast\",\n          title: str_30(UIStrings49.title),\n          failureTitle: str_30(UIStrings49.failureTitle),\n          description: str_30(UIStrings49.description),\n          requiredArtifacts: [\"Accessibility\"]\n        };\n      }\n    };\n    color_contrast_default = ColorContrast;\n  }\n});\n\n// core/audits/accessibility/definition-list.js\nvar definition_list_exports = {};\n__export(definition_list_exports, {\n  UIStrings: () => UIStrings50,\n  default: () => definition_list_default\n});\nvar UIStrings50, str_31, DefinitionList, definition_list_default;\nvar init_definition_list = __esm({\n  \"core/audits/accessibility/definition-list.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_axe_audit();\n    init_i18n();\n    /**\n     * @license\n     * Copyright 2017 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    UIStrings50 = {\n      /** Title of an accessibility audit that evaluates if all the definition list elements have valid markup for screen readers. This title is descriptive of the successful state and is shown to users when no user action is required. */\n      title: \"`<dl>`'s contain only properly-ordered `<dt>` and `<dd>` groups, `<script>`, `<template>` or `<div>` elements.\",\n      /** Title of an accessibility audit that evaluates if all the definition list elements have valid markup for screen readers. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed. */\n      failureTitle: \"`<dl>`'s do not contain only properly-ordered `<dt>` and `<dd>` groups, `<script>`, `<template>` or `<div>` elements.\",\n      /** Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */\n      description: \"When definition lists are not properly marked up, screen readers may produce confusing or inaccurate output. [Learn how to structure definition lists correctly](https://dequeuniversity.com/rules/axe/4.11/definition-list).\"\n    };\n    str_31 = createIcuMessageFn({ url: \"core/audits/accessibility/definition-list.js\" }.url, UIStrings50);\n    DefinitionList = class extends axe_audit_default {\n      static {\n        __name(this, \"DefinitionList\");\n      }\n      /**\n       * @return {LH.Audit.Meta}\n       */\n      static get meta() {\n        return {\n          id: \"definition-list\",\n          title: str_31(UIStrings50.title),\n          failureTitle: str_31(UIStrings50.failureTitle),\n          description: str_31(UIStrings50.description),\n          requiredArtifacts: [\"Accessibility\"]\n        };\n      }\n    };\n    definition_list_default = DefinitionList;\n  }\n});\n\n// core/audits/accessibility/dlitem.js\nvar dlitem_exports = {};\n__export(dlitem_exports, {\n  UIStrings: () => UIStrings51,\n  default: () => dlitem_default\n});\nvar UIStrings51, str_32, DLItem, dlitem_default;\nvar init_dlitem = __esm({\n  \"core/audits/accessibility/dlitem.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_axe_audit();\n    init_i18n();\n    /**\n     * @license\n     * Copyright 2017 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    UIStrings51 = {\n      /** Title of an accessibility audit that evaluates if all definition list item elements (`<dt>`/`<dd>`) have a definition list parent element (`<dl>`). This title is descriptive of the successful state and is shown to users when no user action is required. */\n      title: \"Definition list items are wrapped in `<dl>` elements\",\n      /** Title of an accessibility audit that evaluates if all definition list item elements (`<dt>`/`<dd>`) have a definition list parent element (`<dl>`). This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed. */\n      failureTitle: \"Definition list items are not wrapped in `<dl>` elements\",\n      /** Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */\n      description: \"Definition list items (`<dt>` and `<dd>`) must be wrapped in a parent `<dl>` element to ensure that screen readers can properly announce them. [Learn how to structure definition lists correctly](https://dequeuniversity.com/rules/axe/4.11/dlitem).\"\n    };\n    str_32 = createIcuMessageFn({ url: \"core/audits/accessibility/dlitem.js\" }.url, UIStrings51);\n    DLItem = class extends axe_audit_default {\n      static {\n        __name(this, \"DLItem\");\n      }\n      /**\n       * @return {LH.Audit.Meta}\n       */\n      static get meta() {\n        return {\n          id: \"dlitem\",\n          title: str_32(UIStrings51.title),\n          failureTitle: str_32(UIStrings51.failureTitle),\n          description: str_32(UIStrings51.description),\n          requiredArtifacts: [\"Accessibility\"]\n        };\n      }\n    };\n    dlitem_default = DLItem;\n  }\n});\n\n// core/audits/accessibility/document-title.js\nvar document_title_exports = {};\n__export(document_title_exports, {\n  UIStrings: () => UIStrings52,\n  default: () => document_title_default\n});\nvar UIStrings52, str_33, DocumentTitle, document_title_default;\nvar init_document_title = __esm({\n  \"core/audits/accessibility/document-title.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_axe_audit();\n    init_i18n();\n    /**\n     * @license\n     * Copyright 2017 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    UIStrings52 = {\n      /** Title of an accessibility audit that evaluates if the page has a <title> element that describes the page. This title is descriptive of the successful state and is shown to users when no user action is required. */\n      title: \"Document has a `<title>` element\",\n      /** Title of an accessibility audit that evaluates if the page has a <title> element that describes the page. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed. */\n      failureTitle: \"Document doesn't have a `<title>` element\",\n      /** Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */\n      description: \"The title gives screen reader users an overview of the page, and search engine users rely on it heavily to determine if a page is relevant to their search. [Learn more about document titles](https://dequeuniversity.com/rules/axe/4.11/document-title).\"\n    };\n    str_33 = createIcuMessageFn({ url: \"core/audits/accessibility/document-title.js\" }.url, UIStrings52);\n    DocumentTitle = class extends axe_audit_default {\n      static {\n        __name(this, \"DocumentTitle\");\n      }\n      /**\n       * @return {LH.Audit.Meta}\n       */\n      static get meta() {\n        return {\n          id: \"document-title\",\n          title: str_33(UIStrings52.title),\n          failureTitle: str_33(UIStrings52.failureTitle),\n          description: str_33(UIStrings52.description),\n          requiredArtifacts: [\"Accessibility\"]\n        };\n      }\n    };\n    document_title_default = DocumentTitle;\n  }\n});\n\n// core/audits/accessibility/duplicate-id-aria.js\nvar duplicate_id_aria_exports = {};\n__export(duplicate_id_aria_exports, {\n  UIStrings: () => UIStrings53,\n  default: () => duplicate_id_aria_default\n});\nvar UIStrings53, str_34, DuplicateIdAria, duplicate_id_aria_default;\nvar init_duplicate_id_aria = __esm({\n  \"core/audits/accessibility/duplicate-id-aria.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_axe_audit();\n    init_i18n();\n    /**\n     * @license\n     * Copyright 2019 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    UIStrings53 = {\n      /** Title of an accessibility audit that checks if there are any duplicate ARIA IDs on the page. This title is descriptive of the successful state and is shown to users when no user action is required. */\n      title: \"ARIA IDs are unique\",\n      /** Title of an accessibility audit that checks if there are any duplicate ARIA IDs on the page. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed. */\n      failureTitle: \"ARIA IDs are not unique\",\n      /** Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */\n      description: \"The value of an ARIA ID must be unique to prevent other instances from being overlooked by assistive technologies. [Learn how to fix duplicate ARIA IDs](https://dequeuniversity.com/rules/axe/4.11/duplicate-id-aria).\"\n    };\n    str_34 = createIcuMessageFn({ url: \"core/audits/accessibility/duplicate-id-aria.js\" }.url, UIStrings53);\n    DuplicateIdAria = class extends axe_audit_default {\n      static {\n        __name(this, \"DuplicateIdAria\");\n      }\n      /**\n       * @return {LH.Audit.Meta}\n       */\n      static get meta() {\n        return {\n          id: \"duplicate-id-aria\",\n          title: str_34(UIStrings53.title),\n          failureTitle: str_34(UIStrings53.failureTitle),\n          description: str_34(UIStrings53.description),\n          scoreDisplayMode: axe_audit_default.SCORING_MODES.INFORMATIVE,\n          requiredArtifacts: [\"Accessibility\"]\n        };\n      }\n    };\n    duplicate_id_aria_default = DuplicateIdAria;\n  }\n});\n\n// core/audits/accessibility/empty-heading.js\nvar empty_heading_exports = {};\n__export(empty_heading_exports, {\n  UIStrings: () => UIStrings54,\n  default: () => empty_heading_default\n});\nvar UIStrings54, str_35, EmptyHeading, empty_heading_default;\nvar init_empty_heading = __esm({\n  \"core/audits/accessibility/empty-heading.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_axe_audit();\n    init_i18n();\n    /**\n     * @license\n     * Copyright 2023 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    UIStrings54 = {\n      /** Title of an accessibility audit that checks if all heading elements have content. This title is descriptive of the successful state and is shown to users when no user action is required. */\n      title: \"All heading elements contain content.\",\n      /** Title of an accessibility audit that checks if all heading elements have content. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed. */\n      failureTitle: \"Heading elements do not contain content.\",\n      /** Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */\n      description: \"A heading with no content or inaccessible text prevent screen reader users from accessing information on the page's structure. [Learn more about headings](https://dequeuniversity.com/rules/axe/4.11/empty-heading).\"\n    };\n    str_35 = createIcuMessageFn({ url: \"core/audits/accessibility/empty-heading.js\" }.url, UIStrings54);\n    EmptyHeading = class extends axe_audit_default {\n      static {\n        __name(this, \"EmptyHeading\");\n      }\n      /**\n       * @return {LH.Audit.Meta}\n       */\n      static get meta() {\n        return {\n          id: \"empty-heading\",\n          title: str_35(UIStrings54.title),\n          failureTitle: str_35(UIStrings54.failureTitle),\n          description: str_35(UIStrings54.description),\n          scoreDisplayMode: axe_audit_default.SCORING_MODES.INFORMATIVE,\n          requiredArtifacts: [\"Accessibility\"]\n        };\n      }\n    };\n    empty_heading_default = EmptyHeading;\n  }\n});\n\n// core/audits/accessibility/form-field-multiple-labels.js\nvar form_field_multiple_labels_exports = {};\n__export(form_field_multiple_labels_exports, {\n  UIStrings: () => UIStrings55,\n  default: () => form_field_multiple_labels_default\n});\nvar UIStrings55, str_36, FormFieldMultipleLabels, form_field_multiple_labels_default;\nvar init_form_field_multiple_labels = __esm({\n  \"core/audits/accessibility/form-field-multiple-labels.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_axe_audit();\n    init_i18n();\n    /**\n     * @license\n     * Copyright 2019 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    UIStrings55 = {\n      /** Title of an accessibility audit that checks if any form fields have multiple label elements. This title is descriptive of the successful state and is shown to users when no user action is required. */\n      title: \"No form fields have multiple labels\",\n      /** Title of an accessibility audit that checks if any form fields have multiple label elements. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed. */\n      failureTitle: \"Form fields have multiple labels\",\n      /** Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */\n      description: \"Form fields with multiple labels can be confusingly announced by assistive technologies like screen readers which use either the first, the last, or all of the labels. [Learn how to use form labels](https://dequeuniversity.com/rules/axe/4.11/form-field-multiple-labels).\"\n    };\n    str_36 = createIcuMessageFn({ url: \"core/audits/accessibility/form-field-multiple-labels.js\" }.url, UIStrings55);\n    FormFieldMultipleLabels = class extends axe_audit_default {\n      static {\n        __name(this, \"FormFieldMultipleLabels\");\n      }\n      /**\n       * @return {LH.Audit.Meta}\n       */\n      static get meta() {\n        return {\n          id: \"form-field-multiple-labels\",\n          title: str_36(UIStrings55.title),\n          failureTitle: str_36(UIStrings55.failureTitle),\n          description: str_36(UIStrings55.description),\n          scoreDisplayMode: axe_audit_default.SCORING_MODES.INFORMATIVE,\n          requiredArtifacts: [\"Accessibility\"]\n        };\n      }\n    };\n    form_field_multiple_labels_default = FormFieldMultipleLabels;\n  }\n});\n\n// core/audits/accessibility/frame-title.js\nvar frame_title_exports = {};\n__export(frame_title_exports, {\n  UIStrings: () => UIStrings56,\n  default: () => frame_title_default\n});\nvar UIStrings56, str_37, FrameTitle, frame_title_default;\nvar init_frame_title = __esm({\n  \"core/audits/accessibility/frame-title.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_axe_audit();\n    init_i18n();\n    /**\n     * @license\n     * Copyright 2017 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    UIStrings56 = {\n      /** Title of an accessibility audit that evaluates if all `<frame>` and `<iframe>` elements on the page have a title HTML attribute to describe their contents. This title is descriptive of the successful state and is shown to users when no user action is required. */\n      title: \"`<frame>` or `<iframe>` elements have a title\",\n      /** Title of an accessibility audit that evaluates if all `<frame>` and `<iframe>` elements on the page have a title HTML attribute to describe their contents. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed. */\n      failureTitle: \"`<frame>` or `<iframe>` elements do not have a title\",\n      /** Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */\n      description: \"Screen reader users rely on frame titles to describe the contents of frames. [Learn more about frame titles](https://dequeuniversity.com/rules/axe/4.11/frame-title).\"\n    };\n    str_37 = createIcuMessageFn({ url: \"core/audits/accessibility/frame-title.js\" }.url, UIStrings56);\n    FrameTitle = class extends axe_audit_default {\n      static {\n        __name(this, \"FrameTitle\");\n      }\n      /**\n       * @return {LH.Audit.Meta}\n       */\n      static get meta() {\n        return {\n          id: \"frame-title\",\n          title: str_37(UIStrings56.title),\n          failureTitle: str_37(UIStrings56.failureTitle),\n          description: str_37(UIStrings56.description),\n          requiredArtifacts: [\"Accessibility\"]\n        };\n      }\n    };\n    frame_title_default = FrameTitle;\n  }\n});\n\n// core/audits/accessibility/heading-order.js\nvar heading_order_exports = {};\n__export(heading_order_exports, {\n  UIStrings: () => UIStrings57,\n  default: () => heading_order_default\n});\nvar UIStrings57, str_38, HeadingOrder, heading_order_default;\nvar init_heading_order = __esm({\n  \"core/audits/accessibility/heading-order.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_axe_audit();\n    init_i18n();\n    /**\n     * @license\n     * Copyright 2019 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    UIStrings57 = {\n      /** Title of an accessibility audit that checks if heading elements (<h1>, <h2>, etc) appear in numeric order and only ever increase in steps of 1. This title is descriptive of the successful state and is shown to users when no user action is required. */\n      title: \"Heading elements appear in a sequentially-descending order\",\n      /** Title of an accessibility audit that checks if heading elements (<h1>, <h2>, etc) appear in numeric order and only ever increase in steps of 1. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed. */\n      failureTitle: \"Heading elements are not in a sequentially-descending order\",\n      /** Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */\n      description: \"Properly ordered headings that do not skip levels convey the semantic structure of the page, making it easier to navigate and understand when using assistive technologies. [Learn more about heading order](https://dequeuniversity.com/rules/axe/4.11/heading-order).\"\n    };\n    str_38 = createIcuMessageFn({ url: \"core/audits/accessibility/heading-order.js\" }.url, UIStrings57);\n    HeadingOrder = class extends axe_audit_default {\n      static {\n        __name(this, \"HeadingOrder\");\n      }\n      /**\n       * @return {LH.Audit.Meta}\n       */\n      static get meta() {\n        return {\n          id: \"heading-order\",\n          title: str_38(UIStrings57.title),\n          failureTitle: str_38(UIStrings57.failureTitle),\n          description: str_38(UIStrings57.description),\n          requiredArtifacts: [\"Accessibility\"]\n        };\n      }\n    };\n    heading_order_default = HeadingOrder;\n  }\n});\n\n// core/audits/accessibility/html-has-lang.js\nvar html_has_lang_exports = {};\n__export(html_has_lang_exports, {\n  UIStrings: () => UIStrings58,\n  default: () => html_has_lang_default\n});\nvar UIStrings58, str_39, HTMLHasLang, html_has_lang_default;\nvar init_html_has_lang = __esm({\n  \"core/audits/accessibility/html-has-lang.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_axe_audit();\n    init_i18n();\n    /**\n     * @license\n     * Copyright 2017 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    UIStrings58 = {\n      /** Title of an accessibility audit that evaluates if the root HTML tag has a lang attribute identifying the page's language. This title is descriptive of the successful state and is shown to users when no user action is required. */\n      title: \"`<html>` element has a `[lang]` attribute\",\n      /** Title of an accessibility audit that evaluates if the root HTML tag has a lang attribute identifying the page's language. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed. */\n      failureTitle: \"`<html>` element does not have a `[lang]` attribute\",\n      /** Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */\n      description: \"If a page doesn't specify a `lang` attribute, a screen reader assumes that the page is in the default language that the user chose when setting up the screen reader. If the page isn't actually in the default language, then the screen reader might not announce the page's text correctly. [Learn more about the `lang` attribute](https://dequeuniversity.com/rules/axe/4.11/html-has-lang).\"\n    };\n    str_39 = createIcuMessageFn({ url: \"core/audits/accessibility/html-has-lang.js\" }.url, UIStrings58);\n    HTMLHasLang = class extends axe_audit_default {\n      static {\n        __name(this, \"HTMLHasLang\");\n      }\n      /**\n       * @return {LH.Audit.Meta}\n       */\n      static get meta() {\n        return {\n          id: \"html-has-lang\",\n          title: str_39(UIStrings58.title),\n          failureTitle: str_39(UIStrings58.failureTitle),\n          description: str_39(UIStrings58.description),\n          requiredArtifacts: [\"Accessibility\"]\n        };\n      }\n    };\n    html_has_lang_default = HTMLHasLang;\n  }\n});\n\n// core/audits/accessibility/html-lang-valid.js\nvar html_lang_valid_exports = {};\n__export(html_lang_valid_exports, {\n  UIStrings: () => UIStrings59,\n  default: () => html_lang_valid_default\n});\nvar UIStrings59, str_40, HTMLLangValid, html_lang_valid_default;\nvar init_html_lang_valid = __esm({\n  \"core/audits/accessibility/html-lang-valid.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_axe_audit();\n    init_i18n();\n    /**\n     * @license\n     * Copyright 2017 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    UIStrings59 = {\n      /** Title of an accessibility audit that evaluates if the value for root HTML tag's lang attribute is a valid BCP 47 language. This title is descriptive of the successful state and is shown to users when no user action is required. */\n      title: \"`<html>` element has a valid value for its `[lang]` attribute\",\n      /** Title of an accessibility audit that evaluates if the value for root HTML tag's lang attribute is a valid BCP 47 language. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed. */\n      failureTitle: \"`<html>` element does not have a valid value for its `[lang]` attribute.\",\n      /** Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */\n      description: \"Specifying a valid [BCP 47 language](https://www.w3.org/International/questions/qa-choosing-language-tags#question) helps screen readers announce text properly. [Learn how to use the `lang` attribute](https://dequeuniversity.com/rules/axe/4.11/html-lang-valid).\"\n    };\n    str_40 = createIcuMessageFn({ url: \"core/audits/accessibility/html-lang-valid.js\" }.url, UIStrings59);\n    HTMLLangValid = class extends axe_audit_default {\n      static {\n        __name(this, \"HTMLLangValid\");\n      }\n      /**\n       * @return {LH.Audit.Meta}\n       */\n      static get meta() {\n        return {\n          id: \"html-lang-valid\",\n          title: str_40(UIStrings59.title),\n          failureTitle: str_40(UIStrings59.failureTitle),\n          description: str_40(UIStrings59.description),\n          requiredArtifacts: [\"Accessibility\"]\n        };\n      }\n    };\n    html_lang_valid_default = HTMLLangValid;\n  }\n});\n\n// core/audits/accessibility/html-xml-lang-mismatch.js\nvar html_xml_lang_mismatch_exports = {};\n__export(html_xml_lang_mismatch_exports, {\n  UIStrings: () => UIStrings60,\n  default: () => html_xml_lang_mismatch_default\n});\nvar UIStrings60, str_41, HTMLXMLLangMismatch, html_xml_lang_mismatch_default;\nvar init_html_xml_lang_mismatch = __esm({\n  \"core/audits/accessibility/html-xml-lang-mismatch.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_axe_audit();\n    init_i18n();\n    /**\n     * @license\n     * Copyright 2023 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    UIStrings60 = {\n      /** Title of an accessibility audit that evaluates if the xml:lang attribute, if present, has the same base language as the `lang` attribute. This title is descriptive of the successful state and is shown to users when no user action is required. */\n      title: \"`<html>` element has an `[xml:lang]` attribute with the same base language as the `[lang]` attribute.\",\n      /** Title of an accessibility audit that evaluates if the xml:lang attribute, if present, has the same base language as the `lang` attribute. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed. */\n      failureTitle: \"`<html>` element does not have an `[xml:lang]` attribute with the same base language as the `[lang]` attribute.\",\n      /** Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */\n      description: \"If the webpage does not specify a consistent language, then the screen reader might not announce the page's text correctly. [Learn more about the `lang` attribute](https://dequeuniversity.com/rules/axe/4.11/html-xml-lang-mismatch).\"\n    };\n    str_41 = createIcuMessageFn({ url: \"core/audits/accessibility/html-xml-lang-mismatch.js\" }.url, UIStrings60);\n    HTMLXMLLangMismatch = class extends axe_audit_default {\n      static {\n        __name(this, \"HTMLXMLLangMismatch\");\n      }\n      /**\n       * @return {LH.Audit.Meta}\n       */\n      static get meta() {\n        return {\n          id: \"html-xml-lang-mismatch\",\n          title: str_41(UIStrings60.title),\n          failureTitle: str_41(UIStrings60.failureTitle),\n          description: str_41(UIStrings60.description),\n          requiredArtifacts: [\"Accessibility\"]\n        };\n      }\n    };\n    html_xml_lang_mismatch_default = HTMLXMLLangMismatch;\n  }\n});\n\n// core/audits/accessibility/identical-links-same-purpose.js\nvar identical_links_same_purpose_exports = {};\n__export(identical_links_same_purpose_exports, {\n  UIStrings: () => UIStrings61,\n  default: () => identical_links_same_purpose_default\n});\nvar UIStrings61, str_42, IdenticalLinksSamePurpose, identical_links_same_purpose_default;\nvar init_identical_links_same_purpose = __esm({\n  \"core/audits/accessibility/identical-links-same-purpose.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_axe_audit();\n    init_i18n();\n    /**\n     * @license\n     * Copyright 2023 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    UIStrings61 = {\n      /** Title of an accessibility audit that checks if identical links have the same purpose. This title is descriptive of the successful state and is shown to users when no user action is required. */\n      title: \"Identical links have the same purpose.\",\n      /** Title of an accessibility audit that checks if identical links have the same purpose. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed. */\n      failureTitle: \"Identical links do not have the same purpose.\",\n      /** Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */\n      description: \"Links with the same destination should have the same description, to help users understand the link's purpose and decide whether to follow it. [Learn more about identical links](https://dequeuniversity.com/rules/axe/4.11/identical-links-same-purpose).\"\n    };\n    str_42 = createIcuMessageFn({ url: \"core/audits/accessibility/identical-links-same-purpose.js\" }.url, UIStrings61);\n    IdenticalLinksSamePurpose = class extends axe_audit_default {\n      static {\n        __name(this, \"IdenticalLinksSamePurpose\");\n      }\n      /**\n       * @return {LH.Audit.Meta}\n       */\n      static get meta() {\n        return {\n          id: \"identical-links-same-purpose\",\n          title: str_42(UIStrings61.title),\n          failureTitle: str_42(UIStrings61.failureTitle),\n          description: str_42(UIStrings61.description),\n          scoreDisplayMode: axe_audit_default.SCORING_MODES.INFORMATIVE,\n          requiredArtifacts: [\"Accessibility\"]\n        };\n      }\n    };\n    identical_links_same_purpose_default = IdenticalLinksSamePurpose;\n  }\n});\n\n// core/audits/accessibility/image-alt.js\nvar image_alt_exports = {};\n__export(image_alt_exports, {\n  UIStrings: () => UIStrings62,\n  default: () => image_alt_default\n});\nvar UIStrings62, str_43, ImageAlt, image_alt_default;\nvar init_image_alt = __esm({\n  \"core/audits/accessibility/image-alt.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_axe_audit();\n    init_i18n();\n    /**\n     * @license\n     * Copyright 2017 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    UIStrings62 = {\n      /** Title of an accessibility audit that evaluates if all image elements have the alt HTML attribute to describe their contents. This title is descriptive of the successful state and is shown to users when no user action is required. */\n      title: \"Image elements have `[alt]` attributes\",\n      /** Title of an accessibility audit that evaluates if all image elements have the alt HTML attribute to describe their contents. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed. */\n      failureTitle: \"Image elements do not have `[alt]` attributes\",\n      /** Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */\n      description: \"Informative elements should aim for short, descriptive alternate text. Decorative elements can be ignored with an empty alt attribute. [Learn more about the `alt` attribute](https://dequeuniversity.com/rules/axe/4.11/image-alt).\"\n    };\n    str_43 = createIcuMessageFn({ url: \"core/audits/accessibility/image-alt.js\" }.url, UIStrings62);\n    ImageAlt = class extends axe_audit_default {\n      static {\n        __name(this, \"ImageAlt\");\n      }\n      /**\n       * @return {LH.Audit.Meta}\n       */\n      static get meta() {\n        return {\n          id: \"image-alt\",\n          title: str_43(UIStrings62.title),\n          failureTitle: str_43(UIStrings62.failureTitle),\n          description: str_43(UIStrings62.description),\n          requiredArtifacts: [\"Accessibility\"]\n        };\n      }\n    };\n    image_alt_default = ImageAlt;\n  }\n});\n\n// core/audits/accessibility/image-redundant-alt.js\nvar image_redundant_alt_exports = {};\n__export(image_redundant_alt_exports, {\n  UIStrings: () => UIStrings63,\n  default: () => image_redundant_alt_default\n});\nvar UIStrings63, str_44, ImageRedundantAlt, image_redundant_alt_default;\nvar init_image_redundant_alt = __esm({\n  \"core/audits/accessibility/image-redundant-alt.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_axe_audit();\n    init_i18n();\n    /**\n     * @license\n     * Copyright 2023 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    UIStrings63 = {\n      /** Title of an accessibility audit that evaluates if all image elements have the alt HTML attribute that is not redundant. This title is descriptive of the successful state and is shown to users when no user action is required. */\n      title: \"Image elements do not have `[alt]` attributes that are redundant text.\",\n      /** Title of an accessibility audit that evaluates if all image elements have the alt HTML attribute that is not redundant. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed. */\n      failureTitle: \"Image elements have `[alt]` attributes that are redundant text.\",\n      /** Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */\n      description: \"Informative elements should aim for short, descriptive alternative text. Alternative text that is exactly the same as the text adjacent to the link or image is potentially confusing for screen reader users, because the text will be read twice. [Learn more about the `alt` attribute](https://dequeuniversity.com/rules/axe/4.11/image-redundant-alt).\"\n    };\n    str_44 = createIcuMessageFn({ url: \"core/audits/accessibility/image-redundant-alt.js\" }.url, UIStrings63);\n    ImageRedundantAlt = class extends axe_audit_default {\n      static {\n        __name(this, \"ImageRedundantAlt\");\n      }\n      /**\n       * @return {LH.Audit.Meta}\n       */\n      static get meta() {\n        return {\n          id: \"image-redundant-alt\",\n          title: str_44(UIStrings63.title),\n          failureTitle: str_44(UIStrings63.failureTitle),\n          description: str_44(UIStrings63.description),\n          scoreDisplayMode: axe_audit_default.SCORING_MODES.INFORMATIVE,\n          requiredArtifacts: [\"Accessibility\"]\n        };\n      }\n    };\n    image_redundant_alt_default = ImageRedundantAlt;\n  }\n});\n\n// core/audits/accessibility/input-button-name.js\nvar input_button_name_exports = {};\n__export(input_button_name_exports, {\n  UIStrings: () => UIStrings64,\n  default: () => input_button_name_default\n});\nvar UIStrings64, str_45, InputButtonName, input_button_name_default;\nvar init_input_button_name = __esm({\n  \"core/audits/accessibility/input-button-name.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_axe_audit();\n    init_i18n();\n    /**\n     * @license\n     * Copyright 2023 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    UIStrings64 = {\n      /** Title of an accessibility audit that evaluates if all input buttons have discernible text. This title is descriptive of the successful state and is shown to users when no user action is required. */\n      title: \"Input buttons have discernible text.\",\n      /** Title of an accessibility audit that evaluates if all input buttons have discernible text. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed. */\n      failureTitle: \"Input buttons do not have discernible text.\",\n      /** Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */\n      description: \"Adding discernable and accessible text to input buttons may help screen reader users understand the purpose of the input button. [Learn more about input buttons](https://dequeuniversity.com/rules/axe/4.11/input-button-name).\"\n    };\n    str_45 = createIcuMessageFn({ url: \"core/audits/accessibility/input-button-name.js\" }.url, UIStrings64);\n    InputButtonName = class extends axe_audit_default {\n      static {\n        __name(this, \"InputButtonName\");\n      }\n      /**\n       * @return {LH.Audit.Meta}\n       */\n      static get meta() {\n        return {\n          id: \"input-button-name\",\n          title: str_45(UIStrings64.title),\n          failureTitle: str_45(UIStrings64.failureTitle),\n          description: str_45(UIStrings64.description),\n          requiredArtifacts: [\"Accessibility\"]\n        };\n      }\n    };\n    input_button_name_default = InputButtonName;\n  }\n});\n\n// core/audits/accessibility/input-image-alt.js\nvar input_image_alt_exports = {};\n__export(input_image_alt_exports, {\n  UIStrings: () => UIStrings65,\n  default: () => input_image_alt_default\n});\nvar UIStrings65, str_46, InputImageAlt, input_image_alt_default;\nvar init_input_image_alt = __esm({\n  \"core/audits/accessibility/input-image-alt.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_axe_audit();\n    init_i18n();\n    /**\n     * @license\n     * Copyright 2017 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    UIStrings65 = {\n      /** Title of an accessibility audit that evaluates if all input elements of type image have an alt HTML attribute to describe their contents. This title is descriptive of the successful state and is shown to users when no user action is required. */\n      title: '`<input type=\"image\">` elements have `[alt]` text',\n      /** Title of an accessibility audit that evaluates if all input elements of type image have an alt HTML attribute to describe their contents. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed. */\n      failureTitle: '`<input type=\"image\">` elements do not have `[alt]` text',\n      /** Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */\n      description: \"When an image is being used as an `<input>` button, providing alternative text can help screen reader users understand the purpose of the button. [Learn about input image alt text](https://dequeuniversity.com/rules/axe/4.11/input-image-alt).\"\n    };\n    str_46 = createIcuMessageFn({ url: \"core/audits/accessibility/input-image-alt.js\" }.url, UIStrings65);\n    InputImageAlt = class extends axe_audit_default {\n      static {\n        __name(this, \"InputImageAlt\");\n      }\n      /**\n       * @return {LH.Audit.Meta}\n       */\n      static get meta() {\n        return {\n          id: \"input-image-alt\",\n          title: str_46(UIStrings65.title),\n          failureTitle: str_46(UIStrings65.failureTitle),\n          description: str_46(UIStrings65.description),\n          requiredArtifacts: [\"Accessibility\"]\n        };\n      }\n    };\n    input_image_alt_default = InputImageAlt;\n  }\n});\n\n// core/audits/accessibility/label-content-name-mismatch.js\nvar label_content_name_mismatch_exports = {};\n__export(label_content_name_mismatch_exports, {\n  UIStrings: () => UIStrings66,\n  default: () => label_content_name_mismatch_default\n});\nvar UIStrings66, str_47, LabelContentNameMismatch, label_content_name_mismatch_default;\nvar init_label_content_name_mismatch = __esm({\n  \"core/audits/accessibility/label-content-name-mismatch.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_axe_audit();\n    init_i18n();\n    /**\n     * @license\n     * Copyright 2023 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    UIStrings66 = {\n      /** Title of an accessibility audit that evaluates if elements labeled through their content have their visible text as part of their accessible name. This title is descriptive of the successful state and is shown to users when no user action is required. */\n      title: \"Elements with visible text labels have matching accessible names.\",\n      /** Title of an accessibility audit that evaluates if elements labeled through their content have their visible text as part of their accessible name. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed. */\n      failureTitle: \"Elements with visible text labels do not have matching accessible names.\",\n      /** Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */\n      description: \"Visible text labels that do not match the accessible name can result in a confusing experience for screen reader users. [Learn more about accessible names](https://dequeuniversity.com/rules/axe/4.11/label-content-name-mismatch).\"\n    };\n    str_47 = createIcuMessageFn({ url: \"core/audits/accessibility/label-content-name-mismatch.js\" }.url, UIStrings66);\n    LabelContentNameMismatch = class extends axe_audit_default {\n      static {\n        __name(this, \"LabelContentNameMismatch\");\n      }\n      /**\n       * @return {LH.Audit.Meta}\n       */\n      static get meta() {\n        return {\n          id: \"label-content-name-mismatch\",\n          title: str_47(UIStrings66.title),\n          failureTitle: str_47(UIStrings66.failureTitle),\n          description: str_47(UIStrings66.description),\n          requiredArtifacts: [\"Accessibility\"]\n        };\n      }\n    };\n    label_content_name_mismatch_default = LabelContentNameMismatch;\n  }\n});\n\n// core/audits/accessibility/label.js\nvar label_exports = {};\n__export(label_exports, {\n  UIStrings: () => UIStrings67,\n  default: () => label_default\n});\nvar UIStrings67, str_48, Label, label_default;\nvar init_label = __esm({\n  \"core/audits/accessibility/label.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_axe_audit();\n    init_i18n();\n    /**\n     * @license\n     * Copyright 2017 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    UIStrings67 = {\n      /** Title of an accessibility audit that evaluates if all form elements have corresponding label elements. This title is descriptive of the successful state and is shown to users when no user action is required. */\n      title: \"Form elements have associated labels\",\n      /** Title of an accessibility audit that evaluates if all form elements have corresponding label elements. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed. */\n      failureTitle: \"Form elements do not have associated labels\",\n      /** Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */\n      description: \"Labels ensure that form controls are announced properly by assistive technologies, like screen readers. [Learn more about form element labels](https://dequeuniversity.com/rules/axe/4.11/label).\"\n    };\n    str_48 = createIcuMessageFn({ url: \"core/audits/accessibility/label.js\" }.url, UIStrings67);\n    Label = class extends axe_audit_default {\n      static {\n        __name(this, \"Label\");\n      }\n      /**\n       * @return {LH.Audit.Meta}\n       */\n      static get meta() {\n        return {\n          id: \"label\",\n          title: str_48(UIStrings67.title),\n          failureTitle: str_48(UIStrings67.failureTitle),\n          description: str_48(UIStrings67.description),\n          requiredArtifacts: [\"Accessibility\"]\n        };\n      }\n    };\n    label_default = Label;\n  }\n});\n\n// core/audits/accessibility/landmark-one-main.js\nvar landmark_one_main_exports = {};\n__export(landmark_one_main_exports, {\n  UIStrings: () => UIStrings68,\n  default: () => landmark_one_main_default\n});\nvar UIStrings68, str_49, LandmarkOneMain, landmark_one_main_default;\nvar init_landmark_one_main = __esm({\n  \"core/audits/accessibility/landmark-one-main.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_axe_audit();\n    init_i18n();\n    /**\n     * @license\n     * Copyright 2023 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    UIStrings68 = {\n      /** Title of an accessibility audit that checks if the document has a main landmark. This title is descriptive of the successful state and is shown to users when no user action is required. */\n      title: \"Document has a main landmark.\",\n      /** Title of an accessibility audit that checks if the document has a main landmark. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed. */\n      failureTitle: \"Document does not have a main landmark.\",\n      /** Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */\n      description: \"One main landmark helps screen reader users navigate a web page. [Learn more about landmarks](https://dequeuniversity.com/rules/axe/4.11/landmark-one-main).\"\n    };\n    str_49 = createIcuMessageFn({ url: \"core/audits/accessibility/landmark-one-main.js\" }.url, UIStrings68);\n    LandmarkOneMain = class extends axe_audit_default {\n      static {\n        __name(this, \"LandmarkOneMain\");\n      }\n      /**\n       * @return {LH.Audit.Meta}\n       */\n      static get meta() {\n        return {\n          id: \"landmark-one-main\",\n          title: str_49(UIStrings68.title),\n          failureTitle: str_49(UIStrings68.failureTitle),\n          description: str_49(UIStrings68.description),\n          requiredArtifacts: [\"Accessibility\"]\n        };\n      }\n    };\n    landmark_one_main_default = LandmarkOneMain;\n  }\n});\n\n// core/audits/accessibility/link-in-text-block.js\nvar link_in_text_block_exports = {};\n__export(link_in_text_block_exports, {\n  UIStrings: () => UIStrings69,\n  default: () => link_in_text_block_default\n});\nvar UIStrings69, str_50, LinkInTextBlock, link_in_text_block_default;\nvar init_link_in_text_block = __esm({\n  \"core/audits/accessibility/link-in-text-block.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_axe_audit();\n    init_i18n();\n    /**\n     * @license\n     * Copyright 2023 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    UIStrings69 = {\n      /** Title of an accessibility audit that evaluates if all link elements can be distinguished without relying on color. This title is descriptive of the successful state and is shown to users when no user action is required. */\n      title: \"Links are distinguishable without relying on color.\",\n      /** Title of an accessibility audit that evaluates if all link elements can be distinguished without relying on color. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed. */\n      failureTitle: \"Links rely on color to be distinguishable.\",\n      /** Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */\n      description: \"Low-contrast text is difficult or impossible for many users to read. Link text that is discernible improves the experience for users with low vision. [Learn how to make links distinguishable](https://dequeuniversity.com/rules/axe/4.11/link-in-text-block).\"\n    };\n    str_50 = createIcuMessageFn({ url: \"core/audits/accessibility/link-in-text-block.js\" }.url, UIStrings69);\n    LinkInTextBlock = class extends axe_audit_default {\n      static {\n        __name(this, \"LinkInTextBlock\");\n      }\n      /**\n       * @return {LH.Audit.Meta}\n       */\n      static get meta() {\n        return {\n          id: \"link-in-text-block\",\n          title: str_50(UIStrings69.title),\n          failureTitle: str_50(UIStrings69.failureTitle),\n          description: str_50(UIStrings69.description),\n          requiredArtifacts: [\"Accessibility\"]\n        };\n      }\n    };\n    link_in_text_block_default = LinkInTextBlock;\n  }\n});\n\n// core/audits/accessibility/link-name.js\nvar link_name_exports = {};\n__export(link_name_exports, {\n  UIStrings: () => UIStrings70,\n  default: () => link_name_default\n});\nvar UIStrings70, str_51, LinkName, link_name_default;\nvar init_link_name = __esm({\n  \"core/audits/accessibility/link-name.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_axe_audit();\n    init_i18n();\n    /**\n     * @license\n     * Copyright 2017 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    UIStrings70 = {\n      /** Title of an accessibility audit that evaluates if all link elements have a non-generic name to screen readers. This title is descriptive of the successful state and is shown to users when no user action is required. */\n      title: \"Links have a discernible name\",\n      /** Title of an accessibility audit that evaluates if all link elements have a non-generic name to screen readers. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed. */\n      failureTitle: \"Links do not have a discernible name\",\n      /** Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */\n      description: \"Link text (and alternate text for images, when used as links) that is discernible, unique, and focusable improves the navigation experience for screen reader users. [Learn how to make links accessible](https://dequeuniversity.com/rules/axe/4.11/link-name).\"\n    };\n    str_51 = createIcuMessageFn({ url: \"core/audits/accessibility/link-name.js\" }.url, UIStrings70);\n    LinkName = class extends axe_audit_default {\n      static {\n        __name(this, \"LinkName\");\n      }\n      /**\n       * @return {LH.Audit.Meta}\n       */\n      static get meta() {\n        return {\n          id: \"link-name\",\n          title: str_51(UIStrings70.title),\n          failureTitle: str_51(UIStrings70.failureTitle),\n          description: str_51(UIStrings70.description),\n          requiredArtifacts: [\"Accessibility\"]\n        };\n      }\n    };\n    link_name_default = LinkName;\n  }\n});\n\n// core/audits/accessibility/list.js\nvar list_exports = {};\n__export(list_exports, {\n  UIStrings: () => UIStrings71,\n  default: () => list_default\n});\nvar UIStrings71, str_52, List, list_default;\nvar init_list = __esm({\n  \"core/audits/accessibility/list.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_axe_audit();\n    init_i18n();\n    /**\n     * @license\n     * Copyright 2017 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    UIStrings71 = {\n      /** Title of an accessibility audit that evaluates if all list elements have a valid structure containing only list items. This title is descriptive of the successful state and is shown to users when no user action is required. */\n      title: \"Lists contain only `<li>` elements and script supporting elements (`<script>` and `<template>`).\",\n      /** Title of an accessibility audit that evaluates if all list elements have a valid structure containing only list items. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed. */\n      failureTitle: \"Lists do not contain only `<li>` elements and script supporting elements (`<script>` and `<template>`).\",\n      /** Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */\n      description: \"Screen readers have a specific way of announcing lists. Ensuring proper list structure aids screen reader output. [Learn more about proper list structure](https://dequeuniversity.com/rules/axe/4.11/list).\"\n    };\n    str_52 = createIcuMessageFn({ url: \"core/audits/accessibility/list.js\" }.url, UIStrings71);\n    List = class extends axe_audit_default {\n      static {\n        __name(this, \"List\");\n      }\n      /**\n       * @return {LH.Audit.Meta}\n       */\n      static get meta() {\n        return {\n          id: \"list\",\n          title: str_52(UIStrings71.title),\n          failureTitle: str_52(UIStrings71.failureTitle),\n          description: str_52(UIStrings71.description),\n          requiredArtifacts: [\"Accessibility\"]\n        };\n      }\n    };\n    list_default = List;\n  }\n});\n\n// core/audits/accessibility/listitem.js\nvar listitem_exports = {};\n__export(listitem_exports, {\n  UIStrings: () => UIStrings72,\n  default: () => listitem_default\n});\nvar UIStrings72, str_53, ListItem, listitem_default;\nvar init_listitem = __esm({\n  \"core/audits/accessibility/listitem.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_axe_audit();\n    init_i18n();\n    /**\n     * @license\n     * Copyright 2017 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    UIStrings72 = {\n      /** Title of an accessibility audit that evaluates if any list item elements do not have list parent elements. This title is descriptive of the successful state and is shown to users when no user action is required. */\n      title: \"List items (`<li>`) are contained within `<ul>`, `<ol>` or `<menu>` parent elements\",\n      /** Title of an accessibility audit that evaluates if any list item elements do not have list parent elements. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed. */\n      failureTitle: \"List items (`<li>`) are not contained within `<ul>`, `<ol>` or `<menu>` parent elements.\",\n      /** Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */\n      description: \"Screen readers require list items (`<li>`) to be contained within a parent `<ul>`, `<ol>` or `<menu>` to be announced properly. [Learn more about proper list structure](https://dequeuniversity.com/rules/axe/4.11/listitem).\"\n    };\n    str_53 = createIcuMessageFn({ url: \"core/audits/accessibility/listitem.js\" }.url, UIStrings72);\n    ListItem = class extends axe_audit_default {\n      static {\n        __name(this, \"ListItem\");\n      }\n      /**\n       * @return {LH.Audit.Meta}\n       */\n      static get meta() {\n        return {\n          id: \"listitem\",\n          title: str_53(UIStrings72.title),\n          failureTitle: str_53(UIStrings72.failureTitle),\n          description: str_53(UIStrings72.description),\n          requiredArtifacts: [\"Accessibility\"]\n        };\n      }\n    };\n    listitem_default = ListItem;\n  }\n});\n\n// core/audits/manual/manual-audit.js\nvar ManualAudit, manual_audit_default;\nvar init_manual_audit = __esm({\n  \"core/audits/manual/manual-audit.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_audit();\n    /**\n     * @license\n     * Copyright 2017 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    ManualAudit = class extends Audit {\n      static {\n        __name(this, \"ManualAudit\");\n      }\n      /**\n       * @return {Pick<LH.Audit.Meta, 'scoreDisplayMode'|'requiredArtifacts'>}\n       */\n      static get partialMeta() {\n        return {\n          scoreDisplayMode: Audit.SCORING_MODES.MANUAL,\n          requiredArtifacts: []\n        };\n      }\n      /**\n       * @return {LH.Audit.Product}\n       */\n      static audit() {\n        return {\n          score: 0\n          // displayValue: '(needs manual verification)'\n        };\n      }\n    };\n    manual_audit_default = ManualAudit;\n  }\n});\n\n// core/audits/accessibility/manual/custom-controls-labels.js\nvar custom_controls_labels_exports = {};\n__export(custom_controls_labels_exports, {\n  default: () => custom_controls_labels_default\n});\nvar CustomControlsLabels, custom_controls_labels_default;\nvar init_custom_controls_labels = __esm({\n  \"core/audits/accessibility/manual/custom-controls-labels.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_manual_audit();\n    /**\n     * @license\n     * Copyright 2017 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    CustomControlsLabels = class extends manual_audit_default {\n      static {\n        __name(this, \"CustomControlsLabels\");\n      }\n      /**\n       * @return {LH.Audit.Meta}\n       */\n      static get meta() {\n        return Object.assign({\n          id: \"custom-controls-labels\",\n          description: \"Custom interactive controls have associated labels, provided by aria-label or aria-labelledby. [Learn more about custom controls and labels](https://developer.chrome.com/docs/lighthouse/accessibility/custom-controls-labels/).\",\n          title: \"Custom controls have associated labels\"\n        }, super.partialMeta);\n      }\n    };\n    custom_controls_labels_default = CustomControlsLabels;\n  }\n});\n\n// core/audits/accessibility/manual/custom-controls-roles.js\nvar custom_controls_roles_exports = {};\n__export(custom_controls_roles_exports, {\n  default: () => custom_controls_roles_default\n});\nvar CustomControlsRoles, custom_controls_roles_default;\nvar init_custom_controls_roles = __esm({\n  \"core/audits/accessibility/manual/custom-controls-roles.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_manual_audit();\n    /**\n     * @license\n     * Copyright 2017 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    CustomControlsRoles = class extends manual_audit_default {\n      static {\n        __name(this, \"CustomControlsRoles\");\n      }\n      /**\n       * @return {LH.Audit.Meta}\n       */\n      static get meta() {\n        return Object.assign({\n          id: \"custom-controls-roles\",\n          description: \"Custom interactive controls have appropriate ARIA roles. [Learn how to add roles to custom controls](https://developer.chrome.com/docs/lighthouse/accessibility/custom-control-roles/).\",\n          title: \"Custom controls have ARIA roles\"\n        }, super.partialMeta);\n      }\n    };\n    custom_controls_roles_default = CustomControlsRoles;\n  }\n});\n\n// core/audits/accessibility/manual/focus-traps.js\nvar focus_traps_exports = {};\n__export(focus_traps_exports, {\n  default: () => focus_traps_default\n});\nvar FocusTraps, focus_traps_default;\nvar init_focus_traps = __esm({\n  \"core/audits/accessibility/manual/focus-traps.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_manual_audit();\n    /**\n     * @license\n     * Copyright 2017 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    FocusTraps = class extends manual_audit_default {\n      static {\n        __name(this, \"FocusTraps\");\n      }\n      /**\n       * @return {LH.Audit.Meta}\n       */\n      static get meta() {\n        return Object.assign({\n          id: \"focus-traps\",\n          description: \"A user can tab into and out of any control or region without accidentally trapping their focus. [Learn how to avoid focus traps](https://developer.chrome.com/docs/lighthouse/accessibility/focus-traps/).\",\n          title: \"User focus is not accidentally trapped in a region\"\n        }, super.partialMeta);\n      }\n    };\n    focus_traps_default = FocusTraps;\n  }\n});\n\n// core/audits/accessibility/manual/focusable-controls.js\nvar focusable_controls_exports = {};\n__export(focusable_controls_exports, {\n  default: () => focusable_controls_default\n});\nvar FocusableControls, focusable_controls_default;\nvar init_focusable_controls = __esm({\n  \"core/audits/accessibility/manual/focusable-controls.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_manual_audit();\n    /**\n     * @license\n     * Copyright 2017 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    FocusableControls = class extends manual_audit_default {\n      static {\n        __name(this, \"FocusableControls\");\n      }\n      /**\n       * @return {LH.Audit.Meta}\n       */\n      static get meta() {\n        return Object.assign({\n          id: \"focusable-controls\",\n          description: \"Custom interactive controls are keyboard focusable and display a focus indicator. [Learn how to make custom controls focusable](https://developer.chrome.com/docs/lighthouse/accessibility/focusable-controls/).\",\n          title: \"Interactive controls are keyboard focusable\"\n        }, super.partialMeta);\n      }\n    };\n    focusable_controls_default = FocusableControls;\n  }\n});\n\n// core/audits/accessibility/manual/interactive-element-affordance.js\nvar interactive_element_affordance_exports = {};\n__export(interactive_element_affordance_exports, {\n  default: () => interactive_element_affordance_default\n});\nvar InteractiveElementAffordance, interactive_element_affordance_default;\nvar init_interactive_element_affordance = __esm({\n  \"core/audits/accessibility/manual/interactive-element-affordance.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_manual_audit();\n    /**\n     * @license\n     * Copyright 2018 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    InteractiveElementAffordance = class extends manual_audit_default {\n      static {\n        __name(this, \"InteractiveElementAffordance\");\n      }\n      /**\n       * @return {LH.Audit.Meta}\n       */\n      static get meta() {\n        return Object.assign({\n          id: \"interactive-element-affordance\",\n          description: \"Interactive elements, such as links and buttons, should indicate their state and be distinguishable from non-interactive elements. [Learn how to decorate interactive elements with affordance hints](https://developer.chrome.com/docs/lighthouse/accessibility/interactive-element-affordance/).\",\n          title: \"Interactive elements indicate their purpose and state\"\n        }, super.partialMeta);\n      }\n    };\n    interactive_element_affordance_default = InteractiveElementAffordance;\n  }\n});\n\n// core/audits/accessibility/manual/logical-tab-order.js\nvar logical_tab_order_exports = {};\n__export(logical_tab_order_exports, {\n  default: () => logical_tab_order_default\n});\nvar LogicalTabOrder, logical_tab_order_default;\nvar init_logical_tab_order = __esm({\n  \"core/audits/accessibility/manual/logical-tab-order.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_manual_audit();\n    /**\n     * @license\n     * Copyright 2017 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    LogicalTabOrder = class extends manual_audit_default {\n      static {\n        __name(this, \"LogicalTabOrder\");\n      }\n      /**\n       * @return {LH.Audit.Meta}\n       */\n      static get meta() {\n        return Object.assign({\n          id: \"logical-tab-order\",\n          description: \"Tabbing through the page follows the visual layout. Users cannot focus elements that are offscreen. [Learn more about logical tab ordering](https://developer.chrome.com/docs/lighthouse/accessibility/logical-tab-order/).\",\n          title: \"The page has a logical tab order\"\n        }, super.partialMeta);\n      }\n    };\n    logical_tab_order_default = LogicalTabOrder;\n  }\n});\n\n// core/audits/accessibility/manual/managed-focus.js\nvar managed_focus_exports = {};\n__export(managed_focus_exports, {\n  default: () => managed_focus_default\n});\nvar ManagedFocus, managed_focus_default;\nvar init_managed_focus = __esm({\n  \"core/audits/accessibility/manual/managed-focus.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_manual_audit();\n    /**\n     * @license\n     * Copyright 2017 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    ManagedFocus = class extends manual_audit_default {\n      static {\n        __name(this, \"ManagedFocus\");\n      }\n      /**\n       * @return {LH.Audit.Meta}\n       */\n      static get meta() {\n        return Object.assign({\n          id: \"managed-focus\",\n          description: \"If new content, such as a dialog, is added to the page, the user's focus is directed to it. [Learn how to direct focus to new content](https://developer.chrome.com/docs/lighthouse/accessibility/managed-focus/).\",\n          title: \"The user's focus is directed to new content added to the page\"\n        }, super.partialMeta);\n      }\n    };\n    managed_focus_default = ManagedFocus;\n  }\n});\n\n// core/audits/accessibility/manual/offscreen-content-hidden.js\nvar offscreen_content_hidden_exports = {};\n__export(offscreen_content_hidden_exports, {\n  default: () => offscreen_content_hidden_default\n});\nvar OffscreenContentHidden, offscreen_content_hidden_default;\nvar init_offscreen_content_hidden = __esm({\n  \"core/audits/accessibility/manual/offscreen-content-hidden.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_manual_audit();\n    /**\n     * @license\n     * Copyright 2017 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    OffscreenContentHidden = class extends manual_audit_default {\n      static {\n        __name(this, \"OffscreenContentHidden\");\n      }\n      /**\n       * @return {LH.Audit.Meta}\n       */\n      static get meta() {\n        return Object.assign({\n          id: \"offscreen-content-hidden\",\n          description: \"Offscreen content is hidden with display: none or aria-hidden=true. [Learn how to properly hide offscreen content](https://developer.chrome.com/docs/lighthouse/accessibility/offscreen-content-hidden/).\",\n          title: \"Offscreen content is hidden from assistive technology\"\n        }, super.partialMeta);\n      }\n    };\n    offscreen_content_hidden_default = OffscreenContentHidden;\n  }\n});\n\n// core/audits/accessibility/manual/use-landmarks.js\nvar use_landmarks_exports = {};\n__export(use_landmarks_exports, {\n  default: () => use_landmarks_default\n});\nvar UseLandmarks, use_landmarks_default;\nvar init_use_landmarks = __esm({\n  \"core/audits/accessibility/manual/use-landmarks.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_manual_audit();\n    /**\n     * @license\n     * Copyright 2017 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    UseLandmarks = class extends manual_audit_default {\n      static {\n        __name(this, \"UseLandmarks\");\n      }\n      /**\n       * @return {LH.Audit.Meta}\n       */\n      static get meta() {\n        return Object.assign({\n          id: \"use-landmarks\",\n          description: \"Landmark elements (`<main>`, `<nav>`, etc.) are used to improve the keyboard navigation of the page for assistive technology. [Learn more about landmark elements](https://developer.chrome.com/docs/lighthouse/accessibility/use-landmarks/).\",\n          title: \"HTML5 landmark elements are used to improve navigation\"\n        }, super.partialMeta);\n      }\n    };\n    use_landmarks_default = UseLandmarks;\n  }\n});\n\n// core/audits/accessibility/manual/visual-order-follows-dom.js\nvar visual_order_follows_dom_exports = {};\n__export(visual_order_follows_dom_exports, {\n  default: () => visual_order_follows_dom_default\n});\nvar VisualOrderFollowsDOM, visual_order_follows_dom_default;\nvar init_visual_order_follows_dom = __esm({\n  \"core/audits/accessibility/manual/visual-order-follows-dom.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_manual_audit();\n    /**\n     * @license\n     * Copyright 2017 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    VisualOrderFollowsDOM = class extends manual_audit_default {\n      static {\n        __name(this, \"VisualOrderFollowsDOM\");\n      }\n      /**\n       * @return {LH.Audit.Meta}\n       */\n      static get meta() {\n        return Object.assign({\n          id: \"visual-order-follows-dom\",\n          description: \"DOM order matches the visual order, improving navigation for assistive technology. [Learn more about DOM and visual ordering](https://developer.chrome.com/docs/lighthouse/accessibility/visual-order-follows-dom/).\",\n          title: \"Visual order on the page follows DOM order\"\n        }, super.partialMeta);\n      }\n    };\n    visual_order_follows_dom_default = VisualOrderFollowsDOM;\n  }\n});\n\n// core/audits/accessibility/meta-refresh.js\nvar meta_refresh_exports = {};\n__export(meta_refresh_exports, {\n  UIStrings: () => UIStrings73,\n  default: () => meta_refresh_default\n});\nvar UIStrings73, str_54, MetaRefresh, meta_refresh_default;\nvar init_meta_refresh = __esm({\n  \"core/audits/accessibility/meta-refresh.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_axe_audit();\n    init_i18n();\n    /**\n     * @license\n     * Copyright 2017 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    UIStrings73 = {\n      /** Title of an accessibility audit that evaluates if the page uses a meta tag that refreshes the page automatically. This title is descriptive of the successful state and is shown to users when no user action is required. */\n      title: 'The document does not use `<meta http-equiv=\"refresh\">`',\n      /** Title of an accessibility audit that evaluates if the page uses a meta tag that refreshes the page automatically. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed. */\n      failureTitle: 'The document uses `<meta http-equiv=\"refresh\">`',\n      /** Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */\n      description: \"Users do not expect a page to refresh automatically, and doing so will move focus back to the top of the page. This may create a frustrating or confusing experience. [Learn more about the refresh meta tag](https://dequeuniversity.com/rules/axe/4.11/meta-refresh).\"\n    };\n    str_54 = createIcuMessageFn({ url: \"core/audits/accessibility/meta-refresh.js\" }.url, UIStrings73);\n    MetaRefresh = class extends axe_audit_default {\n      static {\n        __name(this, \"MetaRefresh\");\n      }\n      /**\n       * @return {LH.Audit.Meta}\n       */\n      static get meta() {\n        return {\n          id: \"meta-refresh\",\n          title: str_54(UIStrings73.title),\n          failureTitle: str_54(UIStrings73.failureTitle),\n          description: str_54(UIStrings73.description),\n          requiredArtifacts: [\"Accessibility\"]\n        };\n      }\n    };\n    meta_refresh_default = MetaRefresh;\n  }\n});\n\n// core/audits/accessibility/meta-viewport.js\nvar meta_viewport_exports = {};\n__export(meta_viewport_exports, {\n  UIStrings: () => UIStrings74,\n  default: () => meta_viewport_default\n});\nvar UIStrings74, str_55, MetaViewport, meta_viewport_default;\nvar init_meta_viewport = __esm({\n  \"core/audits/accessibility/meta-viewport.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_axe_audit();\n    init_i18n();\n    /**\n     * @license\n     * Copyright 2017 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    UIStrings74 = {\n      /** Title of an accessibility audit that evaluates if the page has limited the scaling properties of the page in a way that harms users with low vision. This title is descriptive of the successful state and is shown to users when no user action is required. */\n      title: '`[user-scalable=\"no\"]` is not used in the `<meta name=\"viewport\">` element and the `[maximum-scale]` attribute is not less than 5.',\n      /** Title of an accessibility audit that evaluates if the page has limited the scaling properties of the page in a way that harms users with low vision. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed. */\n      failureTitle: '`[user-scalable=\"no\"]` is used in the `<meta name=\"viewport\">` element or the `[maximum-scale]` attribute is less than 5.',\n      /** Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */\n      description: \"Disabling zooming is problematic for users with low vision who rely on screen magnification to properly see the contents of a web page. [Learn more about the viewport meta tag](https://dequeuniversity.com/rules/axe/4.11/meta-viewport).\"\n    };\n    str_55 = createIcuMessageFn({ url: \"core/audits/accessibility/meta-viewport.js\" }.url, UIStrings74);\n    MetaViewport = class extends axe_audit_default {\n      static {\n        __name(this, \"MetaViewport\");\n      }\n      /**\n       * @return {LH.Audit.Meta}\n       */\n      static get meta() {\n        return {\n          id: \"meta-viewport\",\n          title: str_55(UIStrings74.title),\n          failureTitle: str_55(UIStrings74.failureTitle),\n          description: str_55(UIStrings74.description),\n          requiredArtifacts: [\"Accessibility\"]\n        };\n      }\n    };\n    meta_viewport_default = MetaViewport;\n  }\n});\n\n// core/audits/accessibility/object-alt.js\nvar object_alt_exports = {};\n__export(object_alt_exports, {\n  UIStrings: () => UIStrings75,\n  default: () => object_alt_default\n});\nvar UIStrings75, str_56, ObjectAlt, object_alt_default;\nvar init_object_alt = __esm({\n  \"core/audits/accessibility/object-alt.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_axe_audit();\n    init_i18n();\n    /**\n     * @license\n     * Copyright 2017 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    UIStrings75 = {\n      /** Title of an accessibility audit that evaluates if all object elements have an alt HTML attribute that describes their contents. This title is descriptive of the successful state and is shown to users when no user action is required. */\n      title: \"`<object>` elements have alternate text\",\n      /** Title of an accessibility audit that evaluates if all object elements have an alt HTML attribute that describes their contents. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed. */\n      failureTitle: \"`<object>` elements do not have alternate text\",\n      /** Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */\n      description: \"Screen readers cannot translate non-text content. Adding alternate text to `<object>` elements helps screen readers convey meaning to users. [Learn more about alt text for `object` elements](https://dequeuniversity.com/rules/axe/4.11/object-alt).\"\n    };\n    str_56 = createIcuMessageFn({ url: \"core/audits/accessibility/object-alt.js\" }.url, UIStrings75);\n    ObjectAlt = class extends axe_audit_default {\n      static {\n        __name(this, \"ObjectAlt\");\n      }\n      /**\n       * @return {LH.Audit.Meta}\n       */\n      static get meta() {\n        return {\n          id: \"object-alt\",\n          title: str_56(UIStrings75.title),\n          failureTitle: str_56(UIStrings75.failureTitle),\n          description: str_56(UIStrings75.description),\n          requiredArtifacts: [\"Accessibility\"]\n        };\n      }\n    };\n    object_alt_default = ObjectAlt;\n  }\n});\n\n// core/audits/accessibility/select-name.js\nvar select_name_exports = {};\n__export(select_name_exports, {\n  UIStrings: () => UIStrings76,\n  default: () => select_name_default\n});\nvar UIStrings76, str_57, SelectName, select_name_default;\nvar init_select_name = __esm({\n  \"core/audits/accessibility/select-name.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_axe_audit();\n    init_i18n();\n    /**\n     * @license\n     * Copyright 2023 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    UIStrings76 = {\n      /** Title of an accessibility audit that evaluates if all select elements have programmatically associated label elements. This title is descriptive of the successful state and is shown to users when no user action is required. */\n      title: \"Select elements have associated label elements.\",\n      /** Title of an accessibility audit that evaluates if all select elements have programmatically associated label elements. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed. */\n      failureTitle: \"Select elements do not have associated label elements.\",\n      /** Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */\n      description: \"Form elements without effective labels can create frustrating experiences for screen reader users. [Learn more about the `select` element](https://dequeuniversity.com/rules/axe/4.11/select-name).\"\n    };\n    str_57 = createIcuMessageFn({ url: \"core/audits/accessibility/select-name.js\" }.url, UIStrings76);\n    SelectName = class extends axe_audit_default {\n      static {\n        __name(this, \"SelectName\");\n      }\n      /**\n       * @return {LH.Audit.Meta}\n       */\n      static get meta() {\n        return {\n          id: \"select-name\",\n          title: str_57(UIStrings76.title),\n          failureTitle: str_57(UIStrings76.failureTitle),\n          description: str_57(UIStrings76.description),\n          requiredArtifacts: [\"Accessibility\"]\n        };\n      }\n    };\n    select_name_default = SelectName;\n  }\n});\n\n// core/audits/accessibility/skip-link.js\nvar skip_link_exports = {};\n__export(skip_link_exports, {\n  UIStrings: () => UIStrings77,\n  default: () => skip_link_default\n});\nvar UIStrings77, str_58, SkipLink, skip_link_default;\nvar init_skip_link = __esm({\n  \"core/audits/accessibility/skip-link.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_axe_audit();\n    init_i18n();\n    /**\n     * @license\n     * Copyright 2023 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    UIStrings77 = {\n      /** Title of an accessibility audit that evaluates if the skip link is focusable. This title is descriptive of the successful state and is shown to users when no user action is required. */\n      title: \"Skip links are focusable.\",\n      /** Title of an accessibility audit that evaluates if the skip link is focusable. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed. */\n      failureTitle: \"Skip links are not focusable.\",\n      /** Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */\n      description: \"Including a skip link can help users skip to the main content to save time. [Learn more about skip links](https://dequeuniversity.com/rules/axe/4.11/skip-link).\"\n    };\n    str_58 = createIcuMessageFn({ url: \"core/audits/accessibility/skip-link.js\" }.url, UIStrings77);\n    SkipLink = class extends axe_audit_default {\n      static {\n        __name(this, \"SkipLink\");\n      }\n      /**\n       * @return {LH.Audit.Meta}\n       */\n      static get meta() {\n        return {\n          id: \"skip-link\",\n          title: str_58(UIStrings77.title),\n          failureTitle: str_58(UIStrings77.failureTitle),\n          description: str_58(UIStrings77.description),\n          requiredArtifacts: [\"Accessibility\"]\n        };\n      }\n    };\n    skip_link_default = SkipLink;\n  }\n});\n\n// core/audits/accessibility/tabindex.js\nvar tabindex_exports = {};\n__export(tabindex_exports, {\n  UIStrings: () => UIStrings78,\n  default: () => tabindex_default\n});\nvar UIStrings78, str_59, TabIndex, tabindex_default;\nvar init_tabindex = __esm({\n  \"core/audits/accessibility/tabindex.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_axe_audit();\n    init_i18n();\n    /**\n     * @license\n     * Copyright 2017 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    UIStrings78 = {\n      /** Title of an accessibility audit that evaluates if any elements have custom tabindex HTML attributes that might frustrate users of assitive technology. This title is descriptive of the successful state and is shown to users when no user action is required. */\n      title: \"No element has a `[tabindex]` value greater than 0\",\n      /** Title of an accessibility audit that evaluates if any elements have custom tabindex HTML attributes that might frustrate users of assitive technology. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed. */\n      failureTitle: \"Some elements have a `[tabindex]` value greater than 0\",\n      /** Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */\n      description: \"A value greater than 0 implies an explicit navigation ordering. Although technically valid, this often creates frustrating experiences for users who rely on assistive technologies. [Learn more about the `tabindex` attribute](https://dequeuniversity.com/rules/axe/4.11/tabindex).\"\n    };\n    str_59 = createIcuMessageFn({ url: \"core/audits/accessibility/tabindex.js\" }.url, UIStrings78);\n    TabIndex = class extends axe_audit_default {\n      static {\n        __name(this, \"TabIndex\");\n      }\n      /**\n       * @return {LH.Audit.Meta}\n       */\n      static get meta() {\n        return {\n          id: \"tabindex\",\n          title: str_59(UIStrings78.title),\n          failureTitle: str_59(UIStrings78.failureTitle),\n          description: str_59(UIStrings78.description),\n          requiredArtifacts: [\"Accessibility\"]\n        };\n      }\n    };\n    tabindex_default = TabIndex;\n  }\n});\n\n// core/audits/accessibility/table-duplicate-name.js\nvar table_duplicate_name_exports = {};\n__export(table_duplicate_name_exports, {\n  UIStrings: () => UIStrings79,\n  default: () => table_duplicate_name_default\n});\nvar UIStrings79, str_60, TableDuplicateName, table_duplicate_name_default;\nvar init_table_duplicate_name = __esm({\n  \"core/audits/accessibility/table-duplicate-name.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_axe_audit();\n    init_i18n();\n    /**\n     * @license\n     * Copyright 2023 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    UIStrings79 = {\n      /** Title of an accessibility audit that evaluates if tables have different content in the summary attribute and caption element. This title is descriptive of the successful state and is shown to users when no user action is required. */\n      title: \"Tables have different content in the summary attribute and `<caption>`.\",\n      /** Title of an accessibility audit that evaluates if tables have different content in the summary attribute and caption element. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed. */\n      failureTitle: \"Tables have the same content in the summary attribute and `<caption>.`\",\n      /** Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */\n      description: \"The summary attribute should describe the table structure, while `<caption>` should have the onscreen title. Accurate table mark-up helps users of screen readers. [Learn more about summary and caption](https://dequeuniversity.com/rules/axe/4.11/table-duplicate-name).\"\n    };\n    str_60 = createIcuMessageFn({ url: \"core/audits/accessibility/table-duplicate-name.js\" }.url, UIStrings79);\n    TableDuplicateName = class extends axe_audit_default {\n      static {\n        __name(this, \"TableDuplicateName\");\n      }\n      /**\n       * @return {LH.Audit.Meta}\n       */\n      static get meta() {\n        return {\n          id: \"table-duplicate-name\",\n          title: str_60(UIStrings79.title),\n          failureTitle: str_60(UIStrings79.failureTitle),\n          description: str_60(UIStrings79.description),\n          scoreDisplayMode: axe_audit_default.SCORING_MODES.INFORMATIVE,\n          requiredArtifacts: [\"Accessibility\"]\n        };\n      }\n    };\n    table_duplicate_name_default = TableDuplicateName;\n  }\n});\n\n// core/audits/accessibility/table-fake-caption.js\nvar table_fake_caption_exports = {};\n__export(table_fake_caption_exports, {\n  UIStrings: () => UIStrings80,\n  default: () => table_fake_caption_default\n});\nvar UIStrings80, str_61, TableFakeCaption, table_fake_caption_default;\nvar init_table_fake_caption = __esm({\n  \"core/audits/accessibility/table-fake-caption.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_axe_audit();\n    init_i18n();\n    /**\n     * @license\n     * Copyright 2023 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    UIStrings80 = {\n      /** Title of an accessibility audit that evaluates if all tables use caption instead of colspan to indicate a caption. This title is descriptive of the successful state and is shown to users when no user action is required. */\n      title: \"Tables use `<caption>` instead of cells with the `[colspan]` attribute to indicate a caption.\",\n      /** Title of an accessibility audit that evaluates if all tables use caption instead of colspan to indicate a caption. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed. */\n      failureTitle: \"Tables do not use `<caption>` instead of cells with the `[colspan]` attribute to indicate a caption.\",\n      /** Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */\n      description: \"Screen readers have features to make navigating tables easier. Ensuring that tables use the actual caption element instead of cells with the `[colspan]` attribute may improve the experience for screen reader users. [Learn more about captions](https://dequeuniversity.com/rules/axe/4.11/table-fake-caption).\"\n    };\n    str_61 = createIcuMessageFn({ url: \"core/audits/accessibility/table-fake-caption.js\" }.url, UIStrings80);\n    TableFakeCaption = class extends axe_audit_default {\n      static {\n        __name(this, \"TableFakeCaption\");\n      }\n      /**\n       * @return {LH.Audit.Meta}\n       */\n      static get meta() {\n        return {\n          id: \"table-fake-caption\",\n          title: str_61(UIStrings80.title),\n          failureTitle: str_61(UIStrings80.failureTitle),\n          description: str_61(UIStrings80.description),\n          requiredArtifacts: [\"Accessibility\"]\n        };\n      }\n    };\n    table_fake_caption_default = TableFakeCaption;\n  }\n});\n\n// core/audits/accessibility/target-size.js\nvar target_size_exports = {};\n__export(target_size_exports, {\n  UIStrings: () => UIStrings81,\n  default: () => target_size_default\n});\nvar UIStrings81, str_62, TargetSize, target_size_default;\nvar init_target_size = __esm({\n  \"core/audits/accessibility/target-size.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_axe_audit();\n    init_i18n();\n    /**\n     * @license\n     * Copyright 2023 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    UIStrings81 = {\n      /** Title of an accessibility audit that checks if all touch targets have sufficient size and spacing. This title is descriptive of the successful state and is shown to users when no user action is required. */\n      title: \"Touch targets have sufficient size and spacing.\",\n      /** Title of an accessibility audit that checks if all touch targets have sufficient size and spacing. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed. */\n      failureTitle: \"Touch targets do not have sufficient size or spacing.\",\n      /** Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */\n      description: \"Touch targets with sufficient size and spacing help users who may have difficulty targeting small controls to activate the targets. [Learn more about touch targets](https://dequeuniversity.com/rules/axe/4.11/target-size).\"\n    };\n    str_62 = createIcuMessageFn({ url: \"core/audits/accessibility/target-size.js\" }.url, UIStrings81);\n    TargetSize = class extends axe_audit_default {\n      static {\n        __name(this, \"TargetSize\");\n      }\n      /**\n       * @return {LH.Audit.Meta}\n       */\n      static get meta() {\n        return {\n          id: \"target-size\",\n          title: str_62(UIStrings81.title),\n          failureTitle: str_62(UIStrings81.failureTitle),\n          description: str_62(UIStrings81.description),\n          requiredArtifacts: [\"Accessibility\"]\n        };\n      }\n    };\n    target_size_default = TargetSize;\n  }\n});\n\n// core/audits/accessibility/td-has-header.js\nvar td_has_header_exports = {};\n__export(td_has_header_exports, {\n  UIStrings: () => UIStrings82,\n  default: () => td_has_header_default\n});\nvar UIStrings82, str_63, TDHasHeader, td_has_header_default;\nvar init_td_has_header = __esm({\n  \"core/audits/accessibility/td-has-header.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_axe_audit();\n    init_i18n();\n    /**\n     * @license\n     * Copyright 2023 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    UIStrings82 = {\n      /** Title of an accessibility audit that evaluates if all large table elements use the headers HTML attribute. This title is descriptive of the successful state and is shown to users when no user action is required. */\n      title: \"`<td>` elements in a large `<table>` have one or more table headers.\",\n      /** Title of an accessibility audit that evaluates if all large table elements use the headers HTML attribute. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed. */\n      failureTitle: \"`<td>` elements in a large `<table>` do not have table headers.\",\n      /** Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */\n      description: \"Screen readers have features to make navigating tables easier. Ensuring that `<td>` elements in a large table (3 or more cells in width and height) have an associated table header may improve the experience for screen reader users. [Learn more about table headers](https://dequeuniversity.com/rules/axe/4.11/td-has-header).\"\n    };\n    str_63 = createIcuMessageFn({ url: \"core/audits/accessibility/td-has-header.js\" }.url, UIStrings82);\n    TDHasHeader = class extends axe_audit_default {\n      static {\n        __name(this, \"TDHasHeader\");\n      }\n      /**\n       * @return {LH.Audit.Meta}\n       */\n      static get meta() {\n        return {\n          id: \"td-has-header\",\n          title: str_63(UIStrings82.title),\n          failureTitle: str_63(UIStrings82.failureTitle),\n          description: str_63(UIStrings82.description),\n          requiredArtifacts: [\"Accessibility\"]\n        };\n      }\n    };\n    td_has_header_default = TDHasHeader;\n  }\n});\n\n// core/audits/accessibility/td-headers-attr.js\nvar td_headers_attr_exports = {};\n__export(td_headers_attr_exports, {\n  UIStrings: () => UIStrings83,\n  default: () => td_headers_attr_default\n});\nvar UIStrings83, str_64, TDHeadersAttr, td_headers_attr_default;\nvar init_td_headers_attr = __esm({\n  \"core/audits/accessibility/td-headers-attr.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_axe_audit();\n    init_i18n();\n    /**\n     * @license\n     * Copyright 2017 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    UIStrings83 = {\n      /** Title of an accessibility audit that evaluates if all table cell elements in a table that use the headers HTML attribute use it correctly to refer to header cells within the same table. This title is descriptive of the successful state and is shown to users when no user action is required. */\n      title: \"Cells in a `<table>` element that use the `[headers]` attribute refer to table cells within the same table.\",\n      /** Title of an accessibility audit that evaluates if all table cell elements in a table that use the headers HTML attribute use it correctly to refer to header cells within the same table. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed. */\n      failureTitle: \"Cells in a `<table>` element that use the `[headers]` attribute refer to an element `id` not found within the same table.\",\n      /** Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */\n      description: \"Screen readers have features to make navigating tables easier. Ensuring `<td>` cells using the `[headers]` attribute only refer to other cells in the same table may improve the experience for screen reader users. [Learn more about the `headers` attribute](https://dequeuniversity.com/rules/axe/4.11/td-headers-attr).\"\n    };\n    str_64 = createIcuMessageFn({ url: \"core/audits/accessibility/td-headers-attr.js\" }.url, UIStrings83);\n    TDHeadersAttr = class extends axe_audit_default {\n      static {\n        __name(this, \"TDHeadersAttr\");\n      }\n      /**\n       * @return {LH.Audit.Meta}\n       */\n      static get meta() {\n        return {\n          id: \"td-headers-attr\",\n          title: str_64(UIStrings83.title),\n          failureTitle: str_64(UIStrings83.failureTitle),\n          description: str_64(UIStrings83.description),\n          requiredArtifacts: [\"Accessibility\"]\n        };\n      }\n    };\n    td_headers_attr_default = TDHeadersAttr;\n  }\n});\n\n// core/audits/accessibility/th-has-data-cells.js\nvar th_has_data_cells_exports = {};\n__export(th_has_data_cells_exports, {\n  UIStrings: () => UIStrings84,\n  default: () => th_has_data_cells_default\n});\nvar UIStrings84, str_65, THHasDataCells, th_has_data_cells_default;\nvar init_th_has_data_cells = __esm({\n  \"core/audits/accessibility/th-has-data-cells.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_axe_audit();\n    init_i18n();\n    /**\n     * @license\n     * Copyright 2017 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    UIStrings84 = {\n      /** Title of an accessibility audit that evaluates if all table header elements have children. This title is descriptive of the successful state and is shown to users when no user action is required. */\n      title: '`<th>` elements and elements with `[role=\"columnheader\"/\"rowheader\"]` have data cells they describe.',\n      /** Title of an accessibility audit that evaluates if all table header elements have children. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed. */\n      failureTitle: '`<th>` elements and elements with `[role=\"columnheader\"/\"rowheader\"]` do not have data cells they describe.',\n      /** Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */\n      description: \"Screen readers have features to make navigating tables easier. Ensuring table headers always refer to some set of cells may improve the experience for screen reader users. [Learn more about table headers](https://dequeuniversity.com/rules/axe/4.11/th-has-data-cells).\"\n    };\n    str_65 = createIcuMessageFn({ url: \"core/audits/accessibility/th-has-data-cells.js\" }.url, UIStrings84);\n    THHasDataCells = class extends axe_audit_default {\n      static {\n        __name(this, \"THHasDataCells\");\n      }\n      /**\n       * @return {LH.Audit.Meta}\n       */\n      static get meta() {\n        return {\n          id: \"th-has-data-cells\",\n          title: str_65(UIStrings84.title),\n          failureTitle: str_65(UIStrings84.failureTitle),\n          description: str_65(UIStrings84.description),\n          scoreDisplayMode: axe_audit_default.SCORING_MODES.INFORMATIVE,\n          requiredArtifacts: [\"Accessibility\"]\n        };\n      }\n    };\n    th_has_data_cells_default = THHasDataCells;\n  }\n});\n\n// core/audits/accessibility/valid-lang.js\nvar valid_lang_exports = {};\n__export(valid_lang_exports, {\n  UIStrings: () => UIStrings85,\n  default: () => valid_lang_default\n});\nvar UIStrings85, str_66, ValidLang, valid_lang_default;\nvar init_valid_lang = __esm({\n  \"core/audits/accessibility/valid-lang.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_axe_audit();\n    init_i18n();\n    /**\n     * @license\n     * Copyright 2017 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    UIStrings85 = {\n      /** Title of an accessibility audit that evaluates if all lang HTML attributes are valid BCP 47 languages. This title is descriptive of the successful state and is shown to users when no user action is required. */\n      title: \"`[lang]` attributes have a valid value\",\n      /** Title of an accessibility audit that evaluates if all lang HTML attributes are valid BCP 47 languages. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed. */\n      failureTitle: \"`[lang]` attributes do not have a valid value\",\n      /** Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */\n      description: \"Specifying a valid [BCP 47 language](https://www.w3.org/International/questions/qa-choosing-language-tags#question) on elements helps ensure that text is pronounced correctly by a screen reader. [Learn how to use the `lang` attribute](https://dequeuniversity.com/rules/axe/4.11/valid-lang).\"\n    };\n    str_66 = createIcuMessageFn({ url: \"core/audits/accessibility/valid-lang.js\" }.url, UIStrings85);\n    ValidLang = class extends axe_audit_default {\n      static {\n        __name(this, \"ValidLang\");\n      }\n      /**\n       * @return {LH.Audit.Meta}\n       */\n      static get meta() {\n        return {\n          id: \"valid-lang\",\n          title: str_66(UIStrings85.title),\n          failureTitle: str_66(UIStrings85.failureTitle),\n          description: str_66(UIStrings85.description),\n          requiredArtifacts: [\"Accessibility\"]\n        };\n      }\n    };\n    valid_lang_default = ValidLang;\n  }\n});\n\n// core/audits/accessibility/video-caption.js\nvar video_caption_exports = {};\n__export(video_caption_exports, {\n  UIStrings: () => UIStrings86,\n  default: () => video_caption_default\n});\nvar UIStrings86, str_67, VideoCaption, video_caption_default;\nvar init_video_caption = __esm({\n  \"core/audits/accessibility/video-caption.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_axe_audit();\n    init_i18n();\n    /**\n     * @license\n     * Copyright 2017 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    UIStrings86 = {\n      /** Title of an accessibility audit that evaluates if all video elements contain a child track element that has captions describing their audio. This title is descriptive of the successful state and is shown to users when no user action is required. */\n      title: '`<video>` elements contain a `<track>` element with `[kind=\"captions\"]`',\n      /** Title of an accessibility audit that evaluates if all video elements contain a child track element that has captions describing their audio. This title is descriptive of the failing state and is shown to users when there is a failure that needs to be addressed. */\n      failureTitle: '`<video>` elements do not contain a `<track>` element with `[kind=\"captions\"]`.',\n      /** Description of a Lighthouse audit that tells the user *why* they should try to pass. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */\n      description: \"When a video provides a caption it is easier for deaf and hearing impaired users to access its information. [Learn more about video captions](https://dequeuniversity.com/rules/axe/4.11/video-caption).\"\n    };\n    str_67 = createIcuMessageFn({ url: \"core/audits/accessibility/video-caption.js\" }.url, UIStrings86);\n    VideoCaption = class extends axe_audit_default {\n      static {\n        __name(this, \"VideoCaption\");\n      }\n      /**\n       * @return {LH.Audit.Meta}\n       */\n      static get meta() {\n        return {\n          id: \"video-caption\",\n          title: str_67(UIStrings86.title),\n          failureTitle: str_67(UIStrings86.failureTitle),\n          description: str_67(UIStrings86.description),\n          scoreDisplayMode: axe_audit_default.SCORING_MODES.INFORMATIVE,\n          requiredArtifacts: [\"Accessibility\"]\n        };\n      }\n    };\n    video_caption_default = VideoCaption;\n  }\n});\n\n// core/audits/clickjacking-mitigation.js\nvar clickjacking_mitigation_exports = {};\n__export(clickjacking_mitigation_exports, {\n  UIStrings: () => UIStrings87,\n  default: () => clickjacking_mitigation_default\n});\nvar UIStrings87, str_68, ClickjackingMitigation, clickjacking_mitigation_default;\nvar init_clickjacking_mitigation = __esm({\n  \"core/audits/clickjacking-mitigation.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_audit();\n    init_main_resource();\n    init_i18n();\n    /**\n     * @license\n     * Copyright 2024 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    UIStrings87 = {\n      /** Title of a Lighthouse audit that evaluates whether the set CSP or XFO header is mitigating clickjacking attacks. \"XFO\" stands for \"X-Frame-Options\" and should not be translated. \"CSP\" stands for \"Content-Security-Policy\" and should not be translated. \"clickjacking\" should not be translated. */\n      title: \"Mitigate clickjacking with XFO or CSP\",\n      /** Description of a Lighthouse audit that evaluates whether the set CSP or XFO header is mitigating clickjacking attacks. This is displayed after a user expands the section to see more. \"clickjacking\" should not be translated. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. \"XFO\" stands for \"X-Frame-Options\" and should not be translated. \"CSP\" stands for \"Content-Security-Policy\" and should not be translated. */\n      description: \"The `X-Frame-Options` (XFO) header or the `frame-ancestors` directive in the `Content-Security-Policy` (CSP) header control where a page can be embedded. These can mitigate clickjacking attacks by blocking some or all sites from embedding the page. [Learn more about mitigating clickjacking](https://developer.chrome.com/docs/lighthouse/best-practices/clickjacking-mitigation).\",\n      /** Summary text for the results of a Lighthouse audit that evaluates whether the page is mitigating clickjacking attacks with a frame control policy. This text is displayed if the page does not control how it can be embedded on other pages. */\n      noClickjackingMitigation: \"No frame control policy found\",\n      /** Label for a column in a data table; entries will be the severity of an issue with the page's frame control policy. */\n      columnSeverity: \"Severity\"\n    };\n    str_68 = createIcuMessageFn({ url: \"core/audits/clickjacking-mitigation.js\" }.url, UIStrings87);\n    ClickjackingMitigation = class extends Audit {\n      static {\n        __name(this, \"ClickjackingMitigation\");\n      }\n      /**\n       * @return {LH.Audit.Meta}\n       */\n      static get meta() {\n        return {\n          id: \"clickjacking-mitigation\",\n          scoreDisplayMode: Audit.SCORING_MODES.INFORMATIVE,\n          title: str_68(UIStrings87.title),\n          description: str_68(UIStrings87.description),\n          requiredArtifacts: [\"DevtoolsLog\", \"URL\"],\n          supportedModes: [\"navigation\"]\n        };\n      }\n      /**\n       * @param {LH.Artifacts} artifacts\n       * @param {LH.Audit.Context} context\n       * @return {Promise<{cspHeaders: string[], xfoHeaders: string[]}>}\n       */\n      static async getRawCspsAndXfo(artifacts, context) {\n        const devtoolsLog = artifacts.DevtoolsLog;\n        const mainResource = await MainResourceComputed.request({ devtoolsLog, URL: artifacts.URL }, context);\n        const cspHeaders = mainResource.responseHeaders.filter((h) => {\n          return h.name.toLowerCase() === \"content-security-policy\";\n        }).flatMap((h) => h.value.split(\",\")).filter((rawCsp) => rawCsp.replace(/\\s/g, \"\"));\n        let xfoHeaders = mainResource.responseHeaders.filter((h) => {\n          return h.name.toLowerCase() === \"x-frame-options\";\n        }).flatMap((h) => h.value);\n        xfoHeaders = xfoHeaders.map((v) => v.toLowerCase().replace(/\\s/g, \"\"));\n        return { cspHeaders, xfoHeaders };\n      }\n      /**\n       * @param {string | undefined} directive\n       * @param {LH.IcuMessage | string} findingDescription\n       * @param {LH.IcuMessage=} severity\n       * @return {LH.Audit.Details.TableItem}\n       */\n      static findingToTableItem(directive, findingDescription, severity) {\n        return {\n          description: findingDescription,\n          severity\n        };\n      }\n      /**\n       * @param {string[]} cspHeaders\n       * @param {string[]} xfoHeaders\n       * @return {{score: number, results: LH.Audit.Details.TableItem[]}}\n       */\n      static constructResults(cspHeaders, xfoHeaders) {\n        const allowedDirectives = [\"deny\", \"sameorigin\"];\n        for (const cspHeader of cspHeaders) {\n          if (cspHeader.includes(\"frame-ancestors\")) {\n            return { score: 1, results: [] };\n          }\n        }\n        for (const actualDirective of xfoHeaders) {\n          if (allowedDirectives.includes(actualDirective)) {\n            return { score: 1, results: [] };\n          }\n        }\n        return {\n          score: 0,\n          results: [{\n            severity: str_68(UIStrings.itemSeverityHigh),\n            description: str_68(UIStrings87.noClickjackingMitigation)\n          }]\n        };\n      }\n      /**\n       * @param {LH.Artifacts} artifacts\n       * @param {LH.Audit.Context} context\n       * @return {Promise<LH.Audit.Product>}\n       */\n      static async audit(artifacts, context) {\n        const { cspHeaders, xfoHeaders } = await this.getRawCspsAndXfo(artifacts, context);\n        const { score, results } = this.constructResults(cspHeaders, xfoHeaders);\n        const headings = [\n          /* eslint-disable max-len */\n          { key: \"description\", valueType: \"text\", subItemsHeading: { key: \"description\" }, label: str_68(UIStrings.columnDescription) },\n          { key: \"severity\", valueType: \"text\", subItemsHeading: { key: \"severity\" }, label: str_68(UIStrings87.columnSeverity) }\n          /* eslint-enable max-len */\n        ];\n        const details = Audit.makeTableDetails(headings, results);\n        return {\n          score,\n          notApplicable: !results.length,\n          details\n        };\n      }\n    };\n    clickjacking_mitigation_default = ClickjackingMitigation;\n  }\n});\n\n// node_modules/csp_evaluator/dist/finding.js\nvar require_finding = __commonJS({\n  \"node_modules/csp_evaluator/dist/finding.js\"(exports2) {\n    \"use strict\";\n    init_process_global();\n    Object.defineProperty(exports2, \"__esModule\", { value: true });\n    exports2.Type = exports2.Severity = exports2.Finding = void 0;\n    var Finding = class _Finding {\n      static {\n        __name(this, \"Finding\");\n      }\n      constructor(type, description, severity, directive, value) {\n        this.type = type;\n        this.description = description;\n        this.severity = severity;\n        this.directive = directive;\n        this.value = value;\n      }\n      static getHighestSeverity(findings) {\n        if (findings.length === 0) {\n          return Severity.NONE;\n        }\n        const severities = findings.map((finding) => finding.severity);\n        const min = /* @__PURE__ */ __name((prev, cur) => prev < cur ? prev : cur, \"min\");\n        return severities.reduce(min, Severity.NONE);\n      }\n      equals(obj) {\n        if (!(obj instanceof _Finding)) {\n          return false;\n        }\n        return obj.type === this.type && obj.description === this.description && obj.severity === this.severity && obj.directive === this.directive && obj.value === this.value;\n      }\n    };\n    exports2.Finding = Finding;\n    var Severity;\n    (function(Severity2) {\n      Severity2[Severity2[\"HIGH\"] = 10] = \"HIGH\";\n      Severity2[Severity2[\"SYNTAX\"] = 20] = \"SYNTAX\";\n      Severity2[Severity2[\"MEDIUM\"] = 30] = \"MEDIUM\";\n      Severity2[Severity2[\"HIGH_MAYBE\"] = 40] = \"HIGH_MAYBE\";\n      Severity2[Severity2[\"STRICT_CSP\"] = 45] = \"STRICT_CSP\";\n      Severity2[Severity2[\"MEDIUM_MAYBE\"] = 50] = \"MEDIUM_MAYBE\";\n      Severity2[Severity2[\"INFO\"] = 60] = \"INFO\";\n      Severity2[Severity2[\"NONE\"] = 100] = \"NONE\";\n    })(Severity = exports2.Severity || (exports2.Severity = {}));\n    var Type2;\n    (function(Type3) {\n      Type3[Type3[\"MISSING_SEMICOLON\"] = 100] = \"MISSING_SEMICOLON\";\n      Type3[Type3[\"UNKNOWN_DIRECTIVE\"] = 101] = \"UNKNOWN_DIRECTIVE\";\n      Type3[Type3[\"INVALID_KEYWORD\"] = 102] = \"INVALID_KEYWORD\";\n      Type3[Type3[\"NONCE_CHARSET\"] = 106] = \"NONCE_CHARSET\";\n      Type3[Type3[\"MISSING_DIRECTIVES\"] = 300] = \"MISSING_DIRECTIVES\";\n      Type3[Type3[\"SCRIPT_UNSAFE_INLINE\"] = 301] = \"SCRIPT_UNSAFE_INLINE\";\n      Type3[Type3[\"SCRIPT_UNSAFE_EVAL\"] = 302] = \"SCRIPT_UNSAFE_EVAL\";\n      Type3[Type3[\"PLAIN_URL_SCHEMES\"] = 303] = \"PLAIN_URL_SCHEMES\";\n      Type3[Type3[\"PLAIN_WILDCARD\"] = 304] = \"PLAIN_WILDCARD\";\n      Type3[Type3[\"SCRIPT_ALLOWLIST_BYPASS\"] = 305] = \"SCRIPT_ALLOWLIST_BYPASS\";\n      Type3[Type3[\"OBJECT_ALLOWLIST_BYPASS\"] = 306] = \"OBJECT_ALLOWLIST_BYPASS\";\n      Type3[Type3[\"NONCE_LENGTH\"] = 307] = \"NONCE_LENGTH\";\n      Type3[Type3[\"IP_SOURCE\"] = 308] = \"IP_SOURCE\";\n      Type3[Type3[\"DEPRECATED_DIRECTIVE\"] = 309] = \"DEPRECATED_DIRECTIVE\";\n      Type3[Type3[\"SRC_HTTP\"] = 310] = \"SRC_HTTP\";\n      Type3[Type3[\"SRC_NO_PROTOCOL\"] = 311] = \"SRC_NO_PROTOCOL\";\n      Type3[Type3[\"EXPERIMENTAL\"] = 312] = \"EXPERIMENTAL\";\n      Type3[Type3[\"WILDCARD_URL\"] = 313] = \"WILDCARD_URL\";\n      Type3[Type3[\"X_FRAME_OPTIONS_OBSOLETED\"] = 314] = \"X_FRAME_OPTIONS_OBSOLETED\";\n      Type3[Type3[\"STYLE_UNSAFE_INLINE\"] = 315] = \"STYLE_UNSAFE_INLINE\";\n      Type3[Type3[\"STATIC_NONCE\"] = 316] = \"STATIC_NONCE\";\n      Type3[Type3[\"SCRIPT_UNSAFE_HASHES\"] = 317] = \"SCRIPT_UNSAFE_HASHES\";\n      Type3[Type3[\"STRICT_DYNAMIC\"] = 400] = \"STRICT_DYNAMIC\";\n      Type3[Type3[\"STRICT_DYNAMIC_NOT_STANDALONE\"] = 401] = \"STRICT_DYNAMIC_NOT_STANDALONE\";\n      Type3[Type3[\"NONCE_HASH\"] = 402] = \"NONCE_HASH\";\n      Type3[Type3[\"UNSAFE_INLINE_FALLBACK\"] = 403] = \"UNSAFE_INLINE_FALLBACK\";\n      Type3[Type3[\"ALLOWLIST_FALLBACK\"] = 404] = \"ALLOWLIST_FALLBACK\";\n      Type3[Type3[\"IGNORED\"] = 405] = \"IGNORED\";\n      Type3[Type3[\"REQUIRE_TRUSTED_TYPES_FOR_SCRIPTS\"] = 500] = \"REQUIRE_TRUSTED_TYPES_FOR_SCRIPTS\";\n      Type3[Type3[\"REPORTING_DESTINATION_MISSING\"] = 600] = \"REPORTING_DESTINATION_MISSING\";\n      Type3[Type3[\"REPORT_TO_ONLY\"] = 601] = \"REPORT_TO_ONLY\";\n    })(Type2 = exports2.Type || (exports2.Type = {}));\n  }\n});\n\n// node_modules/csp_evaluator/dist/csp.js\nvar require_csp = __commonJS({\n  \"node_modules/csp_evaluator/dist/csp.js\"(exports2) {\n    \"use strict\";\n    init_process_global();\n    Object.defineProperty(exports2, \"__esModule\", { value: true });\n    exports2.CspError = exports2.isHash = exports2.HASH_PATTERN = exports2.STRICT_HASH_PATTERN = exports2.isNonce = exports2.NONCE_PATTERN = exports2.STRICT_NONCE_PATTERN = exports2.isUrlScheme = exports2.isKeyword = exports2.isDirective = exports2.Version = exports2.FETCH_DIRECTIVES = exports2.Directive = exports2.TrustedTypesSink = exports2.Keyword = exports2.Csp = void 0;\n    var finding_1 = require_finding();\n    var Csp = class _Csp {\n      static {\n        __name(this, \"Csp\");\n      }\n      constructor(directives = {}) {\n        this.directives = {};\n        for (const [directive, directiveValues] of Object.entries(directives)) {\n          if (directiveValues) {\n            this.directives[directive] = [...directiveValues];\n          }\n        }\n      }\n      clone() {\n        return new _Csp(this.directives);\n      }\n      convertToString() {\n        let cspString = \"\";\n        for (const [directive, directiveValues] of Object.entries(this.directives)) {\n          cspString += directive;\n          if (directiveValues !== void 0) {\n            for (let value, i = 0; value = directiveValues[i]; i++) {\n              cspString += \" \";\n              cspString += value;\n            }\n          }\n          cspString += \"; \";\n        }\n        return cspString;\n      }\n      getEffectiveCsp(cspVersion, optFindings) {\n        const findings = optFindings || [];\n        const effectiveCsp = this.clone();\n        [Directive3.SCRIPT_SRC, Directive3.SCRIPT_SRC_ATTR, Directive3.SCRIPT_SRC_ELEM].forEach((directiveToNormalize) => {\n          const directive = effectiveCsp.getEffectiveDirective(directiveToNormalize);\n          const values = this.directives[directive] || [];\n          const effectiveCspValues = effectiveCsp.directives[directive];\n          if (effectiveCspValues && (effectiveCsp.policyHasScriptNonces(directive) || effectiveCsp.policyHasScriptHashes(directive))) {\n            if (cspVersion >= Version.CSP2) {\n              if (values.includes(Keyword.UNSAFE_INLINE)) {\n                arrayRemove(effectiveCspValues, Keyword.UNSAFE_INLINE);\n                findings.push(new finding_1.Finding(finding_1.Type.IGNORED, \"unsafe-inline is ignored if a nonce or a hash is present. (CSP2 and above)\", finding_1.Severity.NONE, directive, Keyword.UNSAFE_INLINE));\n              }\n            } else {\n              for (const value of values) {\n                if (value.startsWith(\"'nonce-\") || value.startsWith(\"'sha\")) {\n                  arrayRemove(effectiveCspValues, value);\n                }\n              }\n            }\n          }\n          if (effectiveCspValues && this.policyHasStrictDynamic(directive)) {\n            if (cspVersion >= Version.CSP3) {\n              for (const value of values) {\n                if (!value.startsWith(\"'\") || value === Keyword.SELF || value === Keyword.UNSAFE_INLINE) {\n                  arrayRemove(effectiveCspValues, value);\n                  findings.push(new finding_1.Finding(finding_1.Type.IGNORED, \"Because of strict-dynamic this entry is ignored in CSP3 and above\", finding_1.Severity.NONE, directive, value));\n                }\n              }\n            } else {\n              arrayRemove(effectiveCspValues, Keyword.STRICT_DYNAMIC);\n            }\n          }\n        });\n        if (cspVersion < Version.CSP3) {\n          delete effectiveCsp.directives[Directive3.REPORT_TO];\n          delete effectiveCsp.directives[Directive3.WORKER_SRC];\n          delete effectiveCsp.directives[Directive3.MANIFEST_SRC];\n          delete effectiveCsp.directives[Directive3.TRUSTED_TYPES];\n          delete effectiveCsp.directives[Directive3.REQUIRE_TRUSTED_TYPES_FOR];\n          delete effectiveCsp.directives[Directive3.SCRIPT_SRC_ATTR];\n          delete effectiveCsp.directives[Directive3.SCRIPT_SRC_ELEM];\n          delete effectiveCsp.directives[Directive3.STYLE_SRC_ATTR];\n          delete effectiveCsp.directives[Directive3.STYLE_SRC_ELEM];\n        }\n        return effectiveCsp;\n      }\n      getEffectiveDirective(directive) {\n        if (directive in this.directives) {\n          return directive;\n        }\n        if ((directive === Directive3.SCRIPT_SRC_ATTR || directive === Directive3.SCRIPT_SRC_ELEM) && Directive3.SCRIPT_SRC in this.directives) {\n          return Directive3.SCRIPT_SRC;\n        }\n        if ((directive === Directive3.STYLE_SRC_ATTR || directive === Directive3.STYLE_SRC_ELEM) && Directive3.STYLE_SRC in this.directives) {\n          return Directive3.STYLE_SRC;\n        }\n        if (exports2.FETCH_DIRECTIVES.includes(directive)) {\n          return Directive3.DEFAULT_SRC;\n        }\n        return directive;\n      }\n      getEffectiveDirectives(directives) {\n        const effectiveDirectives = new Set(directives.map((val) => this.getEffectiveDirective(val)));\n        return [...effectiveDirectives];\n      }\n      policyHasScriptNonces(directive) {\n        const directiveName = this.getEffectiveDirective(directive || Directive3.SCRIPT_SRC);\n        const values = this.directives[directiveName] || [];\n        return values.some((val) => isNonce(val));\n      }\n      policyHasScriptHashes(directive) {\n        const directiveName = this.getEffectiveDirective(directive || Directive3.SCRIPT_SRC);\n        const values = this.directives[directiveName] || [];\n        return values.some((val) => isHash(val));\n      }\n      policyHasStrictDynamic(directive) {\n        const directiveName = this.getEffectiveDirective(directive || Directive3.SCRIPT_SRC);\n        const values = this.directives[directiveName] || [];\n        return values.includes(Keyword.STRICT_DYNAMIC);\n      }\n    };\n    exports2.Csp = Csp;\n    var Keyword;\n    (function(Keyword2) {\n      Keyword2[\"SELF\"] = \"'self'\";\n      Keyword2[\"NONE\"] = \"'none'\";\n      Keyword2[\"UNSAFE_INLINE\"] = \"'unsafe-inline'\";\n      Keyword2[\"UNSAFE_EVAL\"] = \"'unsafe-eval'\";\n      Keyword2[\"WASM_EVAL\"] = \"'wasm-eval'\";\n      Keyword2[\"WASM_UNSAFE_EVAL\"] = \"'wasm-unsafe-eval'\";\n      Keyword2[\"STRICT_DYNAMIC\"] = \"'strict-dynamic'\";\n      Keyword2[\"UNSAFE_HASHED_ATTRIBUTES\"] = \"'unsafe-hashed-attributes'\";\n      Keyword2[\"UNSAFE_HASHES\"] = \"'unsafe-hashes'\";\n      Keyword2[\"REPORT_SAMPLE\"] = \"'report-sample'\";\n      Keyword2[\"BLOCK\"] = \"'block'\";\n      Keyword2[\"ALLOW\"] = \"'allow'\";\n      Keyword2[\"INLINE_SPECULATION_RULES\"] = \"'inline-speculation-rules'\";\n    })(Keyword = exports2.Keyword || (exports2.Keyword = {}));\n    var TrustedTypesSink;\n    (function(TrustedTypesSink2) {\n      TrustedTypesSink2[\"SCRIPT\"] = \"'script'\";\n    })(TrustedTypesSink = exports2.TrustedTypesSink || (exports2.TrustedTypesSink = {}));\n    var Directive3;\n    (function(Directive4) {\n      Directive4[\"CHILD_SRC\"] = \"child-src\";\n      Directive4[\"CONNECT_SRC\"] = \"connect-src\";\n      Directive4[\"DEFAULT_SRC\"] = \"default-src\";\n      Directive4[\"FONT_SRC\"] = \"font-src\";\n      Directive4[\"FRAME_SRC\"] = \"frame-src\";\n      Directive4[\"IMG_SRC\"] = \"img-src\";\n      Directive4[\"MEDIA_SRC\"] = \"media-src\";\n      Directive4[\"OBJECT_SRC\"] = \"object-src\";\n      Directive4[\"SCRIPT_SRC\"] = \"script-src\";\n      Directive4[\"SCRIPT_SRC_ATTR\"] = \"script-src-attr\";\n      Directive4[\"SCRIPT_SRC_ELEM\"] = \"script-src-elem\";\n      Directive4[\"STYLE_SRC\"] = \"style-src\";\n      Directive4[\"STYLE_SRC_ATTR\"] = \"style-src-attr\";\n      Directive4[\"STYLE_SRC_ELEM\"] = \"style-src-elem\";\n      Directive4[\"PREFETCH_SRC\"] = \"prefetch-src\";\n      Directive4[\"MANIFEST_SRC\"] = \"manifest-src\";\n      Directive4[\"WORKER_SRC\"] = \"worker-src\";\n      Directive4[\"BASE_URI\"] = \"base-uri\";\n      Directive4[\"PLUGIN_TYPES\"] = \"plugin-types\";\n      Directive4[\"SANDBOX\"] = \"sandbox\";\n      Directive4[\"DISOWN_OPENER\"] = \"disown-opener\";\n      Directive4[\"FORM_ACTION\"] = \"form-action\";\n      Directive4[\"FRAME_ANCESTORS\"] = \"frame-ancestors\";\n      Directive4[\"NAVIGATE_TO\"] = \"navigate-to\";\n      Directive4[\"REPORT_TO\"] = \"report-to\";\n      Directive4[\"REPORT_URI\"] = \"report-uri\";\n      Directive4[\"BLOCK_ALL_MIXED_CONTENT\"] = \"block-all-mixed-content\";\n      Directive4[\"UPGRADE_INSECURE_REQUESTS\"] = \"upgrade-insecure-requests\";\n      Directive4[\"REFLECTED_XSS\"] = \"reflected-xss\";\n      Directive4[\"REFERRER\"] = \"referrer\";\n      Directive4[\"REQUIRE_SRI_FOR\"] = \"require-sri-for\";\n      Directive4[\"TRUSTED_TYPES\"] = \"trusted-types\";\n      Directive4[\"REQUIRE_TRUSTED_TYPES_FOR\"] = \"require-trusted-types-for\";\n      Directive4[\"WEBRTC\"] = \"webrtc\";\n    })(Directive3 = exports2.Directive || (exports2.Directive = {}));\n    exports2.FETCH_DIRECTIVES = [\n      Directive3.CHILD_SRC,\n      Directive3.CONNECT_SRC,\n      Directive3.DEFAULT_SRC,\n      Directive3.FONT_SRC,\n      Directive3.FRAME_SRC,\n      Directive3.IMG_SRC,\n      Directive3.MANIFEST_SRC,\n      Directive3.MEDIA_SRC,\n      Directive3.OBJECT_SRC,\n      Directive3.SCRIPT_SRC,\n      Directive3.SCRIPT_SRC_ATTR,\n      Directive3.SCRIPT_SRC_ELEM,\n      Directive3.STYLE_SRC,\n      Directive3.STYLE_SRC_ATTR,\n      Directive3.STYLE_SRC_ELEM,\n      Directive3.WORKER_SRC\n    ];\n    var Version;\n    (function(Version2) {\n      Version2[Version2[\"CSP1\"] = 1] = \"CSP1\";\n      Version2[Version2[\"CSP2\"] = 2] = \"CSP2\";\n      Version2[Version2[\"CSP3\"] = 3] = \"CSP3\";\n    })(Version = exports2.Version || (exports2.Version = {}));\n    function isDirective(directive) {\n      return Object.values(Directive3).includes(directive);\n    }\n    __name(isDirective, \"isDirective\");\n    exports2.isDirective = isDirective;\n    function isKeyword(keyword) {\n      return Object.values(Keyword).includes(keyword);\n    }\n    __name(isKeyword, \"isKeyword\");\n    exports2.isKeyword = isKeyword;\n    function isUrlScheme(urlScheme) {\n      const pattern = new RegExp(\"^[a-zA-Z][+a-zA-Z0-9.-]*:$\");\n      return pattern.test(urlScheme);\n    }\n    __name(isUrlScheme, \"isUrlScheme\");\n    exports2.isUrlScheme = isUrlScheme;\n    exports2.STRICT_NONCE_PATTERN = new RegExp(\"^'nonce-[a-zA-Z0-9+/_-]+[=]{0,2}'$\");\n    exports2.NONCE_PATTERN = new RegExp(\"^'nonce-(.+)'$\");\n    function isNonce(nonce, strictCheck) {\n      const pattern = strictCheck ? exports2.STRICT_NONCE_PATTERN : exports2.NONCE_PATTERN;\n      return pattern.test(nonce);\n    }\n    __name(isNonce, \"isNonce\");\n    exports2.isNonce = isNonce;\n    exports2.STRICT_HASH_PATTERN = new RegExp(\"^'(sha256|sha384|sha512)-[a-zA-Z0-9+/]+[=]{0,2}'$\");\n    exports2.HASH_PATTERN = new RegExp(\"^'(sha256|sha384|sha512)-(.+)'$\");\n    function isHash(hash, strictCheck) {\n      const pattern = strictCheck ? exports2.STRICT_HASH_PATTERN : exports2.HASH_PATTERN;\n      return pattern.test(hash);\n    }\n    __name(isHash, \"isHash\");\n    exports2.isHash = isHash;\n    var CspError = class extends Error {\n      static {\n        __name(this, \"CspError\");\n      }\n      constructor(message) {\n        super(message);\n      }\n    };\n    exports2.CspError = CspError;\n    function arrayRemove(arr, item) {\n      if (arr.includes(item)) {\n        const idx = arr.findIndex((elem) => item === elem);\n        arr.splice(idx, 1);\n      }\n    }\n    __name(arrayRemove, \"arrayRemove\");\n  }\n});\n\n// node_modules/csp_evaluator/dist/checks/parser_checks.js\nvar require_parser_checks = __commonJS({\n  \"node_modules/csp_evaluator/dist/checks/parser_checks.js\"(exports2) {\n    \"use strict\";\n    init_process_global();\n    var __createBinding4 = exports2 && exports2.__createBinding || (Object.create ? (function(o, m, k, k2) {\n      if (k2 === void 0) k2 = k;\n      Object.defineProperty(o, k2, { enumerable: true, get: /* @__PURE__ */ __name(function() {\n        return m[k];\n      }, \"get\") });\n    }) : (function(o, m, k, k2) {\n      if (k2 === void 0) k2 = k;\n      o[k2] = m[k];\n    }));\n    var __setModuleDefault4 = exports2 && exports2.__setModuleDefault || (Object.create ? (function(o, v) {\n      Object.defineProperty(o, \"default\", { enumerable: true, value: v });\n    }) : function(o, v) {\n      o[\"default\"] = v;\n    });\n    var __importStar4 = exports2 && exports2.__importStar || function(mod2) {\n      if (mod2 && mod2.__esModule) return mod2;\n      var result = {};\n      if (mod2 != null) {\n        for (var k in mod2) if (k !== \"default\" && Object.prototype.hasOwnProperty.call(mod2, k)) __createBinding4(result, mod2, k);\n      }\n      __setModuleDefault4(result, mod2);\n      return result;\n    };\n    Object.defineProperty(exports2, \"__esModule\", { value: true });\n    exports2.checkInvalidKeyword = exports2.checkMissingSemicolon = exports2.checkUnknownDirective = void 0;\n    var csp = __importStar4(require_csp());\n    var csp_1 = require_csp();\n    var finding_1 = require_finding();\n    function checkUnknownDirective(parsedCsp) {\n      const findings = [];\n      for (const directive of Object.keys(parsedCsp.directives)) {\n        if (csp.isDirective(directive)) {\n          continue;\n        }\n        if (directive.endsWith(\":\")) {\n          findings.push(new finding_1.Finding(finding_1.Type.UNKNOWN_DIRECTIVE, \"CSP directives don't end with a colon.\", finding_1.Severity.SYNTAX, directive));\n        } else {\n          findings.push(new finding_1.Finding(finding_1.Type.UNKNOWN_DIRECTIVE, 'Directive \"' + directive + '\" is not a known CSP directive.', finding_1.Severity.SYNTAX, directive));\n        }\n      }\n      return findings;\n    }\n    __name(checkUnknownDirective, \"checkUnknownDirective\");\n    exports2.checkUnknownDirective = checkUnknownDirective;\n    function checkMissingSemicolon(parsedCsp) {\n      const findings = [];\n      for (const [directive, directiveValues] of Object.entries(parsedCsp.directives)) {\n        if (directiveValues === void 0) {\n          continue;\n        }\n        for (const value of directiveValues) {\n          if (csp.isDirective(value)) {\n            findings.push(new finding_1.Finding(finding_1.Type.MISSING_SEMICOLON, 'Did you forget the semicolon? \"' + value + '\" seems to be a directive, not a value.', finding_1.Severity.SYNTAX, directive, value));\n          }\n        }\n      }\n      return findings;\n    }\n    __name(checkMissingSemicolon, \"checkMissingSemicolon\");\n    exports2.checkMissingSemicolon = checkMissingSemicolon;\n    function checkInvalidKeyword(parsedCsp) {\n      const findings = [];\n      const keywordsNoTicks = Object.values(csp_1.Keyword).map((k) => k.replace(/'/g, \"\"));\n      for (const [directive, directiveValues] of Object.entries(parsedCsp.directives)) {\n        if (directiveValues === void 0) {\n          continue;\n        }\n        for (const value of directiveValues) {\n          if (keywordsNoTicks.some((k) => k === value) || value.startsWith(\"nonce-\") || value.match(/^(sha256|sha384|sha512)-/)) {\n            findings.push(new finding_1.Finding(finding_1.Type.INVALID_KEYWORD, 'Did you forget to surround \"' + value + '\" with single-ticks?', finding_1.Severity.SYNTAX, directive, value));\n            continue;\n          }\n          if (!value.startsWith(\"'\")) {\n            continue;\n          }\n          if (directive === csp.Directive.REQUIRE_TRUSTED_TYPES_FOR) {\n            if (value === csp.TrustedTypesSink.SCRIPT) {\n              continue;\n            }\n          } else if (directive === csp.Directive.TRUSTED_TYPES) {\n            if (value === \"'allow-duplicates'\" || value === \"'none'\") {\n              continue;\n            }\n          } else {\n            if (csp.isKeyword(value) || csp.isHash(value) || csp.isNonce(value)) {\n              continue;\n            }\n          }\n          findings.push(new finding_1.Finding(finding_1.Type.INVALID_KEYWORD, value + \" seems to be an invalid CSP keyword.\", finding_1.Severity.SYNTAX, directive, value));\n        }\n      }\n      return findings;\n    }\n    __name(checkInvalidKeyword, \"checkInvalidKeyword\");\n    exports2.checkInvalidKeyword = checkInvalidKeyword;\n  }\n});\n\n// node_modules/csp_evaluator/dist/allowlist_bypasses/angular.js\nvar require_angular2 = __commonJS({\n  \"node_modules/csp_evaluator/dist/allowlist_bypasses/angular.js\"(exports2) {\n    \"use strict\";\n    init_process_global();\n    Object.defineProperty(exports2, \"__esModule\", { value: true });\n    exports2.URLS = void 0;\n    exports2.URLS = [\n      \"//gstatic.com/fsn/angular_js-bundle1.js\",\n      \"//www.gstatic.com/fsn/angular_js-bundle1.js\",\n      \"//www.googleadservices.com/pageadimg/imgad\",\n      \"//yandex.st/angularjs/1.2.16/angular-cookies.min.js\",\n      \"//yastatic.net/angularjs/1.2.23/angular.min.js\",\n      \"//yuedust.yuedu.126.net/js/components/angular/angular.js\",\n      \"//art.jobs.netease.com/script/angular.js\",\n      \"//csu-c45.kxcdn.com/angular/angular.js\",\n      \"//elysiumwebsite.s3.amazonaws.com/uploads/blog-media/rockstar/angular.min.js\",\n      \"//inno.blob.core.windows.net/new/libs/AngularJS/1.2.1/angular.min.js\",\n      \"//gift-talk.kakao.com/public/javascripts/angular.min.js\",\n      \"//ajax.googleapis.com/ajax/libs/angularjs/1.2.0rc1/angular-route.min.js\",\n      \"//master-sumok.ru/vendors/angular/angular-cookies.js\",\n      \"//ayicommon-a.akamaihd.net/static/vendor/angular-1.4.2.min.js\",\n      \"//pangxiehaitao.com/framework/angular-1.3.9/angular-animate.min.js\",\n      \"//cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.16/angular.min.js\",\n      \"//96fe3ee995e96e922b6b-d10c35bd0a0de2c718b252bc575fdb73.ssl.cf1.rackcdn.com/angular.js\",\n      \"//oss.maxcdn.com/angularjs/1.2.20/angular.min.js\",\n      \"//reports.zemanta.com/smedia/common/angularjs/1.2.11/angular.js\",\n      \"//cdn.shopify.com/s/files/1/0225/6463/t/1/assets/angular-animate.min.js\",\n      \"//parademanagement.com.s3-website-ap-southeast-1.amazonaws.com/js/angular.min.js\",\n      \"//cdn.jsdelivr.net/angularjs/1.1.2/angular.min.js\",\n      \"//eb2883ede55c53e09fd5-9c145fb03d93709ea57875d307e2d82e.ssl.cf3.rackcdn.com/components/angular-resource.min.js\",\n      \"//andors-trail.googlecode.com/git/AndorsTrailEdit/lib/angular.min.js\",\n      \"//cdn.walkme.com/General/EnvironmentTests/angular/angular.min.js\",\n      \"//laundrymail.com/angular/angular.js\",\n      \"//s3-eu-west-1.amazonaws.com/staticancpa/js/angular-cookies.min.js\",\n      \"//collade.demo.stswp.com/js/vendor/angular.min.js\",\n      \"//mrfishie.github.io/sailor/bower_components/angular/angular.min.js\",\n      \"//askgithub.com/static/js/angular.min.js\",\n      \"//services.amazon.com/solution-providers/assets/vendor/angular-cookies.min.js\",\n      \"//raw.githubusercontent.com/angular/code.angularjs.org/master/1.0.7/angular-resource.js\",\n      \"//prb-resume.appspot.com/bower_components/angular-animate/angular-animate.js\",\n      \"//dl.dropboxusercontent.com/u/30877786/angular.min.js\",\n      \"//static.tumblr.com/x5qdx0r/nPOnngtff/angular-resource.min_1_.js\",\n      \"//storage.googleapis.com/assets-prod.urbansitter.net/us-sym/assets/vendor/angular-sanitize/angular-sanitize.min.js\",\n      \"//twitter.github.io/labella.js/bower_components/angular/angular.min.js\",\n      \"//cdn2-casinoroom.global.ssl.fastly.net/js/lib/angular-animate.min.js\",\n      \"//www.adobe.com/devnet-apps/flashshowcase/lib/angular/angular.1.1.5.min.js\",\n      \"//eternal-sunset.herokuapp.com/bower_components/angular/angular.js\",\n      \"//cdn.bootcss.com/angular.js/1.2.0/angular.min.js\"\n    ];\n  }\n});\n\n// node_modules/csp_evaluator/dist/allowlist_bypasses/flash.js\nvar require_flash = __commonJS({\n  \"node_modules/csp_evaluator/dist/allowlist_bypasses/flash.js\"(exports2) {\n    \"use strict\";\n    init_process_global();\n    Object.defineProperty(exports2, \"__esModule\", { value: true });\n    exports2.URLS = void 0;\n    exports2.URLS = [\n      \"//vk.com/swf/video.swf\",\n      \"//ajax.googleapis.com/ajax/libs/yui/2.8.0r4/build/charts/assets/charts.swf\"\n    ];\n  }\n});\n\n// node_modules/csp_evaluator/dist/allowlist_bypasses/jsonp.js\nvar require_jsonp = __commonJS({\n  \"node_modules/csp_evaluator/dist/allowlist_bypasses/jsonp.js\"(exports2) {\n    \"use strict\";\n    init_process_global();\n    Object.defineProperty(exports2, \"__esModule\", { value: true });\n    exports2.URLS = exports2.NEEDS_EVAL = void 0;\n    exports2.NEEDS_EVAL = [\n      \"googletagmanager.com\",\n      \"www.googletagmanager.com\",\n      \"www.googleadservices.com\",\n      \"google-analytics.com\",\n      \"ssl.google-analytics.com\",\n      \"www.google-analytics.com\"\n    ];\n    exports2.URLS = [\n      \"//bebezoo.1688.com/fragment/index.htm\",\n      \"//www.google-analytics.com/gtm/js\",\n      \"//googleads.g.doubleclick.net/pagead/conversion/1036918760/wcm\",\n      \"//www.googleadservices.com/pagead/conversion/1070110417/wcm\",\n      \"//www.google.com/tools/feedback/escalation-options\",\n      \"//pin.aliyun.com/check_audio\",\n      \"//offer.alibaba.com/market/CID100002954/5/fetchKeyword.do\",\n      \"//ccrprod.alipay.com/ccr/arriveTime.json\",\n      \"//group.aliexpress.com/ajaxAcquireGroupbuyProduct.do\",\n      \"//detector.alicdn.com/2.7.3/index.php\",\n      \"//suggest.taobao.com/sug\",\n      \"//translate.google.com/translate_a/l\",\n      \"//count.tbcdn.cn//counter3\",\n      \"//wb.amap.com/channel.php\",\n      \"//translate.googleapis.com/translate_a/l\",\n      \"//afpeng.alimama.com/ex\",\n      \"//accounts.google.com/o/oauth2/revoke\",\n      \"//pagead2.googlesyndication.com/relatedsearch\",\n      \"//yandex.ru/soft/browsers/check\",\n      \"//api.facebook.com/restserver.php\",\n      \"//mts0.googleapis.com/maps/vt\",\n      \"//syndication.twitter.com/widgets/timelines/765840589183213568\",\n      \"//www.youtube.com/profile_style\",\n      \"//googletagmanager.com/gtm/js\",\n      \"//mc.yandex.ru/watch/24306916/1\",\n      \"//share.yandex.net/counter/gpp/\",\n      \"//ok.go.mail.ru/lady_on_lady_recipes_r.json\",\n      \"//d1f69o4buvlrj5.cloudfront.net/__efa_15_1_ornpba.xekq.arg/optout_check\",\n      \"//www.googletagmanager.com/gtm/js\",\n      \"//api.vk.com/method/wall.get\",\n      \"//www.sharethis.com/get-publisher-info.php\",\n      \"//google.ru/maps/vt\",\n      \"//pro.netrox.sc/oapi/h_checksite.ashx\",\n      \"//vimeo.com/api/oembed.json/\",\n      \"//de.blog.newrelic.com/wp-admin/admin-ajax.php\",\n      \"//ajax.googleapis.com/ajax/services/search/news\",\n      \"//ssl.google-analytics.com/gtm/js\",\n      \"//pubsub.pubnub.com/subscribe/demo/hello_world/\",\n      \"//pass.yandex.ua/services\",\n      \"//id.rambler.ru/script/topline_info.js\",\n      \"//m.addthis.com/live/red_lojson/100eng.json\",\n      \"//passport.ngs.ru/ajax/check\",\n      \"//catalog.api.2gis.ru/ads/search\",\n      \"//gum.criteo.com/sync\",\n      \"//maps.google.com/maps/vt\",\n      \"//ynuf.alipay.com/service/um.json\",\n      \"//securepubads.g.doubleclick.net/gampad/ads\",\n      \"//c.tiles.mapbox.com/v3/texastribune.tx-congress-cvap/6/15/26.grid.json\",\n      \"//rexchange.begun.ru/banners\",\n      \"//an.yandex.ru/page/147484\",\n      \"//links.services.disqus.com/api/ping\",\n      \"//api.map.baidu.com/\",\n      \"//tj.gongchang.com/api/keywordrecomm/\",\n      \"//data.gongchang.com/livegrail/\",\n      \"//ulogin.ru/token.php\",\n      \"//beta.gismeteo.ru/api/informer/layout.js/120x240-3/ru/\",\n      \"//maps.googleapis.com/maps/api/js/GeoPhotoService.GetMetadata\",\n      \"//a.config.skype.com/config/v1/Skype/908_1.33.0.111/SkypePersonalization\",\n      \"//maps.beeline.ru/w\",\n      \"//target.ukr.net/\",\n      \"//www.meteoprog.ua/data/weather/informer/Poltava.js\",\n      \"//cdn.syndication.twimg.com/widgets/timelines/599200054310604802\",\n      \"//wslocker.ru/client/user.chk.php\",\n      \"//community.adobe.com/CommunityPod/getJSON\",\n      \"//maps.google.lv/maps/vt\",\n      \"//dev.virtualearth.net/REST/V1/Imagery/Metadata/AerialWithLabels/26.318581\",\n      \"//awaps.yandex.ru/10/8938/02400400.\",\n      \"//a248.e.akamai.net/h5.hulu.com/h5.mp4\",\n      \"//nominatim.openstreetmap.org/\",\n      \"//plugins.mozilla.org/en-us/plugins_list.json\",\n      \"//h.cackle.me/widget/32153/bootstrap\",\n      \"//graph.facebook.com/1/\",\n      \"//fellowes.ugc.bazaarvoice.com/data/reviews.json\",\n      \"//widgets.pinterest.com/v3/pidgets/boards/ciciwin/hedgehog-squirrel-crafts/pins/\",\n      \"//se.wikipedia.org/w/api.php\",\n      \"//cse.google.com/api/007627024705277327428/cse/r3vs7b0fcli/queries/js\",\n      \"//relap.io/api/v2/similar_pages_jsonp.js\",\n      \"//c1n3.hypercomments.com/stream/subscribe\",\n      \"//maps.google.de/maps/vt\",\n      \"//books.google.com/books\",\n      \"//connect.mail.ru/share_count\",\n      \"//tr.indeed.com/m/newjobs\",\n      \"//www-onepick-opensocial.googleusercontent.com/gadgets/proxy\",\n      \"//www.panoramio.com/map/get_panoramas.php\",\n      \"//client.siteheart.com/streamcli/client\",\n      \"//www.facebook.com/restserver.php\",\n      \"//autocomplete.travelpayouts.com/avia\",\n      \"//www.googleapis.com/freebase/v1/topic/m/0344_\",\n      \"//mts1.googleapis.com/mapslt/ft\",\n      \"//publish.twitter.com/oembed\",\n      \"//fast.wistia.com/embed/medias/o75jtw7654.json\",\n      \"//partner.googleadservices.com/gampad/ads\",\n      \"//pass.yandex.ru/services\",\n      \"//gupiao.baidu.com/stocks/stockbets\",\n      \"//widget.admitad.com/widget/init\",\n      \"//api.instagram.com/v1/tags/partykungen23328/media/recent\",\n      \"//video.media.yql.yahoo.com/v1/video/sapi/streams/063fb76c-6c70-38c5-9bbc-04b7c384de2b\",\n      \"//ib.adnxs.com/jpt\",\n      \"//pass.yandex.com/services\",\n      \"//www.google.de/maps/vt\",\n      \"//clients1.google.com/complete/search\",\n      \"//api.userlike.com/api/chat/slot/proactive/\",\n      \"//www.youku.com/index_cookielist/s/jsonp\",\n      \"//mt1.googleapis.com/mapslt/ft\",\n      \"//api.mixpanel.com/track/\",\n      \"//wpd.b.qq.com/cgi/get_sign.php\",\n      \"//pipes.yahooapis.com/pipes/pipe.run\",\n      \"//gdata.youtube.com/feeds/api/videos/WsJIHN1kNWc\",\n      \"//9.chart.apis.google.com/chart\",\n      \"//cdn.syndication.twitter.com/moments/709229296800440320\",\n      \"//api.flickr.com/services/feeds/photos_friends.gne\",\n      \"//cbks0.googleapis.com/cbk\",\n      \"//www.blogger.com/feeds/5578653387562324002/posts/summary/4427562025302749269\",\n      \"//query.yahooapis.com/v1/public/yql\",\n      \"//kecngantang.blogspot.com/feeds/posts/default/-/Komik\",\n      \"//www.travelpayouts.com/widgets/50f53ce9ada1b54bcc000031.json\",\n      \"//i.cackle.me/widget/32586/bootstrap\",\n      \"//translate.yandex.net/api/v1.5/tr.json/detect\",\n      \"//a.tiles.mapbox.com/v3/zentralmedia.map-n2raeauc.jsonp\",\n      \"//maps.google.ru/maps/vt\",\n      \"//c1n2.hypercomments.com/stream/subscribe\",\n      \"//rec.ydf.yandex.ru/cookie\",\n      \"//cdn.jsdelivr.net\"\n    ];\n  }\n});\n\n// node_modules/csp_evaluator/dist/utils.js\nvar require_utils = __commonJS({\n  \"node_modules/csp_evaluator/dist/utils.js\"(exports2) {\n    \"use strict\";\n    init_process_global();\n    Object.defineProperty(exports2, \"__esModule\", { value: true });\n    exports2.applyCheckFunktionToDirectives = exports2.matchWildcardUrls = exports2.getHostname = exports2.getSchemeFreeUrl = void 0;\n    function getSchemeFreeUrl(url) {\n      url = url.replace(/^\\w[+\\w.-]*:\\/\\//i, \"\");\n      url = url.replace(/^\\/\\//, \"\");\n      return url;\n    }\n    __name(getSchemeFreeUrl, \"getSchemeFreeUrl\");\n    exports2.getSchemeFreeUrl = getSchemeFreeUrl;\n    function getHostname(url) {\n      const hostname = new URL(\"https://\" + getSchemeFreeUrl(url).replace(\":*\", \"\").replace(\"*\", \"wildcard_placeholder\")).hostname.replace(\"wildcard_placeholder\", \"*\");\n      const ipv6Regex = /^\\[[\\d:]+\\]/;\n      if (getSchemeFreeUrl(url).match(ipv6Regex) && !hostname.match(ipv6Regex)) {\n        return \"[\" + hostname + \"]\";\n      }\n      return hostname;\n    }\n    __name(getHostname, \"getHostname\");\n    exports2.getHostname = getHostname;\n    function setScheme(u) {\n      if (u.startsWith(\"//\")) {\n        return u.replace(\"//\", \"https://\");\n      }\n      return u;\n    }\n    __name(setScheme, \"setScheme\");\n    function matchWildcardUrls(cspUrlString, listOfUrlStrings) {\n      const cspUrl = new URL(setScheme(cspUrlString.replace(\":*\", \"\").replace(\"*\", \"wildcard_placeholder\")));\n      const listOfUrls = listOfUrlStrings.map((u) => new URL(setScheme(u)));\n      const host = cspUrl.hostname.toLowerCase();\n      const hostHasWildcard = host.startsWith(\"wildcard_placeholder.\");\n      const wildcardFreeHost = host.replace(/^\\wildcard_placeholder/i, \"\");\n      const path7 = cspUrl.pathname;\n      const hasPath = path7 !== \"/\";\n      for (const url of listOfUrls) {\n        const domain = url.hostname;\n        if (!domain.endsWith(wildcardFreeHost)) {\n          continue;\n        }\n        if (!hostHasWildcard && host !== domain) {\n          continue;\n        }\n        if (hasPath) {\n          if (path7.endsWith(\"/\")) {\n            if (!url.pathname.startsWith(path7)) {\n              continue;\n            }\n          } else {\n            if (url.pathname !== path7) {\n              continue;\n            }\n          }\n        }\n        return url;\n      }\n      return null;\n    }\n    __name(matchWildcardUrls, \"matchWildcardUrls\");\n    exports2.matchWildcardUrls = matchWildcardUrls;\n    function applyCheckFunktionToDirectives(parsedCsp, check) {\n      const directiveNames = Object.keys(parsedCsp.directives);\n      for (const directive of directiveNames) {\n        const directiveValues = parsedCsp.directives[directive];\n        if (directiveValues) {\n          check(directive, directiveValues);\n        }\n      }\n    }\n    __name(applyCheckFunktionToDirectives, \"applyCheckFunktionToDirectives\");\n    exports2.applyCheckFunktionToDirectives = applyCheckFunktionToDirectives;\n  }\n});\n\n// node_modules/csp_evaluator/dist/checks/security_checks.js\nvar require_security_checks = __commonJS({\n  \"node_modules/csp_evaluator/dist/checks/security_checks.js\"(exports2) {\n    \"use strict\";\n    init_process_global();\n    var __createBinding4 = exports2 && exports2.__createBinding || (Object.create ? (function(o, m, k, k2) {\n      if (k2 === void 0) k2 = k;\n      Object.defineProperty(o, k2, { enumerable: true, get: /* @__PURE__ */ __name(function() {\n        return m[k];\n      }, \"get\") });\n    }) : (function(o, m, k, k2) {\n      if (k2 === void 0) k2 = k;\n      o[k2] = m[k];\n    }));\n    var __setModuleDefault4 = exports2 && exports2.__setModuleDefault || (Object.create ? (function(o, v) {\n      Object.defineProperty(o, \"default\", { enumerable: true, value: v });\n    }) : function(o, v) {\n      o[\"default\"] = v;\n    });\n    var __importStar4 = exports2 && exports2.__importStar || function(mod2) {\n      if (mod2 && mod2.__esModule) return mod2;\n      var result = {};\n      if (mod2 != null) {\n        for (var k in mod2) if (k !== \"default\" && Object.prototype.hasOwnProperty.call(mod2, k)) __createBinding4(result, mod2, k);\n      }\n      __setModuleDefault4(result, mod2);\n      return result;\n    };\n    Object.defineProperty(exports2, \"__esModule\", { value: true });\n    exports2.checkHasConfiguredReporting = exports2.checkSrcHttp = exports2.checkNonceLength = exports2.checkDeprecatedDirective = exports2.checkIpSource = exports2.looksLikeIpAddress = exports2.checkFlashObjectAllowlistBypass = exports2.checkScriptAllowlistBypass = exports2.checkMissingDirectives = exports2.checkMultipleMissingBaseUriDirective = exports2.checkMissingBaseUriDirective = exports2.checkMissingScriptSrcDirective = exports2.checkMissingObjectSrcDirective = exports2.checkWildcards = exports2.checkPlainUrlSchemes = exports2.checkScriptUnsafeEval = exports2.checkScriptUnsafeInline = exports2.URL_SCHEMES_CAUSING_XSS = exports2.DIRECTIVES_CAUSING_XSS = void 0;\n    var angular = __importStar4(require_angular2());\n    var flash = __importStar4(require_flash());\n    var jsonp = __importStar4(require_jsonp());\n    var csp = __importStar4(require_csp());\n    var csp_1 = require_csp();\n    var finding_1 = require_finding();\n    var utils = __importStar4(require_utils());\n    exports2.DIRECTIVES_CAUSING_XSS = [\n      csp_1.Directive.SCRIPT_SRC,\n      csp_1.Directive.SCRIPT_SRC_ATTR,\n      csp_1.Directive.SCRIPT_SRC_ELEM,\n      csp_1.Directive.OBJECT_SRC,\n      csp_1.Directive.BASE_URI\n    ];\n    exports2.URL_SCHEMES_CAUSING_XSS = [\"data:\", \"http:\", \"https:\"];\n    function checkScriptUnsafeInline(effectiveCsp) {\n      const violations = [];\n      const directivesToCheck = effectiveCsp.getEffectiveDirectives([\n        csp_1.Directive.SCRIPT_SRC,\n        csp_1.Directive.SCRIPT_SRC_ATTR,\n        csp_1.Directive.SCRIPT_SRC_ELEM\n      ]);\n      for (const directive of directivesToCheck) {\n        const values = effectiveCsp.directives[directive] || [];\n        if (values.includes(csp_1.Keyword.UNSAFE_INLINE)) {\n          violations.push(new finding_1.Finding(finding_1.Type.SCRIPT_UNSAFE_INLINE, `'unsafe-inline' allows the execution of unsafe in-page scripts and event handlers.`, finding_1.Severity.HIGH, directive, csp_1.Keyword.UNSAFE_INLINE));\n        }\n        if (values.includes(csp_1.Keyword.UNSAFE_HASHES)) {\n          violations.push(new finding_1.Finding(finding_1.Type.SCRIPT_UNSAFE_HASHES, `'unsafe-hashes', while safer than 'unsafe-inline', allows the execution of unsafe in-page scripts and event handlers as long as their hashes appear in the CSP. Please refactor them to no longer use inline scripts if possible.`, finding_1.Severity.MEDIUM_MAYBE, directive, csp_1.Keyword.UNSAFE_HASHES));\n        }\n      }\n      return violations;\n    }\n    __name(checkScriptUnsafeInline, \"checkScriptUnsafeInline\");\n    exports2.checkScriptUnsafeInline = checkScriptUnsafeInline;\n    function checkScriptUnsafeEval(parsedCsp) {\n      const violations = [];\n      const directivesToCheck = parsedCsp.getEffectiveDirectives([\n        csp_1.Directive.SCRIPT_SRC,\n        csp_1.Directive.SCRIPT_SRC_ATTR,\n        csp_1.Directive.SCRIPT_SRC_ELEM\n      ]);\n      for (const directive of directivesToCheck) {\n        const values = parsedCsp.directives[directive] || [];\n        if (values.includes(csp_1.Keyword.UNSAFE_EVAL)) {\n          violations.push(new finding_1.Finding(finding_1.Type.SCRIPT_UNSAFE_EVAL, `'unsafe-eval' allows the execution of code injected into DOM APIs such as eval().`, finding_1.Severity.MEDIUM_MAYBE, directive, csp_1.Keyword.UNSAFE_EVAL));\n        }\n      }\n      return violations;\n    }\n    __name(checkScriptUnsafeEval, \"checkScriptUnsafeEval\");\n    exports2.checkScriptUnsafeEval = checkScriptUnsafeEval;\n    function checkPlainUrlSchemes(parsedCsp) {\n      const violations = [];\n      const directivesToCheck = parsedCsp.getEffectiveDirectives(exports2.DIRECTIVES_CAUSING_XSS);\n      for (const directive of directivesToCheck) {\n        const values = parsedCsp.directives[directive] || [];\n        for (const value of values) {\n          if (exports2.URL_SCHEMES_CAUSING_XSS.includes(value)) {\n            violations.push(new finding_1.Finding(finding_1.Type.PLAIN_URL_SCHEMES, value + \" URI in \" + directive + \" allows the execution of unsafe scripts.\", finding_1.Severity.HIGH, directive, value));\n          }\n        }\n      }\n      return violations;\n    }\n    __name(checkPlainUrlSchemes, \"checkPlainUrlSchemes\");\n    exports2.checkPlainUrlSchemes = checkPlainUrlSchemes;\n    function checkWildcards(parsedCsp) {\n      const violations = [];\n      const directivesToCheck = parsedCsp.getEffectiveDirectives(exports2.DIRECTIVES_CAUSING_XSS);\n      for (const directive of directivesToCheck) {\n        const values = parsedCsp.directives[directive] || [];\n        for (const value of values) {\n          const url = utils.getSchemeFreeUrl(value);\n          if (url === \"*\") {\n            violations.push(new finding_1.Finding(finding_1.Type.PLAIN_WILDCARD, directive + ` should not allow '*' as source`, finding_1.Severity.HIGH, directive, value));\n            continue;\n          }\n        }\n      }\n      return violations;\n    }\n    __name(checkWildcards, \"checkWildcards\");\n    exports2.checkWildcards = checkWildcards;\n    function checkMissingObjectSrcDirective(parsedCsp) {\n      let objectRestrictions = [];\n      if (csp_1.Directive.OBJECT_SRC in parsedCsp.directives) {\n        objectRestrictions = parsedCsp.directives[csp_1.Directive.OBJECT_SRC];\n      } else if (csp_1.Directive.DEFAULT_SRC in parsedCsp.directives) {\n        objectRestrictions = parsedCsp.directives[csp_1.Directive.DEFAULT_SRC];\n      }\n      if (objectRestrictions !== void 0 && objectRestrictions.length >= 1) {\n        return [];\n      }\n      return [new finding_1.Finding(finding_1.Type.MISSING_DIRECTIVES, `Missing object-src allows the injection of plugins which can execute JavaScript. Can you set it to 'none'?`, finding_1.Severity.HIGH, csp_1.Directive.OBJECT_SRC)];\n    }\n    __name(checkMissingObjectSrcDirective, \"checkMissingObjectSrcDirective\");\n    exports2.checkMissingObjectSrcDirective = checkMissingObjectSrcDirective;\n    function checkMissingScriptSrcDirective(parsedCsp) {\n      if (csp_1.Directive.SCRIPT_SRC in parsedCsp.directives || csp_1.Directive.DEFAULT_SRC in parsedCsp.directives) {\n        return [];\n      }\n      return [new finding_1.Finding(finding_1.Type.MISSING_DIRECTIVES, \"script-src directive is missing.\", finding_1.Severity.HIGH, csp_1.Directive.SCRIPT_SRC)];\n    }\n    __name(checkMissingScriptSrcDirective, \"checkMissingScriptSrcDirective\");\n    exports2.checkMissingScriptSrcDirective = checkMissingScriptSrcDirective;\n    function checkMissingBaseUriDirective(parsedCsp) {\n      return checkMultipleMissingBaseUriDirective([parsedCsp]);\n    }\n    __name(checkMissingBaseUriDirective, \"checkMissingBaseUriDirective\");\n    exports2.checkMissingBaseUriDirective = checkMissingBaseUriDirective;\n    function checkMultipleMissingBaseUriDirective(parsedCsps) {\n      const needsBaseUri = /* @__PURE__ */ __name((csp2) => csp2.policyHasScriptNonces() || csp2.policyHasScriptHashes() && csp2.policyHasStrictDynamic(), \"needsBaseUri\");\n      const hasBaseUri = /* @__PURE__ */ __name((csp2) => csp_1.Directive.BASE_URI in csp2.directives, \"hasBaseUri\");\n      if (parsedCsps.some(needsBaseUri) && !parsedCsps.some(hasBaseUri)) {\n        const description = `Missing base-uri allows the injection of base tags. They can be used to set the base URL for all relative (script) URLs to an attacker controlled domain. Can you set it to 'none' or 'self'?`;\n        return [new finding_1.Finding(finding_1.Type.MISSING_DIRECTIVES, description, finding_1.Severity.HIGH, csp_1.Directive.BASE_URI)];\n      }\n      return [];\n    }\n    __name(checkMultipleMissingBaseUriDirective, \"checkMultipleMissingBaseUriDirective\");\n    exports2.checkMultipleMissingBaseUriDirective = checkMultipleMissingBaseUriDirective;\n    function checkMissingDirectives(parsedCsp) {\n      return [\n        ...checkMissingObjectSrcDirective(parsedCsp),\n        ...checkMissingScriptSrcDirective(parsedCsp),\n        ...checkMissingBaseUriDirective(parsedCsp)\n      ];\n    }\n    __name(checkMissingDirectives, \"checkMissingDirectives\");\n    exports2.checkMissingDirectives = checkMissingDirectives;\n    function checkScriptAllowlistBypass(parsedCsp) {\n      const violations = [];\n      parsedCsp.getEffectiveDirectives([csp_1.Directive.SCRIPT_SRC, csp_1.Directive.SCRIPT_SRC_ELEM]).forEach((effectiveScriptSrcDirective) => {\n        const scriptSrcValues = parsedCsp.directives[effectiveScriptSrcDirective] || [];\n        if (scriptSrcValues.includes(csp_1.Keyword.NONE)) {\n          return;\n        }\n        for (const value of scriptSrcValues) {\n          if (value === csp_1.Keyword.SELF) {\n            violations.push(new finding_1.Finding(finding_1.Type.SCRIPT_ALLOWLIST_BYPASS, `'self' can be problematic if you host JSONP, AngularJS or user uploaded files.`, finding_1.Severity.MEDIUM_MAYBE, effectiveScriptSrcDirective, value));\n            continue;\n          }\n          if (value.startsWith(\"'\")) {\n            continue;\n          }\n          if (csp.isUrlScheme(value) || value.indexOf(\".\") === -1) {\n            continue;\n          }\n          const url = \"//\" + utils.getSchemeFreeUrl(value);\n          const angularBypass = utils.matchWildcardUrls(url, angular.URLS);\n          let jsonpBypass = utils.matchWildcardUrls(url, jsonp.URLS);\n          if (jsonpBypass) {\n            const evalRequired = jsonp.NEEDS_EVAL.includes(jsonpBypass.hostname);\n            const evalPresent = scriptSrcValues.includes(csp_1.Keyword.UNSAFE_EVAL);\n            if (evalRequired && !evalPresent) {\n              jsonpBypass = null;\n            }\n          }\n          if (jsonpBypass || angularBypass) {\n            let bypassDomain = \"\";\n            let bypassTxt = \"\";\n            if (jsonpBypass) {\n              bypassDomain = jsonpBypass.hostname;\n              bypassTxt = \" JSONP endpoints\";\n            }\n            if (angularBypass) {\n              bypassDomain = angularBypass.hostname;\n              bypassTxt += bypassTxt.trim() === \"\" ? \"\" : \" and\";\n              bypassTxt += \" Angular libraries\";\n            }\n            violations.push(new finding_1.Finding(finding_1.Type.SCRIPT_ALLOWLIST_BYPASS, bypassDomain + \" is known to host\" + bypassTxt + \" which allow to bypass this CSP.\", finding_1.Severity.HIGH, effectiveScriptSrcDirective, value));\n          } else {\n            violations.push(new finding_1.Finding(finding_1.Type.SCRIPT_ALLOWLIST_BYPASS, `No bypass found; make sure that this URL doesn't serve JSONP replies or Angular libraries.`, finding_1.Severity.MEDIUM_MAYBE, effectiveScriptSrcDirective, value));\n          }\n        }\n      });\n      return violations;\n    }\n    __name(checkScriptAllowlistBypass, \"checkScriptAllowlistBypass\");\n    exports2.checkScriptAllowlistBypass = checkScriptAllowlistBypass;\n    function checkFlashObjectAllowlistBypass(parsedCsp) {\n      const violations = [];\n      const effectiveObjectSrcDirective = parsedCsp.getEffectiveDirective(csp_1.Directive.OBJECT_SRC);\n      const objectSrcValues = parsedCsp.directives[effectiveObjectSrcDirective] || [];\n      const pluginTypes = parsedCsp.directives[csp_1.Directive.PLUGIN_TYPES];\n      if (pluginTypes && !pluginTypes.includes(\"application/x-shockwave-flash\")) {\n        return [];\n      }\n      for (const value of objectSrcValues) {\n        if (value === csp_1.Keyword.NONE) {\n          return [];\n        }\n        const url = \"//\" + utils.getSchemeFreeUrl(value);\n        const flashBypass = utils.matchWildcardUrls(url, flash.URLS);\n        if (flashBypass) {\n          violations.push(new finding_1.Finding(finding_1.Type.OBJECT_ALLOWLIST_BYPASS, flashBypass.hostname + \" is known to host Flash files which allow to bypass this CSP.\", finding_1.Severity.HIGH, effectiveObjectSrcDirective, value));\n        } else if (effectiveObjectSrcDirective === csp_1.Directive.OBJECT_SRC) {\n          violations.push(new finding_1.Finding(finding_1.Type.OBJECT_ALLOWLIST_BYPASS, `Can you restrict object-src to 'none' only?`, finding_1.Severity.MEDIUM_MAYBE, effectiveObjectSrcDirective, value));\n        }\n      }\n      return violations;\n    }\n    __name(checkFlashObjectAllowlistBypass, \"checkFlashObjectAllowlistBypass\");\n    exports2.checkFlashObjectAllowlistBypass = checkFlashObjectAllowlistBypass;\n    function looksLikeIpAddress(maybeIp) {\n      if (maybeIp.startsWith(\"[\") && maybeIp.endsWith(\"]\")) {\n        return true;\n      }\n      if (/^[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}$/.test(maybeIp)) {\n        return true;\n      }\n      return false;\n    }\n    __name(looksLikeIpAddress, \"looksLikeIpAddress\");\n    exports2.looksLikeIpAddress = looksLikeIpAddress;\n    function checkIpSource(parsedCsp) {\n      const violations = [];\n      const checkIp = /* @__PURE__ */ __name((directive, directiveValues) => {\n        for (const value of directiveValues) {\n          const host = utils.getHostname(value);\n          if (looksLikeIpAddress(host)) {\n            if (host === \"127.0.0.1\") {\n              violations.push(new finding_1.Finding(finding_1.Type.IP_SOURCE, directive + \" directive allows localhost as source. Please make sure to remove this in production environments.\", finding_1.Severity.INFO, directive, value));\n            } else {\n              violations.push(new finding_1.Finding(finding_1.Type.IP_SOURCE, directive + \" directive has an IP-Address as source: \" + host + \" (will be ignored by browsers!). \", finding_1.Severity.INFO, directive, value));\n            }\n          }\n        }\n      }, \"checkIp\");\n      utils.applyCheckFunktionToDirectives(parsedCsp, checkIp);\n      return violations;\n    }\n    __name(checkIpSource, \"checkIpSource\");\n    exports2.checkIpSource = checkIpSource;\n    function checkDeprecatedDirective(parsedCsp) {\n      const violations = [];\n      if (csp_1.Directive.REFLECTED_XSS in parsedCsp.directives) {\n        violations.push(new finding_1.Finding(finding_1.Type.DEPRECATED_DIRECTIVE, \"reflected-xss is deprecated since CSP2. Please, use the X-XSS-Protection header instead.\", finding_1.Severity.INFO, csp_1.Directive.REFLECTED_XSS));\n      }\n      if (csp_1.Directive.REFERRER in parsedCsp.directives) {\n        violations.push(new finding_1.Finding(finding_1.Type.DEPRECATED_DIRECTIVE, \"referrer is deprecated since CSP2. Please, use the Referrer-Policy header instead.\", finding_1.Severity.INFO, csp_1.Directive.REFERRER));\n      }\n      if (csp_1.Directive.DISOWN_OPENER in parsedCsp.directives) {\n        violations.push(new finding_1.Finding(finding_1.Type.DEPRECATED_DIRECTIVE, \"disown-opener is deprecated since CSP3. Please, use the Cross Origin Opener Policy header instead.\", finding_1.Severity.INFO, csp_1.Directive.DISOWN_OPENER));\n      }\n      if (csp_1.Directive.PREFETCH_SRC in parsedCsp.directives) {\n        violations.push(new finding_1.Finding(finding_1.Type.DEPRECATED_DIRECTIVE, \"prefetch-src is deprecated since CSP3. Be aware that this feature may cease to work at any time.\", finding_1.Severity.INFO, csp_1.Directive.PREFETCH_SRC));\n      }\n      return violations;\n    }\n    __name(checkDeprecatedDirective, \"checkDeprecatedDirective\");\n    exports2.checkDeprecatedDirective = checkDeprecatedDirective;\n    function checkNonceLength(parsedCsp) {\n      const noncePattern = new RegExp(\"^'nonce-(.+)'$\");\n      const violations = [];\n      utils.applyCheckFunktionToDirectives(parsedCsp, (directive, directiveValues) => {\n        for (const value of directiveValues) {\n          const match = value.match(noncePattern);\n          if (!match) {\n            continue;\n          }\n          const nonceValue = match[1];\n          if (nonceValue.length < 8) {\n            violations.push(new finding_1.Finding(finding_1.Type.NONCE_LENGTH, \"Nonces should be at least 8 characters long.\", finding_1.Severity.MEDIUM, directive, value));\n          }\n          if (!csp.isNonce(value, true)) {\n            violations.push(new finding_1.Finding(finding_1.Type.NONCE_CHARSET, \"Nonces should only use the base64 charset.\", finding_1.Severity.INFO, directive, value));\n          }\n        }\n      });\n      return violations;\n    }\n    __name(checkNonceLength, \"checkNonceLength\");\n    exports2.checkNonceLength = checkNonceLength;\n    function checkSrcHttp(parsedCsp) {\n      const violations = [];\n      utils.applyCheckFunktionToDirectives(parsedCsp, (directive, directiveValues) => {\n        for (const value of directiveValues) {\n          const description = directive === csp_1.Directive.REPORT_URI ? \"Use HTTPS to send violation reports securely.\" : \"Allow only resources downloaded over HTTPS.\";\n          if (value.startsWith(\"http://\")) {\n            violations.push(new finding_1.Finding(finding_1.Type.SRC_HTTP, description, finding_1.Severity.MEDIUM, directive, value));\n          }\n        }\n      });\n      return violations;\n    }\n    __name(checkSrcHttp, \"checkSrcHttp\");\n    exports2.checkSrcHttp = checkSrcHttp;\n    function checkHasConfiguredReporting(parsedCsp) {\n      const reportUriValues = parsedCsp.directives[csp_1.Directive.REPORT_URI] || [];\n      if (reportUriValues.length > 0) {\n        return [];\n      }\n      const reportToValues = parsedCsp.directives[csp_1.Directive.REPORT_TO] || [];\n      if (reportToValues.length > 0) {\n        return [new finding_1.Finding(finding_1.Type.REPORT_TO_ONLY, `This CSP policy only provides a reporting destination via the 'report-to' directive. This directive is only supported in Chromium-based browsers so it is recommended to also use a 'report-uri' directive.`, finding_1.Severity.INFO, csp_1.Directive.REPORT_TO)];\n      }\n      return [new finding_1.Finding(finding_1.Type.REPORTING_DESTINATION_MISSING, \"This CSP policy does not configure a reporting destination. This makes it difficult to maintain the CSP policy over time and monitor for any breakages.\", finding_1.Severity.INFO, csp_1.Directive.REPORT_URI)];\n    }\n    __name(checkHasConfiguredReporting, \"checkHasConfiguredReporting\");\n    exports2.checkHasConfiguredReporting = checkHasConfiguredReporting;\n  }\n});\n\n// node_modules/csp_evaluator/dist/checks/strictcsp_checks.js\nvar require_strictcsp_checks = __commonJS({\n  \"node_modules/csp_evaluator/dist/checks/strictcsp_checks.js\"(exports2) {\n    \"use strict\";\n    init_process_global();\n    var __createBinding4 = exports2 && exports2.__createBinding || (Object.create ? (function(o, m, k, k2) {\n      if (k2 === void 0) k2 = k;\n      Object.defineProperty(o, k2, { enumerable: true, get: /* @__PURE__ */ __name(function() {\n        return m[k];\n      }, \"get\") });\n    }) : (function(o, m, k, k2) {\n      if (k2 === void 0) k2 = k;\n      o[k2] = m[k];\n    }));\n    var __setModuleDefault4 = exports2 && exports2.__setModuleDefault || (Object.create ? (function(o, v) {\n      Object.defineProperty(o, \"default\", { enumerable: true, value: v });\n    }) : function(o, v) {\n      o[\"default\"] = v;\n    });\n    var __importStar4 = exports2 && exports2.__importStar || function(mod2) {\n      if (mod2 && mod2.__esModule) return mod2;\n      var result = {};\n      if (mod2 != null) {\n        for (var k in mod2) if (k !== \"default\" && Object.prototype.hasOwnProperty.call(mod2, k)) __createBinding4(result, mod2, k);\n      }\n      __setModuleDefault4(result, mod2);\n      return result;\n    };\n    Object.defineProperty(exports2, \"__esModule\", { value: true });\n    exports2.checkRequiresTrustedTypesForScripts = exports2.checkAllowlistFallback = exports2.checkUnsafeInlineFallback = exports2.checkStrictDynamicNotStandalone = exports2.checkStrictDynamic = void 0;\n    var csp = __importStar4(require_csp());\n    var csp_1 = require_csp();\n    var finding_1 = require_finding();\n    function checkStrictDynamic(parsedCsp) {\n      const directiveName = parsedCsp.getEffectiveDirective(csp.Directive.SCRIPT_SRC);\n      const values = parsedCsp.directives[directiveName] || [];\n      const schemeOrHostPresent = values.some((v) => !v.startsWith(\"'\"));\n      if (schemeOrHostPresent && !values.includes(csp_1.Keyword.STRICT_DYNAMIC)) {\n        return [new finding_1.Finding(finding_1.Type.STRICT_DYNAMIC, \"Host allowlists can frequently be bypassed. Consider using 'strict-dynamic' in combination with CSP nonces or hashes.\", finding_1.Severity.STRICT_CSP, directiveName)];\n      }\n      return [];\n    }\n    __name(checkStrictDynamic, \"checkStrictDynamic\");\n    exports2.checkStrictDynamic = checkStrictDynamic;\n    function checkStrictDynamicNotStandalone(parsedCsp) {\n      const directiveName = parsedCsp.getEffectiveDirective(csp.Directive.SCRIPT_SRC);\n      const values = parsedCsp.directives[directiveName] || [];\n      if (values.includes(csp_1.Keyword.STRICT_DYNAMIC) && (!parsedCsp.policyHasScriptNonces() && !parsedCsp.policyHasScriptHashes())) {\n        return [new finding_1.Finding(finding_1.Type.STRICT_DYNAMIC_NOT_STANDALONE, \"'strict-dynamic' without a CSP nonce/hash will block all scripts.\", finding_1.Severity.INFO, directiveName)];\n      }\n      return [];\n    }\n    __name(checkStrictDynamicNotStandalone, \"checkStrictDynamicNotStandalone\");\n    exports2.checkStrictDynamicNotStandalone = checkStrictDynamicNotStandalone;\n    function checkUnsafeInlineFallback(parsedCsp) {\n      if (!parsedCsp.policyHasScriptNonces() && !parsedCsp.policyHasScriptHashes()) {\n        return [];\n      }\n      const directiveName = parsedCsp.getEffectiveDirective(csp.Directive.SCRIPT_SRC);\n      const values = parsedCsp.directives[directiveName] || [];\n      if (!values.includes(csp_1.Keyword.UNSAFE_INLINE)) {\n        return [new finding_1.Finding(finding_1.Type.UNSAFE_INLINE_FALLBACK, \"Consider adding 'unsafe-inline' (ignored by browsers supporting nonces/hashes) to be backward compatible with older browsers.\", finding_1.Severity.STRICT_CSP, directiveName)];\n      }\n      return [];\n    }\n    __name(checkUnsafeInlineFallback, \"checkUnsafeInlineFallback\");\n    exports2.checkUnsafeInlineFallback = checkUnsafeInlineFallback;\n    function checkAllowlistFallback(parsedCsp) {\n      const directiveName = parsedCsp.getEffectiveDirective(csp.Directive.SCRIPT_SRC);\n      const values = parsedCsp.directives[directiveName] || [];\n      if (!values.includes(csp_1.Keyword.STRICT_DYNAMIC)) {\n        return [];\n      }\n      if (!values.some((v) => [\"http:\", \"https:\", \"*\"].includes(v) || v.includes(\".\"))) {\n        return [new finding_1.Finding(finding_1.Type.ALLOWLIST_FALLBACK, \"Consider adding https: and http: url schemes (ignored by browsers supporting 'strict-dynamic') to be backward compatible with older browsers.\", finding_1.Severity.STRICT_CSP, directiveName)];\n      }\n      return [];\n    }\n    __name(checkAllowlistFallback, \"checkAllowlistFallback\");\n    exports2.checkAllowlistFallback = checkAllowlistFallback;\n    function checkRequiresTrustedTypesForScripts(parsedCsp) {\n      const directiveName = parsedCsp.getEffectiveDirective(csp.Directive.REQUIRE_TRUSTED_TYPES_FOR);\n      const values = parsedCsp.directives[directiveName] || [];\n      if (!values.includes(csp.TrustedTypesSink.SCRIPT)) {\n        return [new finding_1.Finding(finding_1.Type.REQUIRE_TRUSTED_TYPES_FOR_SCRIPTS, `Consider requiring Trusted Types for scripts to lock down DOM XSS injection sinks. You can do this by adding \"require-trusted-types-for 'script'\" to your policy.`, finding_1.Severity.INFO, csp.Directive.REQUIRE_TRUSTED_TYPES_FOR)];\n      }\n      return [];\n    }\n    __name(checkRequiresTrustedTypesForScripts, \"checkRequiresTrustedTypesForScripts\");\n    exports2.checkRequiresTrustedTypesForScripts = checkRequiresTrustedTypesForScripts;\n  }\n});\n\n// node_modules/csp_evaluator/dist/lighthouse/lighthouse_checks.js\nvar require_lighthouse_checks = __commonJS({\n  \"node_modules/csp_evaluator/dist/lighthouse/lighthouse_checks.js\"(exports2) {\n    \"use strict\";\n    init_process_global();\n    Object.defineProperty(exports2, \"__esModule\", { value: true });\n    exports2.evaluateForSyntaxErrors = exports2.evaluateForWarnings = exports2.evaluateForFailure = void 0;\n    var parser_checks_1 = require_parser_checks();\n    var security_checks_1 = require_security_checks();\n    var strictcsp_checks_1 = require_strictcsp_checks();\n    var csp_1 = require_csp();\n    function arrayContains(arr, elem) {\n      return arr.some((e) => e.equals(elem));\n    }\n    __name(arrayContains, \"arrayContains\");\n    function setIntersection(sets) {\n      const intersection = [];\n      if (sets.length === 0) {\n        return intersection;\n      }\n      const firstSet = sets[0];\n      for (const elem of firstSet) {\n        if (sets.every((set) => arrayContains(set, elem))) {\n          intersection.push(elem);\n        }\n      }\n      return intersection;\n    }\n    __name(setIntersection, \"setIntersection\");\n    function setUnion(sets) {\n      const union = [];\n      for (const set of sets) {\n        for (const elem of set) {\n          if (!arrayContains(union, elem)) {\n            union.push(elem);\n          }\n        }\n      }\n      return union;\n    }\n    __name(setUnion, \"setUnion\");\n    function atLeastOnePasses(parsedCsps, checker) {\n      const findings = [];\n      for (const parsedCsp of parsedCsps) {\n        findings.push(checker(parsedCsp));\n      }\n      return setIntersection(findings);\n    }\n    __name(atLeastOnePasses, \"atLeastOnePasses\");\n    function atLeastOneFails(parsedCsps, checker) {\n      const findings = [];\n      for (const parsedCsp of parsedCsps) {\n        findings.push(checker(parsedCsp));\n      }\n      return setUnion(findings);\n    }\n    __name(atLeastOneFails, \"atLeastOneFails\");\n    function evaluateForFailure2(parsedCsps) {\n      const targetsXssFindings = [\n        ...atLeastOnePasses(parsedCsps, security_checks_1.checkMissingScriptSrcDirective),\n        ...atLeastOnePasses(parsedCsps, security_checks_1.checkMissingObjectSrcDirective),\n        ...security_checks_1.checkMultipleMissingBaseUriDirective(parsedCsps)\n      ];\n      const effectiveCsps = parsedCsps.map((csp) => csp.getEffectiveCsp(csp_1.Version.CSP3));\n      const effectiveCspsWithScript = effectiveCsps.filter((csp) => {\n        const directiveName = csp.getEffectiveDirective(csp_1.Directive.SCRIPT_SRC);\n        return csp.directives[directiveName];\n      });\n      const robust = [\n        ...atLeastOnePasses(effectiveCspsWithScript, strictcsp_checks_1.checkStrictDynamic),\n        ...atLeastOnePasses(effectiveCspsWithScript, security_checks_1.checkScriptUnsafeInline),\n        ...atLeastOnePasses(effectiveCsps, security_checks_1.checkWildcards),\n        ...atLeastOnePasses(effectiveCsps, security_checks_1.checkPlainUrlSchemes)\n      ];\n      return [...targetsXssFindings, ...robust];\n    }\n    __name(evaluateForFailure2, \"evaluateForFailure\");\n    exports2.evaluateForFailure = evaluateForFailure2;\n    function evaluateForWarnings2(parsedCsps) {\n      return [\n        ...atLeastOneFails(parsedCsps, strictcsp_checks_1.checkUnsafeInlineFallback),\n        ...atLeastOneFails(parsedCsps, strictcsp_checks_1.checkAllowlistFallback)\n      ];\n    }\n    __name(evaluateForWarnings2, \"evaluateForWarnings\");\n    exports2.evaluateForWarnings = evaluateForWarnings2;\n    function evaluateForSyntaxErrors2(parsedCsps) {\n      const allFindings = [];\n      for (const csp of parsedCsps) {\n        const findings = [\n          ...security_checks_1.checkNonceLength(csp),\n          ...parser_checks_1.checkUnknownDirective(csp),\n          ...security_checks_1.checkDeprecatedDirective(csp),\n          ...parser_checks_1.checkMissingSemicolon(csp),\n          ...parser_checks_1.checkInvalidKeyword(csp)\n        ];\n        allFindings.push(findings);\n      }\n      return allFindings;\n    }\n    __name(evaluateForSyntaxErrors2, \"evaluateForSyntaxErrors\");\n    exports2.evaluateForSyntaxErrors = evaluateForSyntaxErrors2;\n  }\n});\n\n// node_modules/csp_evaluator/dist/parser.js\nvar require_parser2 = __commonJS({\n  \"node_modules/csp_evaluator/dist/parser.js\"(exports2) {\n    \"use strict\";\n    init_process_global();\n    var __createBinding4 = exports2 && exports2.__createBinding || (Object.create ? (function(o, m, k, k2) {\n      if (k2 === void 0) k2 = k;\n      Object.defineProperty(o, k2, { enumerable: true, get: /* @__PURE__ */ __name(function() {\n        return m[k];\n      }, \"get\") });\n    }) : (function(o, m, k, k2) {\n      if (k2 === void 0) k2 = k;\n      o[k2] = m[k];\n    }));\n    var __setModuleDefault4 = exports2 && exports2.__setModuleDefault || (Object.create ? (function(o, v) {\n      Object.defineProperty(o, \"default\", { enumerable: true, value: v });\n    }) : function(o, v) {\n      o[\"default\"] = v;\n    });\n    var __importStar4 = exports2 && exports2.__importStar || function(mod2) {\n      if (mod2 && mod2.__esModule) return mod2;\n      var result = {};\n      if (mod2 != null) {\n        for (var k in mod2) if (k !== \"default\" && Object.prototype.hasOwnProperty.call(mod2, k)) __createBinding4(result, mod2, k);\n      }\n      __setModuleDefault4(result, mod2);\n      return result;\n    };\n    Object.defineProperty(exports2, \"__esModule\", { value: true });\n    exports2.TEST_ONLY = exports2.CspParser = void 0;\n    var csp = __importStar4(require_csp());\n    var CspParser2 = class {\n      static {\n        __name(this, \"CspParser\");\n      }\n      constructor(unparsedCsp) {\n        this.csp = new csp.Csp();\n        this.parse(unparsedCsp);\n      }\n      parse(unparsedCsp) {\n        this.csp = new csp.Csp();\n        const directiveTokens = unparsedCsp.split(\";\");\n        for (let i = 0; i < directiveTokens.length; i++) {\n          const directiveToken = directiveTokens[i].trim();\n          const directiveParts = directiveToken.match(/\\S+/g);\n          if (Array.isArray(directiveParts)) {\n            const directiveName = directiveParts[0].toLowerCase();\n            if (directiveName in this.csp.directives) {\n              continue;\n            }\n            if (!csp.isDirective(directiveName)) {\n            }\n            const directiveValues = [];\n            for (let directiveValue, j = 1; directiveValue = directiveParts[j]; j++) {\n              directiveValue = normalizeDirectiveValue(directiveValue);\n              if (!directiveValues.includes(directiveValue)) {\n                directiveValues.push(directiveValue);\n              }\n            }\n            this.csp.directives[directiveName] = directiveValues;\n          }\n        }\n        return this.csp;\n      }\n    };\n    exports2.CspParser = CspParser2;\n    function normalizeDirectiveValue(directiveValue) {\n      directiveValue = directiveValue.trim();\n      const directiveValueLower = directiveValue.toLowerCase();\n      if (csp.isKeyword(directiveValueLower) || csp.isUrlScheme(directiveValue)) {\n        return directiveValueLower;\n      }\n      return directiveValue;\n    }\n    __name(normalizeDirectiveValue, \"normalizeDirectiveValue\");\n    exports2.TEST_ONLY = { normalizeDirectiveValue };\n  }\n});\n\n// core/lib/csp-evaluator.js\nfunction getTranslatedDescription(finding) {\n  let result = FINDING_TO_UI_STRING[finding.type];\n  if (!result) {\n    lighthouse_logger_default.warn(\"CSP Evaluator\", `No translation found for description: ${finding.description}`);\n    return finding.description;\n  }\n  if (isIcuMessage(result)) return result;\n  if (typeof result === \"string\") return str_69(result, { keyword: finding.value || \"\" });\n  result = result[finding.directive];\n  if (!result) {\n    lighthouse_logger_default.warn(\"CSP Evaluator\", `No translation found for description: ${finding.description}`);\n    return finding.description;\n  }\n  return result;\n}\nfunction parseCsp(rawCsp) {\n  return new import_parser.CspParser(rawCsp).csp;\n}\nfunction evaluateRawCspsForXss(rawCsps) {\n  const parsedCsps = rawCsps.map(parseCsp);\n  const bypasses = (0, import_lighthouse_checks.evaluateForFailure)(parsedCsps);\n  const warnings = (0, import_lighthouse_checks.evaluateForWarnings)(parsedCsps);\n  const syntax = (0, import_lighthouse_checks.evaluateForSyntaxErrors)(parsedCsps);\n  return { bypasses, warnings, syntax };\n}\nvar import_lighthouse_checks, import_finding, import_parser, import_csp, UIStrings88, str_69, FINDING_TO_UI_STRING;\nvar init_csp_evaluator = __esm({\n  \"core/lib/csp-evaluator.js\"() {\n    \"use strict\";\n    init_process_global();\n    import_lighthouse_checks = __toESM(require_lighthouse_checks(), 1);\n    import_finding = __toESM(require_finding(), 1);\n    import_parser = __toESM(require_parser2(), 1);\n    import_csp = __toESM(require_csp(), 1);\n    init_lighthouse_logger();\n    init_i18n();\n    init_format();\n    /**\n     * @license\n     * Copyright 2021 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    UIStrings88 = {\n      /** Message shown when a CSP does not have a base-uri directive. Shown in a table with a list of other CSP vulnerabilities and suggestions. \"CSP\" stands for \"Content Security Policy\". \"base-uri\", \"'none'\", and \"'self'\" do not need to be translated. */\n      missingBaseUri: \"Missing `base-uri` allows injected `<base>` tags to set the base URL for all relative URLs (e.g. scripts) to an attacker controlled domain. Consider setting `base-uri` to `'none'` or `'self'`.\",\n      /** Message shown when a CSP does not have a script-src directive. Shown in a table with a list of other CSP vulnerabilities and suggestions. \"CSP\" stands for \"Content Security Policy\". \"script-src\" does not need to be translated. */\n      missingScriptSrc: \"`script-src` directive is missing. This can allow the execution of unsafe scripts.\",\n      /** Message shown when a CSP does not have a script-src directive. Shown in a table with a list of other CSP vulnerabilities and suggestions. \"CSP\" stands for \"Content Security Policy\". \"object-src\" and \"'none'\" do not need to be translated. */\n      missingObjectSrc: \"Missing `object-src` allows the injection of plugins that execute unsafe scripts. Consider setting `object-src` to `'none'` if you can.\",\n      /** Message shown when a CSP uses a domain allowlist to filter out malicious scripts. Shown in a table with a list of other CSP vulnerabilities and suggestions. \"CSP\" stands for \"Content Security Policy\". \"CSP\", \"'strict-dynamic'\", \"nonces\", and \"hashes\" do not need to be translated. \"allowlists\" can be interpreted as \"whitelist\". */\n      strictDynamic: \"Host allowlists can frequently be bypassed. Consider using CSP nonces or hashes instead, along with `'strict-dynamic'` if necessary.\",\n      /** Message shown when a CSP allows inline scripts to be run in the page. Shown in a table with a list of other CSP vulnerabilities and suggestions. \"CSP\" stands for \"Content Security Policy\". \"CSP\", \"'unsafe-inline'\", \"nonces\", and \"hashes\" do not need to be translated. */\n      unsafeInline: \"`'unsafe-inline'` allows the execution of unsafe in-page scripts and event handlers. Consider using CSP nonces or hashes to allow scripts individually.\",\n      /** Message shown when a CSP is not backwards compatible with browsers that do not support CSP nonces/hashes. Shown in a table with a list of other CSP vulnerabilities and suggestions. \"CSP\" stands for \"Content Security Policy\". \"'unsafe-inline'\", \"nonces\", and \"hashes\" do not need to be translated. */\n      unsafeInlineFallback: \"Consider adding `'unsafe-inline'` (ignored by browsers supporting nonces/hashes) to be backward compatible with older browsers.\",\n      /** Message shown when a CSP is not backwards compatible with browsers that do not support the 'strict-dynamic' keyword. Shown in a table with a list of other CSP vulnerabilities and suggestions. \"CSP\" stands for \"Content Security Policy\". \"http:\", \"https:\", and \"'strict-dynamic'\" do not need to be translated. */\n      allowlistFallback: \"Consider adding https: and http: URL schemes (ignored by browsers supporting `'strict-dynamic'`) to be backward compatible with older browsers.\",\n      /** Message shown when a CSP only provides a reporting destination through the report-to directive. Shown in a table with a list of other CSP vulnerabilities and suggestions. \"CSP\" stands for \"Content Security Policy\". \"report-to\", \"report-uri\", and \"Chromium\" do not need to be translated. */\n      reportToOnly: \"The reporting destination is only configured via the report-to directive. This directive is only supported in Chromium-based browsers so it is recommended to also use a `report-uri` directive.\",\n      /** Message shown when a CSP does not provide a reporting destination. Shown in a table with a list of other CSP vulnerabilities and suggestions. \"CSP\" stands for \"Content Security Policy\". \"CSP\" does not need to be translated. */\n      reportingDestinationMissing: \"No CSP configures a reporting destination. This makes it difficult to maintain the CSP over time and monitor for any breakages.\",\n      /** Message shown when a CSP nonce has less than 8 characters. Shown in a table with a list of other CSP vulnerabilities and suggestions. \"CSP\" stands for \"Content Security Policy\". \"Nonces\" does not need to be translated. */\n      nonceLength: \"Nonces should be at least 8 characters long.\",\n      /** Message shown when a CSP nonce does not use teh base64 charset. Shown in a table with a list of other CSP vulnerabilities and suggestions. \"CSP\" stands for \"Content Security Policy\". \"Nonces\" and \"base84\" do not need to be translated. \"charset\" can be interpreted as \"a set of characters\". */\n      nonceCharset: \"Nonces should use the base64 charset.\",\n      /**\n       * @description Message shown when a CSP is missing a semicolon. Shown in a table with a list of other CSP vulnerabilities and suggestions. \"CSP\" stands for \"Content Security Policy\".\n       * @example {'object-src'} keyword\n       */\n      missingSemicolon: \"Did you forget the semicolon? {keyword} seems to be a directive, not a keyword.\",\n      /** Message shown when a CSP contains an unknown keyword. Shown in a table with a list of other CSP vulnerabilities and suggestions. \"CSP\" stands for \"Content Security Policy\". \"CSP\" does not need to be translated. */\n      unknownDirective: \"Unknown CSP directive.\",\n      /**\n       * @description Message shown when a CSP contains an invalid keyword. Shown in a table with a list of other CSP vulnerabilities and suggestions. \"CSP\" stands for \"Content Security Policy\".\n       * @example {'invalid-keyword'} keyword\n       */\n      unknownKeyword: \"{keyword} seems to be an invalid keyword.\",\n      /** Message shown when a CSP uses the deprecated reflected-xss directive. Shown in a table with a list of other CSP vulnerabilities and suggestions. \"CSP\" stands for \"Content Security Policy\". \"reflected-xss\", \"CSP2\" and \"X-XSS-Protection\" do not need to be translated. */\n      deprecatedReflectedXSS: \"`reflected-xss` is deprecated since CSP2. Please, use the X-XSS-Protection header instead.\",\n      /** Message shown when a CSP uses the deprecated referrer directive. Shown in a table with a list of other CSP vulnerabilities and suggestions. \"CSP\" stands for \"Content Security Policy\". \"referrer\", \"CSP2\" and \"Referrer-Policy\" do not need to be translated. */\n      deprecatedReferrer: \"`referrer` is deprecated since CSP2. Please, use the Referrer-Policy header instead.\",\n      /** Message shown when a CSP uses the deprecated disown-opener directive. Shown in a table with a list of other CSP vulnerabilities and suggestions. \"CSP\" stands for \"Content Security Policy\". \"disown-opener\", \"CSP3\" and \"Cross-Origin-Opener-Policy\" do not need to be translated. */\n      deprecatedDisownOpener: \"`disown-opener` is deprecated since CSP3. Please, use the Cross-Origin-Opener-Policy header instead.\",\n      /**\n       * @description Message shown when a CSP wildcard allows unsafe scripts to be run in the page. Shown in a table with a list of other CSP vulnerabilities and suggestions. \"CSP\" stands for \"Content Security Policy\".\n       *  @example {*} keyword\n       */\n      plainWildcards: \"Avoid using plain wildcards ({keyword}) in this directive. Plain wildcards allow scripts to be sourced from an unsafe domain.\",\n      /**\n       * @description Message shown when a CSP URL scheme allows unsafe scripts to be run in the page. Shown in a table with a list of other CSP vulnerabilities and suggestions. \"CSP\" stands for \"Content Security Policy\".\n       *  @example {https:} keyword\n       */\n      plainUrlScheme: \"Avoid using plain URL schemes ({keyword}) in this directive. Plain URL schemes allow scripts to be sourced from an unsafe domain.\"\n    };\n    str_69 = createIcuMessageFn({ url: \"core/lib/csp-evaluator.js\" }.url, UIStrings88);\n    FINDING_TO_UI_STRING = {\n      [import_finding.Type.MISSING_SEMICOLON]: UIStrings88.missingSemicolon,\n      [import_finding.Type.UNKNOWN_DIRECTIVE]: str_69(UIStrings88.unknownDirective),\n      [import_finding.Type.INVALID_KEYWORD]: UIStrings88.unknownKeyword,\n      [import_finding.Type.MISSING_DIRECTIVES]: {\n        [import_csp.Directive.BASE_URI]: str_69(UIStrings88.missingBaseUri),\n        [import_csp.Directive.SCRIPT_SRC]: str_69(UIStrings88.missingScriptSrc),\n        [import_csp.Directive.OBJECT_SRC]: str_69(UIStrings88.missingObjectSrc)\n      },\n      [import_finding.Type.SCRIPT_UNSAFE_INLINE]: str_69(UIStrings88.unsafeInline),\n      [import_finding.Type.PLAIN_WILDCARD]: UIStrings88.plainWildcards,\n      [import_finding.Type.PLAIN_URL_SCHEMES]: UIStrings88.plainUrlScheme,\n      [import_finding.Type.NONCE_LENGTH]: str_69(UIStrings88.nonceLength),\n      [import_finding.Type.NONCE_CHARSET]: str_69(UIStrings88.nonceCharset),\n      [import_finding.Type.DEPRECATED_DIRECTIVE]: {\n        [import_csp.Directive.REFLECTED_XSS]: str_69(UIStrings88.deprecatedReflectedXSS),\n        [import_csp.Directive.REFERRER]: str_69(UIStrings88.deprecatedReferrer),\n        [import_csp.Directive.DISOWN_OPENER]: str_69(UIStrings88.deprecatedDisownOpener)\n      },\n      [import_finding.Type.STRICT_DYNAMIC]: str_69(UIStrings88.strictDynamic),\n      [import_finding.Type.UNSAFE_INLINE_FALLBACK]: str_69(UIStrings88.unsafeInlineFallback),\n      [import_finding.Type.ALLOWLIST_FALLBACK]: str_69(UIStrings88.allowlistFallback),\n      [import_finding.Type.REPORTING_DESTINATION_MISSING]: str_69(UIStrings88.reportingDestinationMissing),\n      [import_finding.Type.REPORT_TO_ONLY]: str_69(UIStrings88.reportToOnly)\n    };\n    __name(getTranslatedDescription, \"getTranslatedDescription\");\n    __name(parseCsp, \"parseCsp\");\n    __name(evaluateRawCspsForXss, \"evaluateRawCspsForXss\");\n  }\n});\n\n// core/audits/csp-xss.js\nvar csp_xss_exports = {};\n__export(csp_xss_exports, {\n  UIStrings: () => UIStrings89,\n  default: () => csp_xss_default\n});\nvar UIStrings89, str_70, CspXss, csp_xss_default;\nvar init_csp_xss = __esm({\n  \"core/audits/csp-xss.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_audit();\n    init_main_resource();\n    init_i18n();\n    init_csp_evaluator();\n    /**\n     * @license\n     * Copyright 2021 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    UIStrings89 = {\n      /** Title of a Lighthouse audit that evaluates the security of a page's CSP. \"CSP\" stands for \"Content Security Policy\". \"XSS\" stands for \"Cross Site Scripting\". \"CSP\" and \"XSS\" do not need to be translated. */\n      title: \"Ensure CSP is effective against XSS attacks\",\n      /** Description of a Lighthouse audit that evaluates the security of a page's CSP. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. \"CSP\" stands for \"Content Security Policy\". \"XSS\" stands for \"Cross Site Scripting\". \"CSP\" and \"XSS\" do not need to be translated. */\n      description: \"A strong Content Security Policy (CSP) significantly reduces the risk of cross-site scripting (XSS) attacks. [Learn how to use a CSP to prevent XSS](https://developer.chrome.com/docs/lighthouse/best-practices/csp-xss/)\",\n      /** Summary text for the results of a Lighthouse audit that evaluates the security of a page's CSP. This is displayed if no CSP is being enforced. \"CSP\" stands for \"Content Security Policy\". \"CSP\" does not need to be translated. */\n      noCsp: \"No CSP found in enforcement mode\",\n      /** Message shown when one or more CSPs are defined in a <meta> tag. Shown in a table with a list of other CSP bypasses and warnings. \"CSP\" stands for \"Content Security Policy\". \"CSP\" and \"HTTP\" do not need to be translated. */\n      metaTagMessage: \"The page contains a CSP defined in a `<meta>` tag. Consider moving the CSP to an HTTP header or defining another strict CSP in an HTTP header.\",\n      /** Label for a column in a data table; entries will be a directive of a CSP. \"CSP\" stands for \"Content Security Policy\". */\n      columnDirective: \"Directive\",\n      /** Label for a column in a data table; entries will be the severity of an issue with the CSP. \"CSP\" stands for \"Content Security Policy\". */\n      columnSeverity: \"Severity\",\n      /** Table item value calling out the presence of a syntax error. */\n      itemSeveritySyntax: \"Syntax\"\n    };\n    str_70 = createIcuMessageFn({ url: \"core/audits/csp-xss.js\" }.url, UIStrings89);\n    CspXss = class extends Audit {\n      static {\n        __name(this, \"CspXss\");\n      }\n      /**\n       * @return {LH.Audit.Meta}\n       */\n      static get meta() {\n        return {\n          id: \"csp-xss\",\n          scoreDisplayMode: Audit.SCORING_MODES.INFORMATIVE,\n          title: str_70(UIStrings89.title),\n          description: str_70(UIStrings89.description),\n          requiredArtifacts: [\"DevtoolsLog\", \"MetaElements\", \"URL\"]\n        };\n      }\n      /**\n       * @param {LH.Artifacts} artifacts\n       * @param {LH.Audit.Context} context\n       * @return {Promise<{cspHeaders: string[], cspMetaTags: string[]}>}\n       */\n      static async getRawCsps(artifacts, context) {\n        const devtoolsLog = artifacts.DevtoolsLog;\n        const mainResource = await MainResourceComputed.request({ devtoolsLog, URL: artifacts.URL }, context);\n        const cspMetaTags = artifacts.MetaElements.filter((m) => {\n          return m.httpEquiv && m.httpEquiv.toLowerCase() === \"content-security-policy\";\n        }).flatMap((m) => (m.content || \"\").split(\",\")).filter((rawCsp) => rawCsp.replace(/\\s/g, \"\"));\n        const cspHeaders = mainResource.responseHeaders.filter((h) => {\n          return h.name.toLowerCase() === \"content-security-policy\";\n        }).flatMap((h) => h.value.split(\",\")).filter((rawCsp) => rawCsp.replace(/\\s/g, \"\"));\n        return { cspHeaders, cspMetaTags };\n      }\n      /**\n       * @param {Finding} finding\n       * @param {LH.IcuMessage=} severity\n       * @return {LH.Audit.Details.TableItem}\n       */\n      static findingToTableItem(finding, severity) {\n        return {\n          directive: finding.directive,\n          description: getTranslatedDescription(finding),\n          severity\n        };\n      }\n      /**\n       * @param {Finding[][]} syntaxFindings\n       * @param {string[]} rawCsps\n       * @return {LH.Audit.Details.TableItem[]}\n       */\n      static constructSyntaxResults(syntaxFindings, rawCsps) {\n        const results = [];\n        for (let i = 0; i < syntaxFindings.length; ++i) {\n          const items = syntaxFindings[i].map((f) => this.findingToTableItem(f));\n          if (!items.length) continue;\n          results.push({\n            severity: str_70(UIStrings89.itemSeveritySyntax),\n            description: {\n              type: \"code\",\n              value: rawCsps[i]\n            },\n            subItems: {\n              type: \"subitems\",\n              items\n            }\n          });\n        }\n        return results;\n      }\n      /**\n       * @param {string[]} cspHeaders\n       * @param {string[]} cspMetaTags\n       * @return {{score: number, results: LH.Audit.Details.TableItem[]}}\n       */\n      static constructResults(cspHeaders, cspMetaTags) {\n        const rawCsps = [...cspHeaders, ...cspMetaTags];\n        if (!rawCsps.length) {\n          return {\n            score: 0,\n            results: [{\n              severity: str_70(UIStrings.itemSeverityHigh),\n              description: str_70(UIStrings89.noCsp),\n              directive: void 0\n            }]\n          };\n        }\n        const { bypasses, warnings, syntax } = evaluateRawCspsForXss(rawCsps);\n        const results = [\n          ...this.constructSyntaxResults(syntax, rawCsps),\n          ...bypasses.map((f) => this.findingToTableItem(f, str_70(UIStrings.itemSeverityHigh))),\n          ...warnings.map((f) => this.findingToTableItem(f, str_70(UIStrings.itemSeverityMedium)))\n        ];\n        const headerOnlyBypasses = evaluateRawCspsForXss(cspHeaders).bypasses;\n        const headerOnlyIsInsecure = headerOnlyBypasses.length > 0 || cspHeaders.length === 0;\n        if (cspMetaTags.length > 0 && headerOnlyIsInsecure) {\n          results.push({\n            severity: str_70(UIStrings.itemSeverityMedium),\n            description: str_70(UIStrings89.metaTagMessage),\n            directive: void 0\n          });\n        }\n        return { score: bypasses.length ? 0 : 1, results };\n      }\n      /**\n       * @param {LH.Artifacts} artifacts\n       * @param {LH.Audit.Context} context\n       * @return {Promise<LH.Audit.Product>}\n       */\n      static async audit(artifacts, context) {\n        const { cspHeaders, cspMetaTags } = await this.getRawCsps(artifacts, context);\n        const { score, results } = this.constructResults(cspHeaders, cspMetaTags);\n        const headings = [\n          /* eslint-disable max-len */\n          { key: \"description\", valueType: \"text\", subItemsHeading: { key: \"description\" }, label: str_70(UIStrings.columnDescription) },\n          { key: \"directive\", valueType: \"code\", subItemsHeading: { key: \"directive\" }, label: str_70(UIStrings89.columnDirective) },\n          { key: \"severity\", valueType: \"text\", subItemsHeading: { key: \"severity\" }, label: str_70(UIStrings89.columnSeverity) }\n          /* eslint-enable max-len */\n        ];\n        const details = Audit.makeTableDetails(headings, results);\n        return {\n          score,\n          notApplicable: !results.length,\n          details\n        };\n      }\n    };\n    csp_xss_default = CspXss;\n  }\n});\n\n// core/computed/js-bundles.js\nfunction computeGeneratedFileSizes2(map, contentLength, content) {\n  const lines = content.split(\"\\n\");\n  const files = {};\n  const totalBytes = contentLength;\n  let unmappedBytes = totalBytes;\n  map.computeLastGeneratedColumns();\n  for (const mapping of map.mappings()) {\n    const source = mapping.sourceURL;\n    const lineNum = mapping.lineNumber;\n    const colNum = mapping.columnNumber;\n    const lastColNum = mapping.lastColumnNumber;\n    if (!source) continue;\n    const line = lines[lineNum];\n    if (line === null || line === void 0) {\n      const errorMessage = `${map.url()} mapping for line out of bounds: ${lineNum + 1}`;\n      lighthouse_logger_default.error(\"JSBundles\", errorMessage);\n      return { errorMessage };\n    }\n    if (colNum > line.length) {\n      const errorMessage = `${map.url()} mapping for column out of bounds: ${lineNum + 1}:${colNum}`;\n      lighthouse_logger_default.error(\"JSBundles\", errorMessage);\n      return { errorMessage };\n    }\n    let mappingLength = 0;\n    if (lastColNum !== void 0) {\n      if (lastColNum > line.length) {\n        const errorMessage = `${map.url()} mapping for last column out of bounds: ${lineNum + 1}:${lastColNum}`;\n        lighthouse_logger_default.error(\"JSBundles\", errorMessage);\n        return { errorMessage };\n      }\n      mappingLength = lastColNum - colNum;\n    } else {\n      mappingLength = line.length - colNum + 1;\n    }\n    files[source] = (files[source] || 0) + mappingLength;\n    unmappedBytes -= mappingLength;\n  }\n  return {\n    files,\n    unmappedBytes,\n    totalBytes\n  };\n}\nvar import_SDK2, JSBundles, JSBundlesComputed;\nvar init_js_bundles = __esm({\n  \"core/computed/js-bundles.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_lighthouse_logger();\n    init_computed_artifact();\n    import_SDK2 = __toESM(require_SDK(), 1);\n    /**\n     * @license\n     * Copyright 2020 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    __name(computeGeneratedFileSizes2, \"computeGeneratedFileSizes\");\n    JSBundles = class {\n      static {\n        __name(this, \"JSBundles\");\n      }\n      /**\n       * @param {Pick<LH.Artifacts, 'SourceMaps'|'Scripts'>} artifacts\n       */\n      static async compute_(artifacts) {\n        const { SourceMaps: SourceMaps2, Scripts: Scripts2 } = artifacts;\n        const bundles = [];\n        for (const SourceMap of SourceMaps2) {\n          if (!SourceMap.map) continue;\n          const { scriptId, map: rawMap } = SourceMap;\n          if (!rawMap.mappings) continue;\n          const script = Scripts2.find((s) => s.scriptId === scriptId);\n          if (!script) continue;\n          const compiledUrl = SourceMap.scriptUrl || \"compiled.js\";\n          const mapUrl = SourceMap.sourceMapUrl || \"compiled.js.map\";\n          const map = new import_SDK2.default.SourceMap(compiledUrl, mapUrl, rawMap);\n          const sizes = computeGeneratedFileSizes2(map, script.length || 0, script.content || \"\");\n          const bundle = {\n            rawMap,\n            script,\n            map,\n            sizes\n          };\n          bundles.push(bundle);\n        }\n        return bundles;\n      }\n    };\n    JSBundlesComputed = makeComputedArtifact(JSBundles, [\"Scripts\", \"SourceMaps\"]);\n  }\n});\n\n// core/lib/deprecations-strings.js\nvar UIStrings90, DEPRECATIONS_METADATA;\nvar init_deprecations_strings = __esm({\n  \"core/lib/deprecations-strings.js\"() {\n    \"use strict\";\n    init_process_global();\n    UIStrings90 = {\n      /**\n       * @description We show this warning when 1) an 'authorization' header is attached to the request by scripts, 2) there is no 'authorization' in the 'access-control-allow-headers' header in the response, and 3) there is a wildcard symbol ('*') in the 'access-control-allow-header' header in the response. This is allowed now, but we're planning to reject such responses and require responses to have an 'access-control-allow-headers' containing 'authorization'.\n       */\n      AuthorizationCoveredByWildcard: \"Authorization will not be covered by the wildcard symbol (*) in CORS `Access-Control-Allow-Headers` handling.\",\n      /**\n       * @description This warning occurs when a page attempts to request a resource whose URL contained both a newline character (`\\n` or `\\r`), and a less-than character (`<`). These resources are blocked.\n       */\n      CanRequestURLHTTPContainingNewline: \"Resource requests whose URLs contained both removed whitespace `(n|r|t)` characters and less-than characters (`<`) are blocked. Please remove newlines and encode less-than characters from places like element attribute values in order to load these resources.\",\n      /**\n       * @description This warning occurs when the website attempts to invoke the deprecated `chrome.loadTimes().connectionInfo` API.\n       */\n      ChromeLoadTimesConnectionInfo: \"`chrome.loadTimes()` is deprecated, instead use standardized API: Navigation Timing 2.\",\n      /**\n       * @description This warning occurs when the website attempts to invoke the deprecated `chrome.loadTimes().firstPaintAfterLoadTime` API.\n       */\n      ChromeLoadTimesFirstPaintAfterLoadTime: \"`chrome.loadTimes()` is deprecated, instead use standardized API: Paint Timing.\",\n      /**\n       * @description This warning occurs when the website attempts to invoke the deprecated `chrome.loadTimes().wasAlternateProtocolAvailable` API.\n       */\n      ChromeLoadTimesWasAlternateProtocolAvailable: \"`chrome.loadTimes()` is deprecated, instead use standardized API: `nextHopProtocol` in Navigation Timing 2.\",\n      /**\n       * @description This warning occurs when the browser attempts to store a cookie containing a banned character. Rather than the cookie string being truncated at the banned character, the entire cookie will be rejected now.\n       */\n      CookieWithTruncatingChar: \"Cookies containing a `(0|r|n)` character will be rejected instead of truncated.\",\n      /**\n       * @description This warning occurs when a frame accesses another frame's data after having set `document.domain` without having set the `Origin-Agent-Cluster` http header. This is a companion warning to `documentDomainSettingWithoutOriginAgentClusterHeader`, where that warning occurs when `document.domain` is set, and this warning occurs when an access has been made, based on that previous `document.domain` setting.\n       */\n      CrossOriginAccessBasedOnDocumentDomain: \"Relaxing the same-origin policy by setting `document.domain` is deprecated, and will be disabled by default. This deprecation warning is for a cross-origin access that was enabled by setting `document.domain`.\",\n      /**\n       * @description Issue text shown when the web page uses a deprecated web API. The window.alert is the deprecated web API function.\n       */\n      CrossOriginWindowAlert: \"Triggering window.alert from cross origin iframes has been deprecated and will be removed in the future.\",\n      /**\n       * @description Issue text shown when the web page uses a deprecated web API. The window.confirm is the deprecated web API function.\n       */\n      CrossOriginWindowConfirm: \"Triggering window.confirm from cross origin iframes has been deprecated and will be removed in the future.\",\n      /**\n       * @description Warning displayed to developers when they hide the Cast button on a video element using the deprecated CSS selector instead of using the disableRemotePlayback attribute on the element.\n       */\n      CSSSelectorInternalMediaControlsOverlayCastButton: \"The `disableRemotePlayback` attribute should be used in order to disable the default Cast integration instead of using `-internal-media-controls-overlay-cast-button` selector.\",\n      /**\n       * @description Warning displayed to developers to let them know the CSS appearance property value they used is not standard and will be removed.\n       */\n      CSSValueAppearanceSliderVertical: \"CSS appearance value `slider-vertical` is not standardized and will be removed.\",\n      /**\n       * @description Warning displayed to developers when a data: URL is assigned to SVGUseElement to let them know that the support is deprecated.\n       */\n      DataUrlInSvgUse: \"Support for data: URLs in SVGUseElement is deprecated and it will be removed in the future.\",\n      /**\n       * @description Warning displayed to developers when the Geolocation API is used from an insecure origin (one that isn't localhost or doesn't use HTTPS) to notify them that this use is no longer supported.\n       */\n      GeolocationInsecureOrigin: \"`getCurrentPosition()` and `watchPosition()` no longer work on insecure origins. To use this feature, you should consider switching your application to a secure origin, such as HTTPS. See https://www.chromium.org/Home/chromium-security/deprecating-powerful-features-on-insecure-origins/ for more details.\",\n      /**\n       * @description Warning displayed to developers when the Geolocation API is used from an insecure origin (one that isn't localhost or doesn't use HTTPS) to notify them that this use is deprecated.\n       */\n      GeolocationInsecureOriginDeprecatedNotRemoved: \"`getCurrentPosition()` and `watchPosition()` are deprecated on insecure origins. To use this feature, you should consider switching your application to a secure origin, such as HTTPS. See https://www.chromium.org/Home/chromium-security/deprecating-powerful-features-on-insecure-origins/ for more details.\",\n      /**\n       * @description This warning occurs when the `getUserMedia()` API is invoked on an insecure (e.g., HTTP) site. This is only permitted on secure sites (e.g., HTTPS).\n       */\n      GetUserMediaInsecureOrigin: \"`getUserMedia()` no longer works on insecure origins. To use this feature, you should consider switching your application to a secure origin, such as HTTPS. See https://www.chromium.org/Home/chromium-security/deprecating-powerful-features-on-insecure-origins/ for more details.\",\n      /**\n       * @description A deprecation warning shown to developers in the DevTools Issues tab when code tries to use the deprecated hostCandidate field, guiding developers to use the equivalent information in the .address and .port fields instead.\n       */\n      HostCandidateAttributeGetter: \"`RTCPeerConnectionIceErrorEvent.hostCandidate` is deprecated. Please use `RTCPeerConnectionIceErrorEvent.address` or `RTCPeerConnectionIceErrorEvent.port` instead.\",\n      /**\n       * @description A deprecation warning shown in the DevTools Issues tab, when a service worker reads one of the fields from an event named 'canmakepayment'.\n       */\n      IdentityInCanMakePaymentEvent: \"The merchant origin and arbitrary data from the `canmakepayment` service worker event are deprecated and will be removed: `topOrigin`, `paymentRequestOrigin`, `methodData`, `modifiers`.\",\n      /**\n       * @description This warning occurs when an insecure context (e.g., HTTP) requests a private resource (not on open internet). This is done to mitigate the potential for CSRF and other attacks.\n       */\n      InsecurePrivateNetworkSubresourceRequest: \"The website requested a subresource from a network that it could only access because of its users' privileged network position. These requests expose non-public devices and servers to the internet, increasing the risk of a cross-site request forgery (CSRF) attack, and/or information leakage. To mitigate these risks, Chrome deprecates requests to non-public subresources when initiated from non-secure contexts, and will start blocking them.\",\n      /**\n       * @description This is a deprecated warning to developers that a field in a structure has been renamed.\n       */\n      InterestGroupDailyUpdateUrl: \"The `dailyUpdateUrl` field of `InterestGroups` passed to `joinAdInterestGroup()` has been renamed to `updateUrl`, to more accurately reflect its behavior.\",\n      /**\n       * @description Warning displayed to developers that instead of calling the `Intl.v8BreakIterator` constructor, which is not a standard JavaScript API, use ECMA402 standard API Intl.Segmenter shipped in end of 2020 instead.\n       */\n      IntlV8BreakIterator: \"`Intl.v8BreakIterator` is deprecated. Please use `Intl.Segmenter` instead.\",\n      /**\n       * @description This warning occurs when a stylesheet loaded from a local file directive does not end in the file type `.css`.\n       */\n      LocalCSSFileExtensionRejected: \"CSS cannot be loaded from `file:` URLs unless they end in a `.css` file extension.\",\n      /**\n       * @description This is a deprecation warning to developers that occurs when the script attempts to use the Media Source Extensions API in a way that is no longer supported by the specification for the API. The usage that is problematic is when the script calls the `SourceBuffer.abort()` method at a time when there is still processing happening in response to a previous `SourceBuffer.remove()` call for the same SourceBuffer object. More precisely, we show this warning to developers when script calls the SourceBuffer abort() method while the asynchronous processing of a remove() call on that SourceBuffer is not yet complete. Early versions of the Media Source Extensions specification allowed such aborts, but standardization of the specification resulted in disallowing the aborts. The script should instead wait for the asynchronous remove() operation to complete, which is observable by listening for the associated 'updateend' event from the SourceBuffer. A note is also included in the warning, describing when abort() is meaningful and allowed by the specification for purposes other than interrupting a remove() operation's asynchronous steps. Those supported purposes include using abort() to interrupt processing that may still be happening in response to a previous appendBuffer() call on that SourceBuffer, or using abort() to clear the internal of any unprocessed data remaining from previous appendBuffer() calls. See https://www.w3.org/TR/media-source-2/#dom-sourcebuffer-abort for the currently specified behavior, which would throw an exception once the deprecated removal abort is no longer supported. See https://github.com/w3c/media-source/issues/19 for the discussion that led to the specification change.\n       */\n      MediaSourceAbortRemove: \"Using `SourceBuffer.abort()` to abort `remove()`'s asynchronous range removal is deprecated due to specification change. Support will be removed in the future. You should listen to the `updateend` event instead. `abort()` is intended to only abort an asynchronous media append or reset parser state.\",\n      /**\n       * @description This is a deprecation warning to developers that occurs when the script attempts to use the Media Source Extensions API in a way that is no longer supported by the specification for the API. The usage that is problematic is when the script sets the duration attribute of a MediaSource object too low. The duration attribute of a MediaSource must be longer than the actual duration of any media (audio or video) already in the MediaSource. When set too low, the MediaSource must remove audio and video content that is beyond the time indicated by the new duration. Content removal that is caused by setting the duration attribute too low is no longer allowed by the specification. The message describes the minimum allowable duration value as the 'highest presentation timestamp of any buffered coded frames' as a more precise way of describing the duration of content already in the MediaSource: 'coded frames' are the specification's way of describing compressed audio frames or compressed video frames, and they each have a 'presentation timestamp' that describes precisely when that frame's playback occurs in the overall media presentation. Early versions of the Media Source Extensions specification allowed this to happen, but standardization of the specification resulted in disallowing this behavior. The underlying issue leading to this specification change was that setting the duration attribute should be synchronous, but setting it lower than the timestamp of something currently buffered would cause confusing removal of media between that new duration and the previous, larger, duration. The script should instead explicitly remove that range of media first, before lowering the duration. See https://www.w3.org/TR/media-source-2/#dom-mediasource-duration and https://www.w3.org/TR/media-source-2/#dom-mediasource-duration for the currently specified behavior, which would throw an exception once support is removed for deprecated implicit asynchronous range removal when duration is truncated. See both https://github.com/w3c/media-source/issues/20 and https://github.com/w3c/media-source/issues/26 for the discussion that led to the specification change.\n       */\n      MediaSourceDurationTruncatingBuffered: \"Setting `MediaSource.duration` below the highest presentation timestamp of any buffered coded frames is deprecated due to specification change. Support for implicit removal of truncated buffered media will be removed in the future. You should instead perform explicit `remove(newDuration, oldDuration)` on all `sourceBuffers`, where `newDuration < oldDuration`.\",\n      /**\n       * @description This warning occurs when the browser requests Web MIDI access as sysex (system exclusive messages) can be allowed via prompt even if the browser did not specifically request it.\n       */\n      NoSysexWebMIDIWithoutPermission: \"Web MIDI will ask a permission to use even if the sysex is not specified in the `MIDIOptions`.\",\n      /**\n       * @description Warning displayed to developers when the Notification API is used from an insecure origin (one that isn't localhost or doesn't use HTTPS) to notify them that this use is no longer supported.\n       */\n      NotificationInsecureOrigin: \"The Notification API may no longer be used from insecure origins. You should consider switching your application to a secure origin, such as HTTPS. See https://www.chromium.org/Home/chromium-security/deprecating-powerful-features-on-insecure-origins/ for more details.\",\n      /**\n       * @description Warning displayed to developers when permission to use notifications has been requested by a cross-origin iframe, to notify them that this use is no longer supported.\n       */\n      NotificationPermissionRequestedIframe: \"Permission for the Notification API may no longer be requested from a cross-origin iframe. You should consider requesting permission from a top-level frame or opening a new window instead.\",\n      /**\n       * @description Warning displayed to developers when CreateImageBitmap is used with the newly deprecated option imageOrientation: 'none'.\n       */\n      ObsoleteCreateImageBitmapImageOrientationNone: \"Option `imageOrientation: 'none'` in createImageBitmap is deprecated. Please use createImageBitmap with option '\\\\{imageOrientation: 'from-image'\\\\}' instead.\",\n      /**\n       * @description This warning occurs when the WebRTC protocol attempts to negotiate a connection using an obsolete cipher and risks connection security.\n       */\n      ObsoleteWebRtcCipherSuite: \"Your partner is negotiating an obsolete (D)TLS version. Please check with your partner to have this fixed.\",\n      /**\n       * @description Warning displayed to developers that use overflow:visible for replaced elements. This declaration was earlier ignored but will now change the element's painting based on whether the overflow value allows the element to paint outside its bounds.\n       */\n      OverflowVisibleOnReplacedElement: \"Specifying `overflow: visible` on img, video and canvas tags may cause them to produce visual content outside of the element bounds. See https://github.com/WICG/shared-element-transitions/blob/main/debugging_overflow_on_images.md.\",\n      /**\n       * @description Warning displayed to developers when they use a Flash Embed URLS to let them know that the browser will not automatically link to their equivalent HTML5 link.\n       */\n      OverrideFlashEmbedwithHTML: \"Legacy flash video embed has been rewritten to HTML iframe. Flash is long gone, this rewriting hack is deprecated and may be removed in the future.\",\n      /**\n       * @description Warning displayed to developers when they use the PaymentInstruments API to let them know this API is deprecated.\n       */\n      PaymentInstruments: \"`paymentManager.instruments` is deprecated. Please use just-in-time install for payment handlers instead.\",\n      /**\n       * @description Warning displayed to developers when their Web Payment API usage violates their Content-Security-Policy (CSP) connect-src directive to let them know this CSP bypass has been deprecated.\n       */\n      PaymentRequestCSPViolation: \"Your `PaymentRequest` call bypassed Content-Security-Policy (CSP) `connect-src` directive. This bypass is deprecated. Please add the payment method identifier from the `PaymentRequest` API (in `supportedMethods` field) to your CSP `connect-src` directive.\",\n      /**\n       * @description Warning displayed to developers when persistent storage type is used to notify that storage type is deprecated.\n       */\n      PersistentQuotaType: \"`StorageType.persistent` is deprecated. Please use standardized `navigator.storage` instead.\",\n      /**\n       * @description This issue indicates that a `<source>` element with a `<picture>` parent was using an `src` attribute, which is not valid and is ignored by the browser. The `srcset` attribute should be used instead.\n       */\n      PictureSourceSrc: \"`<source src>` with a `<picture>` parent is invalid and therefore ignored. Please use `<source srcset>` instead.\",\n      /**\n       * @description Warning displayed to developers when the vendor-prefixed method (webkitCancelAnimationFrame) is used rather than the equivalent unprefixed method (cancelAnimationFrame).\n       */\n      PrefixedCancelAnimationFrame: \"webkitCancelAnimationFrame is vendor-specific. Please use the standard cancelAnimationFrame instead.\",\n      /**\n       * @description Warning displayed to developers when the vendor-prefixed method (webkitRequestAnimationFrame) is used rather than the equivalent unprefixed method (requestAnimationFrame).\n       */\n      PrefixedRequestAnimationFrame: \"webkitRequestAnimationFrame is vendor-specific. Please use the standard requestAnimationFrame instead.\",\n      /**\n       * @description Standard message when one web API is deprecated in favor of another.\n       */\n      PrefixedVideoDisplayingFullscreen: \"HTMLVideoElement.webkitDisplayingFullscreen is deprecated. Please use Document.fullscreenElement instead.\",\n      /**\n       * @description Standard message when one web API is deprecated in favor of another.\n       */\n      PrefixedVideoEnterFullScreen: \"HTMLVideoElement.webkitEnterFullScreen() is deprecated. Please use Element.requestFullscreen() instead.\",\n      /**\n       * @description Standard message when one web API is deprecated in favor of another.\n       */\n      PrefixedVideoEnterFullscreen: \"HTMLVideoElement.webkitEnterFullscreen() is deprecated. Please use Element.requestFullscreen() instead.\",\n      /**\n       * @description Standard message when one web API is deprecated in favor of another.\n       */\n      PrefixedVideoExitFullScreen: \"HTMLVideoElement.webkitExitFullScreen() is deprecated. Please use Document.exitFullscreen() instead.\",\n      /**\n       * @description Standard message when one web API is deprecated in favor of another.\n       */\n      PrefixedVideoExitFullscreen: \"HTMLVideoElement.webkitExitFullscreen() is deprecated. Please use Document.exitFullscreen() instead.\",\n      /**\n       * @description Standard message when one web API is deprecated in favor of another.\n       */\n      PrefixedVideoSupportsFullscreen: \"HTMLVideoElement.webkitSupportsFullscreen is deprecated. Please use Document.fullscreenEnabled instead.\",\n      /**\n       * @description Warning displayed to developers that the API `chrome.privacy.websites.privacySandboxEnabled` is being deprecated in favour of three new more granular APIs: topicsEnabled, FledgeEnabled and adMeasurementEnabled. The `privacySandboxEnabled` API allowed extensions to control the homologous Chrome Setting. The existing Chrome Setting for Privacy Sandbox is also going away in favor of more granular settings that are matched by the new extensions APIs- topicsEnabled, FledgeEnabled and adMeasurementEnabled.\n       */\n      PrivacySandboxExtensionsAPI: \"We're deprecating the API `chrome.privacy.websites.privacySandboxEnabled`, though it will remain active for backward compatibility until release M113. Instead, please use `chrome.privacy.websites.topicsEnabled`, `chrome.privacy.websites.fledgeEnabled` and `chrome.privacy.websites.adMeasurementEnabled`. See https://developer.chrome.com/docs/extensions/reference/privacy/#property-websites-privacySandboxEnabled.\",\n      /**\n       * @description Standard message when one web API is deprecated in favor of another.\n       */\n      RangeExpand: \"Range.expand() is deprecated. Please use Selection.modify() instead.\",\n      /**\n       * @description This warning occurs when a subresource loaded by a page has a URL with an authority portion. These are disallowed.\n       */\n      RequestedSubresourceWithEmbeddedCredentials: \"Subresource requests whose URLs contain embedded credentials (e.g. `https://user:pass@host/`) are blocked.\",\n      /**\n       * @description A deprecation warning shown in the DevTools Issues tab. It's shown when a video conferencing website attempts to use a non-standard crypto method when performing a handshake to set up a connection with another endpoint.\n       */\n      RTCConstraintEnableDtlsSrtpFalse: \"The constraint `DtlsSrtpKeyAgreement` is removed. You have specified a `false` value for this constraint, which is interpreted as an attempt to use the removed `SDES key negotiation` method. This functionality is removed; use a service that supports `DTLS key negotiation` instead.\",\n      /**\n       * @description A deprecation warning shown in the DevTools Issues tab. It's shown when a video conferencing website uses a non-standard API for controlling the crypto method used, but is not having an effect because the desired behavior is already enabled-by-default.\n       */\n      RTCConstraintEnableDtlsSrtpTrue: \"The constraint `DtlsSrtpKeyAgreement` is removed. You have specified a `true` value for this constraint, which had no effect, but you can remove this constraint for tidiness.\",\n      /**\n       * @description WebRTC is set of JavaScript APIs for sending and receiving data, audio and video. getStats() is a method used to obtain network and quality metrics. There are two versions of this method, one is being deprecated because it is non-standard.\n       */\n      RTCPeerConnectionGetStatsLegacyNonCompliant: \"The callback-based getStats() is deprecated and will be removed. Use the spec-compliant getStats() instead.\",\n      /**\n       * @description A deprecation warning shown in the DevTools Issues tab. It's shown then a video conferencing website attempts to use the `RTCP MUX` policy.\n       */\n      RtcpMuxPolicyNegotiate: \"The `rtcpMuxPolicy` option is deprecated and will be removed.\",\n      /**\n       * @description A deprecation warning shown in the DevTools Issues tab. The placeholder is always the noun 'SharedArrayBuffer' which refers to a JavaScript construct.\n       */\n      SharedArrayBufferConstructedWithoutIsolation: \"`SharedArrayBuffer` will require cross-origin isolation. See https://developer.chrome.com/blog/enabling-shared-array-buffer/ for more details.\",\n      /**\n       * @description A deprecation warning shown in the DevTools Issues tab. It's shown when the speech synthesis API is called before the page receives a user activation.\n       */\n      TextToSpeech_DisallowedByAutoplay: \"`speechSynthesis.speak()` without user activation is deprecated and will be removed.\",\n      /**\n       * @description A deprecation warning shown in the DevTools Issues tab. It's shown when a listener for the `unload` event is added.\n       */\n      UnloadHandler: \"Unload event listeners are deprecated and will be removed.\",\n      /**\n       * @description A deprecation warning shown in the DevTools Issues tab. The placeholder is always the noun 'SharedArrayBuffer' which refers to a JavaScript construct. 'Extensions' refers to Chrome extensions. The warning is shown when Chrome Extensions attempt to use 'SharedArrayBuffer's under insecure circumstances.\n       */\n      V8SharedArrayBufferConstructedInExtensionWithoutIsolation: \"Extensions should opt into cross-origin isolation to continue using `SharedArrayBuffer`. See https://developer.chrome.com/docs/extensions/mv3/cross-origin-isolation/.\",\n      /**\n       * @description Warning displayed to developers that they are using `XMLHttpRequest` API in a way that they expect an unsupported character encoding `UTF-16` could be used in the server reply.\n       */\n      XHRJSONEncodingDetection: \"UTF-16 is not supported by response json in `XMLHttpRequest`\",\n      /**\n       * @description Warning displayed to developers. It is shown when the `XMLHttpRequest` API is used in a way that it slows down the page load of the next page. The `main thread` refers to an operating systems thread used to run most of the processing of HTML documents, so please use a consistent wording.\n       */\n      XMLHttpRequestSynchronousInNonWorkerOutsideBeforeUnload: \"Synchronous `XMLHttpRequest` on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check https://xhr.spec.whatwg.org/.\"\n    };\n    DEPRECATIONS_METADATA = {\n      \"AuthorizationCoveredByWildcard\": {\n        \"milestone\": 97\n      },\n      \"CSSSelectorInternalMediaControlsOverlayCastButton\": {\n        \"chromeStatusFeature\": 5714245488476160\n      },\n      \"CSSValueAppearanceSliderVertical\": {\n        \"chromeStatusFeature\": 6001359429566464\n      },\n      \"CanRequestURLHTTPContainingNewline\": {\n        \"chromeStatusFeature\": 5735596811091968\n      },\n      \"ChromeLoadTimesConnectionInfo\": {\n        \"chromeStatusFeature\": 5637885046816768\n      },\n      \"ChromeLoadTimesFirstPaintAfterLoadTime\": {\n        \"chromeStatusFeature\": 5637885046816768\n      },\n      \"ChromeLoadTimesWasAlternateProtocolAvailable\": {\n        \"chromeStatusFeature\": 5637885046816768\n      },\n      \"CookieWithTruncatingChar\": {\n        \"milestone\": 103\n      },\n      \"CrossOriginAccessBasedOnDocumentDomain\": {\n        \"milestone\": 115\n      },\n      \"DataUrlInSvgUse\": {\n        \"chromeStatusFeature\": 5128825141198848,\n        \"milestone\": 119\n      },\n      \"IdentityInCanMakePaymentEvent\": {\n        \"chromeStatusFeature\": 5190978431352832\n      },\n      \"InsecurePrivateNetworkSubresourceRequest\": {\n        \"chromeStatusFeature\": 5436853517811712,\n        \"milestone\": 92\n      },\n      \"LocalCSSFileExtensionRejected\": {\n        \"milestone\": 64\n      },\n      \"MediaSourceAbortRemove\": {\n        \"chromeStatusFeature\": 6107495151960064\n      },\n      \"MediaSourceDurationTruncatingBuffered\": {\n        \"chromeStatusFeature\": 6107495151960064\n      },\n      \"NoSysexWebMIDIWithoutPermission\": {\n        \"chromeStatusFeature\": 5138066234671104,\n        \"milestone\": 82\n      },\n      \"NotificationPermissionRequestedIframe\": {\n        \"chromeStatusFeature\": 6451284559265792\n      },\n      \"ObsoleteCreateImageBitmapImageOrientationNone\": {\n        \"milestone\": 111\n      },\n      \"ObsoleteWebRtcCipherSuite\": {\n        \"milestone\": 81\n      },\n      \"OverflowVisibleOnReplacedElement\": {\n        \"chromeStatusFeature\": 5137515594383360,\n        \"milestone\": 108\n      },\n      \"OverrideFlashEmbedwithHTML\": {\n        \"milestone\": 140\n      },\n      \"PaymentInstruments\": {\n        \"chromeStatusFeature\": 5099285054488576\n      },\n      \"PaymentRequestCSPViolation\": {\n        \"chromeStatusFeature\": 6286595631087616\n      },\n      \"PersistentQuotaType\": {\n        \"chromeStatusFeature\": 5176235376246784,\n        \"milestone\": 106\n      },\n      \"RTCConstraintEnableDtlsSrtpFalse\": {\n        \"milestone\": 97\n      },\n      \"RTCConstraintEnableDtlsSrtpTrue\": {\n        \"milestone\": 97\n      },\n      \"RTCPeerConnectionGetStatsLegacyNonCompliant\": {\n        \"chromeStatusFeature\": 4631626228695040,\n        \"milestone\": 117\n      },\n      \"RequestedSubresourceWithEmbeddedCredentials\": {\n        \"chromeStatusFeature\": 5669008342777856\n      },\n      \"RtcpMuxPolicyNegotiate\": {\n        \"chromeStatusFeature\": 5654810086866944,\n        \"milestone\": 62\n      },\n      \"SharedArrayBufferConstructedWithoutIsolation\": {\n        \"milestone\": 106\n      },\n      \"TextToSpeech_DisallowedByAutoplay\": {\n        \"chromeStatusFeature\": 5687444770914304,\n        \"milestone\": 71\n      },\n      \"UnloadHandler\": {\n        \"chromeStatusFeature\": 5579556305502208\n      },\n      \"V8SharedArrayBufferConstructedInExtensionWithoutIsolation\": {\n        \"milestone\": 96\n      },\n      \"XHRJSONEncodingDetection\": {\n        \"milestone\": 93\n      }\n    };\n  }\n});\n\n// core/lib/deprecation-description.js\nfunction getIssueDetailDescription(issueDetails) {\n  let message;\n  const type = (\n    /** @type {keyof DEPRECATIONS_METADATA} */\n    issueDetails.type\n  );\n  const maybeEnglishMessage = UIStrings90[type];\n  if (maybeEnglishMessage) {\n    message = deprecationsStr_(maybeEnglishMessage);\n  }\n  const links = [];\n  const deprecationMeta = DEPRECATIONS_METADATA[type];\n  const feature = deprecationMeta?.chromeStatusFeature ?? 0;\n  if (feature !== 0) {\n    links.push({\n      link: `https://chromestatus.com/feature/${feature}`,\n      linkTitle: str_71(UIStrings91.feature)\n    });\n  }\n  const milestone = deprecationMeta?.milestone ?? 0;\n  if (milestone !== 0) {\n    links.push({\n      link: \"https://chromiumdash.appspot.com/schedule\",\n      linkTitle: str_71(UIStrings91.milestone, { milestone })\n    });\n  }\n  return {\n    substitutions: /* @__PURE__ */ new Map([\n      [\"PLACEHOLDER_title\", str_71(UIStrings91.title)],\n      [\"PLACEHOLDER_message\", message]\n    ]),\n    links,\n    message\n  };\n}\nvar UIStrings91, str_71, deprecationsStr_;\nvar init_deprecation_description = __esm({\n  \"core/lib/deprecation-description.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_i18n();\n    init_deprecations_strings();\n    /**\n     * @license\n     * Copyright 2023 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    UIStrings91 = {\n      // Store strings used across messages in this block.\n      /**\n       * @description This links to the chrome feature status page when one exists.\n       */\n      feature: \"Check the feature status page for more details.\",\n      /**\n       * @description This links to the chromium dash schedule when a milestone is set.\n       * @example {100} milestone\n       */\n      milestone: \"This change will go into effect with milestone {milestone}.\",\n      /**\n       * @description Title of issue raised when a deprecated feature is used\n       */\n      title: \"Deprecated Feature Used\"\n    };\n    str_71 = createIcuMessageFn({ url: \"core/lib/deprecation-description.js\" }.url, UIStrings91);\n    deprecationsStr_ = createIcuMessageFn(\n      \"node_modules/@paulirish/trace_engine/generated/Deprecation.js\",\n      UIStrings90\n    );\n    __name(getIssueDetailDescription, \"getIssueDetailDescription\");\n  }\n});\n\n// core/audits/deprecations.js\nvar deprecations_exports = {};\n__export(deprecations_exports, {\n  UIStrings: () => UIStrings92,\n  default: () => deprecations_default\n});\nvar UIStrings92, str_72, Deprecations, deprecations_default;\nvar init_deprecations = __esm({\n  \"core/audits/deprecations.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_audit();\n    init_js_bundles();\n    init_i18n();\n    init_deprecation_description();\n    /**\n     * @license\n     * Copyright 2017 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    UIStrings92 = {\n      /** Title of a Lighthouse audit that provides detail on the use of deprecated APIs. This descriptive title is shown to users when the page does not use deprecated APIs. */\n      title: \"Avoids deprecated APIs\",\n      /** Title of a Lighthouse audit that provides detail on the use of deprecated APIs. This descriptive title is shown to users when the page uses deprecated APIs. */\n      failureTitle: \"Uses deprecated APIs\",\n      /** Description of a Lighthouse audit that tells the user why they should not use deprecated APIs on their page. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */\n      description: \"Deprecated APIs will eventually be removed from the browser. [Learn more about deprecated APIs](https://developer.chrome.com/docs/lighthouse/best-practices/deprecations/).\",\n      /** [ICU Syntax] Label for the audit identifying the number of warnings generated by using deprecated APIs. */\n      displayValue: `{itemCount, plural,\n    =1 {1 warning found}\n    other {# warnings found}\n    }`,\n      /** Header of the table column which displays the warning message describing use of a deprecated API by code running in the web page. */\n      columnDeprecate: \"Deprecation / Warning\",\n      /** Table column header for line of code (eg. 432) that is using a deprecated API. */\n      columnLine: \"Line\"\n    };\n    str_72 = createIcuMessageFn({ url: \"core/audits/deprecations.js\" }.url, UIStrings92);\n    Deprecations = class extends Audit {\n      static {\n        __name(this, \"Deprecations\");\n      }\n      /**\n       * @return {LH.Audit.Meta}\n       */\n      static get meta() {\n        return {\n          id: \"deprecations\",\n          title: str_72(UIStrings92.title),\n          failureTitle: str_72(UIStrings92.failureTitle),\n          description: str_72(UIStrings92.description),\n          requiredArtifacts: [\"InspectorIssues\", \"SourceMaps\", \"Scripts\"]\n        };\n      }\n      /**\n       * @param {LH.Artifacts} artifacts\n       * @param {LH.Audit.Context} context\n       * @return {Promise<LH.Audit.Product>}\n       */\n      static async audit(artifacts, context) {\n        const bundles = await JSBundlesComputed.request(artifacts, context);\n        const deprecations = (artifacts.InspectorIssues.deprecationIssue ?? []).map((deprecation) => {\n          const { scriptId, url, lineNumber, columnNumber } = deprecation.sourceCodeLocation;\n          const bundle = bundles.find((bundle2) => bundle2.script.scriptId === scriptId);\n          const deprecationMeta = getIssueDetailDescription(deprecation);\n          let subItems = void 0;\n          if (deprecationMeta.links.length) {\n            subItems = {\n              type: \"subitems\",\n              items: deprecationMeta.links.map((link) => ({\n                type: \"link\",\n                url: link.link,\n                text: link.linkTitle\n              }))\n            };\n          }\n          const legacyMessage = deprecation.message;\n          const item = {\n            value: deprecationMeta.message || legacyMessage || deprecation.type,\n            // Protocol.Audits.SourceCodeLocation.columnNumber is 1-indexed, but we use 0-indexed.\n            source: Audit.makeSourceLocation(url, lineNumber, columnNumber - 1, bundle),\n            subItems\n          };\n          return item;\n        });\n        const headings = [\n          { key: \"value\", valueType: \"text\", label: str_72(UIStrings92.columnDeprecate) },\n          { key: \"source\", valueType: \"source-location\", label: str_72(UIStrings.columnSource) }\n        ];\n        const details = Audit.makeTableDetails(headings, deprecations);\n        let displayValue;\n        if (deprecations.length > 0) {\n          displayValue = str_72(UIStrings92.displayValue, { itemCount: deprecations.length });\n        }\n        return {\n          score: Number(deprecations.length === 0),\n          displayValue,\n          details\n        };\n      }\n    };\n    deprecations_default = Deprecations;\n  }\n});\n\n// core/audits/dobetterweb/charset.js\nvar charset_exports = {};\n__export(charset_exports, {\n  CHARSET_HTML_REGEX: () => CHARSET_HTML_REGEX,\n  CHARSET_HTTP_REGEX: () => CHARSET_HTTP_REGEX,\n  IANA_REGEX: () => IANA_REGEX,\n  UIStrings: () => UIStrings93,\n  default: () => charset_default\n});\nvar UIStrings93, str_73, CONTENT_TYPE_HEADER, IANA_REGEX, CHARSET_HTML_REGEX, CHARSET_HTTP_REGEX, CharsetDefined, charset_default;\nvar init_charset = __esm({\n  \"core/audits/dobetterweb/charset.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_audit();\n    init_i18n();\n    init_main_resource();\n    /**\n     * @license\n     * Copyright 2020 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    UIStrings93 = {\n      /** Title of a Lighthouse audit that provides detail on if the charset is set properly for a page. This title is shown when the charset is defined correctly. Charset defines the character encoding (eg UTF-8) of the page content. */\n      title: \"Properly defines charset\",\n      /** Title of a Lighthouse audit that provides detail on if the charset is set properly for a page. This title is shown when the charset meta tag is missing or defined too late in the page. */\n      failureTitle: \"Charset declaration is missing or occurs too late in the HTML\",\n      /** Description of a Lighthouse audit that tells the user why the charset needs to be defined early on. */\n      description: \"A character encoding declaration is required. It can be done with a `<meta>` tag in the first 1024 bytes of the HTML or in the Content-Type HTTP response header. [Learn more about declaring the character encoding](https://developer.chrome.com/docs/lighthouse/best-practices/charset/).\"\n    };\n    str_73 = createIcuMessageFn({ url: \"core/audits/dobetterweb/charset.js\" }.url, UIStrings93);\n    CONTENT_TYPE_HEADER = \"content-type\";\n    IANA_REGEX = /^[a-zA-Z0-9-_:.()]{2,}$/;\n    CHARSET_HTML_REGEX = /<meta[^>]+charset[^<]+>/i;\n    CHARSET_HTTP_REGEX = /charset\\s*=\\s*[a-zA-Z0-9-_:.()]{2,}/i;\n    CharsetDefined = class extends Audit {\n      static {\n        __name(this, \"CharsetDefined\");\n      }\n      /**\n       * @return {LH.Audit.Meta}\n       */\n      static get meta() {\n        return {\n          id: \"charset\",\n          title: str_73(UIStrings93.title),\n          failureTitle: str_73(UIStrings93.failureTitle),\n          description: str_73(UIStrings93.description),\n          requiredArtifacts: [\"MainDocumentContent\", \"URL\", \"DevtoolsLog\", \"MetaElements\"]\n        };\n      }\n      /**\n       * @param {LH.Artifacts} artifacts\n       * @param {LH.Audit.Context} context\n       * @return {Promise<LH.Audit.Product>}\n       */\n      static async audit(artifacts, context) {\n        const devtoolsLog = artifacts.DevtoolsLog;\n        const mainResource = await MainResourceComputed.request({ devtoolsLog, URL: artifacts.URL }, context);\n        let isCharsetSet = false;\n        if (mainResource.responseHeaders) {\n          const contentTypeHeader = mainResource.responseHeaders.find((header) => header.name.toLowerCase() === CONTENT_TYPE_HEADER);\n          if (contentTypeHeader) {\n            isCharsetSet = CHARSET_HTTP_REGEX.test(contentTypeHeader.value);\n          }\n        }\n        const BOM_FIRSTCHAR = 65279;\n        isCharsetSet = isCharsetSet || artifacts.MainDocumentContent.charCodeAt(0) === BOM_FIRSTCHAR;\n        if (CHARSET_HTML_REGEX.test(artifacts.MainDocumentContent.slice(0, 1024))) {\n          isCharsetSet = isCharsetSet || artifacts.MetaElements.some((meta) => {\n            return meta.charset && IANA_REGEX.test(meta.charset) || meta.httpEquiv === \"content-type\" && meta.content && CHARSET_HTTP_REGEX.test(meta.content);\n          });\n        }\n        return {\n          score: Number(isCharsetSet)\n        };\n      }\n    };\n    charset_default = CharsetDefined;\n  }\n});\n\n// core/lib/lh-trace-processor.js\nvar LHTraceProcessor, lh_trace_processor_default;\nvar init_lh_trace_processor = __esm({\n  \"core/lib/lh-trace-processor.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_lh_error();\n    init_trace_processor();\n    /**\n     * @license\n     * Copyright 2021 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    LHTraceProcessor = class extends TraceProcessor2 {\n      static {\n        __name(this, \"LHTraceProcessor\");\n      }\n      /**\n       * @return {Error}\n       */\n      static createNoNavstartError() {\n        return new LighthouseError(LighthouseError.errors.NO_NAVSTART);\n      }\n      /**\n       * This isn't currently used, but will be when the time origin of trace processing is changed.\n       * @see {TraceProcessor.computeTimeOrigin}\n       * @see https://github.com/GoogleChrome/lighthouse/pull/11253#discussion_r507985527\n       * @return {Error}\n       */\n      static createNoResourceSendRequestError() {\n        return new LighthouseError(LighthouseError.errors.NO_RESOURCE_REQUEST);\n      }\n      /**\n       * @return {Error}\n       */\n      static createNoTracingStartedError() {\n        return new LighthouseError(LighthouseError.errors.NO_TRACING_STARTED);\n      }\n      /**\n       * @return {Error}\n       */\n      static createNoFirstContentfulPaintError() {\n        return new LighthouseError(LighthouseError.errors.NO_FCP);\n      }\n    };\n    lh_trace_processor_default = LHTraceProcessor;\n  }\n});\n\n// core/computed/processed-trace.js\nvar ProcessedTrace, ProcessedTraceComputed;\nvar init_processed_trace = __esm({\n  \"core/computed/processed-trace.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_computed_artifact();\n    init_lh_trace_processor();\n    /**\n     * @license\n     * Copyright 2021 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    ProcessedTrace = class {\n      static {\n        __name(this, \"ProcessedTrace\");\n      }\n      /**\n        * @param {LH.Trace} trace\n        * @return {Promise<LH.Artifacts.ProcessedTrace>}\n       */\n      static async compute_(trace) {\n        return lh_trace_processor_default.processTrace(trace);\n      }\n    };\n    ProcessedTraceComputed = makeComputedArtifact(ProcessedTrace, null);\n  }\n});\n\n// core/audits/dobetterweb/doctype.js\nvar doctype_exports2 = {};\n__export(doctype_exports2, {\n  UIStrings: () => UIStrings94,\n  default: () => doctype_default2\n});\nvar UIStrings94, str_74, Doctype2, doctype_default2;\nvar init_doctype2 = __esm({\n  \"core/audits/dobetterweb/doctype.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_audit();\n    init_i18n();\n    init_processed_trace();\n    /**\n     * @license\n     * Copyright 2018 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    UIStrings94 = {\n      /** Title of a Lighthouse audit that provides detail on the doctype of a page. This descriptive title is shown to users when the pages's doctype is set to HTML. */\n      title: \"Page has the HTML doctype\",\n      /** Title of a Lighthouse audit that provides detail on the doctype of a page. This descriptive title is shown to users when the page's doctype is not set to HTML. */\n      failureTitle: \"Page lacks the HTML doctype, thus triggering quirks-mode\",\n      /** Description of a Lighthouse audit that tells the user why they should define an HTML doctype. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */\n      description: \"Specifying a doctype prevents the browser from switching to quirks-mode. [Learn more about the doctype declaration](https://developer.chrome.com/docs/lighthouse/best-practices/doctype/).\",\n      /** Explanatory message stating that the document has no doctype. */\n      explanationNoDoctype: \"Document must contain a doctype\",\n      /** Explanatory message stating that the document has wrong doctype that triggers `quirks-mode` */\n      explanationWrongDoctype: \"Document contains a `doctype` that triggers `quirks-mode`\",\n      /** Explanatory message stating that the document has wrong doctype that triggers `limited-quirks-mode` */\n      explanationLimitedQuirks: \"Document contains a `doctype` that triggers `limited-quirks-mode`\",\n      /** Explanatory message stating that the publicId field is not empty. */\n      explanationPublicId: \"Expected publicId to be an empty string\",\n      /** Explanatory message stating that the systemId field is not empty. */\n      explanationSystemId: \"Expected systemId to be an empty string\",\n      /** Explanatory message stating that the doctype is set, but is not \"html\" and is therefore invalid. */\n      explanationBadDoctype: \"Doctype name must be the string `html`\"\n    };\n    str_74 = createIcuMessageFn({ url: \"core/audits/dobetterweb/doctype.js\" }.url, UIStrings94);\n    Doctype2 = class extends Audit {\n      static {\n        __name(this, \"Doctype\");\n      }\n      /**\n       * @return {LH.Audit.Meta}\n       */\n      static get meta() {\n        return {\n          id: \"doctype\",\n          title: str_74(UIStrings94.title),\n          failureTitle: str_74(UIStrings94.failureTitle),\n          description: str_74(UIStrings94.description),\n          requiredArtifacts: [\"Doctype\"],\n          __internalOptionalArtifacts: [\"InspectorIssues\", \"Trace\"]\n        };\n      }\n      /**\n       * @param {LH.Artifacts} artifacts\n       * @param {LH.Audit.Context} context\n       * @return {Promise<LH.Audit.Product>}\n       */\n      static async audit(artifacts, context) {\n        if (!artifacts.Doctype) {\n          return {\n            score: 0,\n            explanation: str_74(UIStrings94.explanationNoDoctype)\n          };\n        }\n        const doctypeName = artifacts.Doctype.name;\n        const doctypePublicId = artifacts.Doctype.publicId;\n        const doctypeSystemId = artifacts.Doctype.systemId;\n        const compatMode = artifacts.Doctype.documentCompatMode;\n        const trace = artifacts.Trace;\n        let quirksModeIssues = [];\n        if (trace && artifacts.InspectorIssues?.quirksModeIssue) {\n          const processedTrace = await ProcessedTraceComputed.request(trace, context);\n          const mainFrameId2 = processedTrace.mainFrameInfo.frameId;\n          quirksModeIssues = artifacts.InspectorIssues.quirksModeIssue.filter((issue) => issue.frameId === mainFrameId2);\n        }\n        const isLimitedQuirksMode = quirksModeIssues.some((issue) => issue.isLimitedQuirksMode);\n        if (compatMode === \"CSS1Compat\" && !isLimitedQuirksMode) {\n          return {\n            score: 1\n          };\n        }\n        if (isLimitedQuirksMode) {\n          return {\n            score: 0,\n            explanation: str_74(UIStrings94.explanationLimitedQuirks)\n          };\n        }\n        if (doctypePublicId !== \"\") {\n          return {\n            score: 0,\n            explanation: str_74(UIStrings94.explanationPublicId)\n          };\n        }\n        if (doctypeSystemId !== \"\") {\n          return {\n            score: 0,\n            explanation: str_74(UIStrings94.explanationSystemId)\n          };\n        }\n        if (doctypeName !== \"html\") {\n          return {\n            score: 0,\n            explanation: str_74(UIStrings94.explanationBadDoctype)\n          };\n        }\n        return {\n          score: 0,\n          explanation: str_74(UIStrings94.explanationWrongDoctype)\n        };\n      }\n    };\n    doctype_default2 = Doctype2;\n  }\n});\n\n// core/audits/violation-audit.js\nvar ViolationAudit, violation_audit_default;\nvar init_violation_audit = __esm({\n  \"core/audits/violation-audit.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_audit();\n    init_js_bundles();\n    /**\n     * @license\n     * Copyright 2017 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    ViolationAudit = class extends Audit {\n      static {\n        __name(this, \"ViolationAudit\");\n      }\n      /**\n       * @param {LH.Artifacts} artifacts\n       * @param {LH.Audit.Context} context\n       * @param {RegExp} pattern\n       * @return {Promise<Array<{source: LH.Audit.Details.SourceLocationValue}>>}\n       */\n      static async getViolationResults(artifacts, context, pattern) {\n        const bundles = await JSBundlesComputed.request(artifacts, context);\n        function filterUndefined(value) {\n          return value !== void 0;\n        }\n        __name(filterUndefined, \"filterUndefined\");\n        const seen = /* @__PURE__ */ new Set();\n        return artifacts.ConsoleMessages.filter((entry) => entry.url && entry.source === \"violation\" && pattern.test(entry.text)).map((entry) => {\n          const bundle = bundles.find((bundle2) => bundle2.script.scriptId === entry.scriptId);\n          return Audit.makeSourceLocationFromConsoleMessage(entry, bundle);\n        }).filter(filterUndefined).filter((source) => {\n          const key = `${source.url}!${source.line}!${source.column}`;\n          if (seen.has(key)) return false;\n          seen.add(key);\n          return true;\n        }).map((source) => ({ source }));\n      }\n    };\n    violation_audit_default = ViolationAudit;\n  }\n});\n\n// core/audits/dobetterweb/geolocation-on-start.js\nvar geolocation_on_start_exports = {};\n__export(geolocation_on_start_exports, {\n  UIStrings: () => UIStrings95,\n  default: () => geolocation_on_start_default\n});\nvar UIStrings95, str_75, GeolocationOnStart, geolocation_on_start_default;\nvar init_geolocation_on_start = __esm({\n  \"core/audits/dobetterweb/geolocation-on-start.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_violation_audit();\n    init_i18n();\n    /**\n     * @license\n     * Copyright 2016 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    UIStrings95 = {\n      /** Title of a Lighthouse audit that provides detail on geolocation permission requests while the page is loading. This descriptive title is shown to users when the page does not ask for geolocation permissions on load. */\n      title: \"Avoids requesting the geolocation permission on page load\",\n      /** Title of a Lighthouse audit that provides detail on geolocation permissions requests. This descriptive title is shown to users when the page does ask for geolocation permissions on load. */\n      failureTitle: \"Requests the geolocation permission on page load\",\n      /** Description of a Lighthouse audit that tells the user why they should not ask for geolocation permissions on load. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */\n      description: \"Users are mistrustful of or confused by sites that request their location without context. Consider tying the request to a user action instead. [Learn more about the geolocation permission](https://developer.chrome.com/docs/lighthouse/best-practices/geolocation-on-start/).\"\n    };\n    str_75 = createIcuMessageFn({ url: \"core/audits/dobetterweb/geolocation-on-start.js\" }.url, UIStrings95);\n    GeolocationOnStart = class extends violation_audit_default {\n      static {\n        __name(this, \"GeolocationOnStart\");\n      }\n      /**\n       * @return {LH.Audit.Meta}\n       */\n      static get meta() {\n        return {\n          id: \"geolocation-on-start\",\n          title: str_75(UIStrings95.title),\n          failureTitle: str_75(UIStrings95.failureTitle),\n          description: str_75(UIStrings95.description),\n          supportedModes: [\"navigation\"],\n          requiredArtifacts: [\"ConsoleMessages\", \"SourceMaps\", \"Scripts\"]\n        };\n      }\n      /**\n       * @param {LH.Artifacts} artifacts\n       * @param {LH.Audit.Context} context\n       * @return {Promise<LH.Audit.Product>}\n       */\n      static async audit(artifacts, context) {\n        const results = await violation_audit_default.getViolationResults(artifacts, context, /geolocation/);\n        const headings = [\n          { key: \"source\", valueType: \"source-location\", label: str_75(UIStrings.columnSource) }\n        ];\n        const details = violation_audit_default.makeTableDetails(headings, results);\n        return {\n          score: Number(results.length === 0),\n          details\n        };\n      }\n    };\n    geolocation_on_start_default = GeolocationOnStart;\n  }\n});\n\n// core/audits/dobetterweb/inspector-issues.js\nvar inspector_issues_exports2 = {};\n__export(inspector_issues_exports2, {\n  UIStrings: () => UIStrings96,\n  default: () => inspector_issues_default2\n});\nvar UIStrings96, str_76, IssuesPanelEntries, inspector_issues_default2;\nvar init_inspector_issues2 = __esm({\n  \"core/audits/dobetterweb/inspector-issues.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_audit();\n    init_i18n();\n    /**\n     * @license\n     * Copyright 2020 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    UIStrings96 = {\n      /** Title of a Lighthouse audit that provides detail on various types of problems with a website, like security or network errors. This descriptive title is shown to users when no issues were logged into the Chrome DevTools Issues panel. */\n      title: \"No issues in the `Issues` panel in Chrome Devtools\",\n      /** Title of a Lighthouse audit that provides detail on various types of problems with a website, like security or network errors. This descriptive title is shown to users when issues are detected and logged into the Chrome DevTools Issues panel. */\n      failureTitle: \"Issues were logged in the `Issues` panel in Chrome Devtools\",\n      /* eslint-disable max-len */\n      /** Description of a Lighthouse audit that tells the user why issues being logged to the Chrome DevTools Issues panel are a cause for concern and so should be fixed. This is displayed after a user expands the section to see more. No character length limits. */\n      description: \"Issues logged to the `Issues` panel in Chrome Devtools indicate unresolved problems. They can come from network request failures, insufficient security controls, and other browser concerns. Open up the Issues panel in Chrome DevTools for more details on each issue.\",\n      /* eslint-enable max-len */\n      /** Table column header for the types of problems observed in a website, like security or network errors. */\n      columnIssueType: \"Issue type\",\n      /** The type of an Issue in Chrome DevTools when a resource is blocked due to the website's cross-origin policy. */\n      issueTypeBlockedByResponse: \"Blocked by cross-origin policy\",\n      /** The type of an Issue in Chrome DevTools when a site has large ads that use up a lot of the browser's resources. */\n      issueTypeHeavyAds: \"Heavy resource usage by ads\"\n    };\n    str_76 = createIcuMessageFn({ url: \"core/audits/dobetterweb/inspector-issues.js\" }.url, UIStrings96);\n    IssuesPanelEntries = class extends Audit {\n      static {\n        __name(this, \"IssuesPanelEntries\");\n      }\n      /**\n       * @return {LH.Audit.Meta}\n       */\n      static get meta() {\n        return {\n          id: \"inspector-issues\",\n          title: str_76(UIStrings96.title),\n          failureTitle: str_76(UIStrings96.failureTitle),\n          description: str_76(UIStrings96.description),\n          requiredArtifacts: [\"InspectorIssues\"]\n        };\n      }\n      /**\n       * @param {Array<LH.Crdp.Audits.MixedContentIssueDetails>} mixedContentIssues\n       * @return {LH.Audit.Details.TableItem}\n       */\n      static getMixedContentRow(mixedContentIssues) {\n        const requestUrls = /* @__PURE__ */ new Set();\n        for (const issue of mixedContentIssues) {\n          const requestUrl = issue.request?.url || issue.mainResourceURL;\n          requestUrls.add(requestUrl);\n        }\n        return {\n          issueType: \"Mixed content\",\n          subItems: {\n            type: \"subitems\",\n            items: Array.from(requestUrls).map((url) => ({ url }))\n          }\n        };\n      }\n      /**\n       * @param {Array<LH.Crdp.Audits.CookieIssueDetails>} CookieIssues\n       * @return {LH.Audit.Details.TableItem}\n       */\n      static getCookieRow(CookieIssues) {\n        const requestUrls = /* @__PURE__ */ new Set();\n        for (const issue of CookieIssues) {\n          const requestUrl = issue.request?.url || issue.cookieUrl;\n          if (requestUrl) {\n            requestUrls.add(requestUrl);\n          }\n        }\n        return {\n          issueType: \"Cookie\",\n          subItems: {\n            type: \"subitems\",\n            items: Array.from(requestUrls).map((url) => {\n              return {\n                url\n              };\n            })\n          }\n        };\n      }\n      /**\n       * @param {Array<LH.Crdp.Audits.BlockedByResponseIssueDetails>} blockedByResponseIssues\n       * @return {LH.Audit.Details.TableItem}\n       */\n      static getBlockedByResponseRow(blockedByResponseIssues) {\n        const requestUrls = /* @__PURE__ */ new Set();\n        for (const issue of blockedByResponseIssues) {\n          const requestUrl = issue.request?.url;\n          if (requestUrl) {\n            requestUrls.add(requestUrl);\n          }\n        }\n        return {\n          issueType: str_76(UIStrings96.issueTypeBlockedByResponse),\n          subItems: {\n            type: \"subitems\",\n            items: Array.from(requestUrls).map((url) => {\n              return {\n                url\n              };\n            })\n          }\n        };\n      }\n      /**\n       * @param {Array<LH.Crdp.Audits.ContentSecurityPolicyIssueDetails>} cspIssues\n       * @return {LH.Audit.Details.TableItem}\n       */\n      static getContentSecurityPolicyRow(cspIssues) {\n        const requestUrls = /* @__PURE__ */ new Set();\n        for (const issue of cspIssues) {\n          const requestUrl = issue.blockedURL;\n          if (requestUrl) {\n            requestUrls.add(requestUrl);\n          }\n        }\n        return {\n          issueType: \"Content security policy\",\n          subItems: {\n            type: \"subitems\",\n            items: Array.from(requestUrls).map((url) => {\n              return {\n                url\n              };\n            })\n          }\n        };\n      }\n      /**\n       * @param {LH.Artifacts} artifacts\n       * @return {LH.Audit.Product}\n       */\n      static audit(artifacts) {\n        const headings = [\n          /* eslint-disable max-len */\n          { key: \"issueType\", valueType: \"text\", subItemsHeading: { key: \"url\", valueType: \"url\" }, label: str_76(UIStrings96.columnIssueType) }\n          /* eslint-enable max-len */\n        ];\n        const issues = artifacts.InspectorIssues;\n        const items = [];\n        if (issues.mixedContentIssue?.length) {\n          items.push(this.getMixedContentRow(issues.mixedContentIssue));\n        }\n        if (issues.cookieIssue?.length) {\n          items.push(this.getCookieRow(issues.cookieIssue));\n        }\n        if (issues.blockedByResponseIssue?.length) {\n          items.push(this.getBlockedByResponseRow(issues.blockedByResponseIssue));\n        }\n        if (issues.heavyAdIssue?.length) {\n          items.push({ issueType: str_76(UIStrings96.issueTypeHeavyAds) });\n        }\n        if (issues.contentSecurityPolicyIssue?.length) {\n          items.push(this.getContentSecurityPolicyRow(issues.contentSecurityPolicyIssue));\n        }\n        return {\n          score: items.length > 0 ? 0 : 1,\n          details: Audit.makeTableDetails(headings, items)\n        };\n      }\n    };\n    inspector_issues_default2 = IssuesPanelEntries;\n  }\n});\n\n// core/audits/dobetterweb/js-libraries.js\nvar js_libraries_exports = {};\n__export(js_libraries_exports, {\n  UIStrings: () => UIStrings97,\n  default: () => js_libraries_default\n});\nvar UIStrings97, str_77, JsLibrariesAudit, js_libraries_default;\nvar init_js_libraries = __esm({\n  \"core/audits/dobetterweb/js-libraries.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_audit();\n    init_i18n();\n    /**\n     * @license\n     * Copyright 2017 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    UIStrings97 = {\n      /** Title of a Lighthouse audit that provides detail on the Javascript libraries that are used on the page. */\n      title: \"Detected JavaScript libraries\",\n      /** Description of a Lighthouse audit that tells the user what this audit is detecting. This is displayed after a user expands the section to see more. No character length limits. */\n      description: \"All front-end JavaScript libraries detected on the page. [Learn more about this JavaScript library detection diagnostic audit](https://developer.chrome.com/docs/lighthouse/best-practices/js-libraries/).\",\n      /** Label for a column in a data table; entries will be the version numbers of the detected Javascript libraries.  */\n      columnVersion: \"Version\"\n    };\n    str_77 = createIcuMessageFn({ url: \"core/audits/dobetterweb/js-libraries.js\" }.url, UIStrings97);\n    JsLibrariesAudit = class extends Audit {\n      static {\n        __name(this, \"JsLibrariesAudit\");\n      }\n      /**\n       * @return {LH.Audit.Meta}\n       */\n      static get meta() {\n        return {\n          id: \"js-libraries\",\n          title: str_77(UIStrings97.title),\n          scoreDisplayMode: Audit.SCORING_MODES.INFORMATIVE,\n          description: str_77(UIStrings97.description),\n          requiredArtifacts: [\"Stacks\"]\n        };\n      }\n      /**\n       * @param {LH.Artifacts} artifacts\n       * @return {LH.Audit.Product}\n       */\n      static audit(artifacts) {\n        const libDetails = artifacts.Stacks.filter((stack) => stack.detector === \"js\").filter((stack) => !stack.id.endsWith(\"-fast\")).map((stack) => ({\n          name: stack.name,\n          version: stack.version,\n          npm: stack.npm\n        }));\n        const headings = [\n          { key: \"name\", valueType: \"text\", label: str_77(UIStrings.columnName) },\n          { key: \"version\", valueType: \"text\", label: str_77(UIStrings97.columnVersion) }\n        ];\n        const details = Audit.makeTableDetails(headings, libDetails);\n        const debugData = {\n          type: (\n            /** @type {const} */\n            \"debugdata\"\n          ),\n          stacks: artifacts.Stacks.map((stack) => {\n            return {\n              id: stack.id,\n              version: stack.version\n            };\n          })\n        };\n        if (!libDetails.length) {\n          return { score: null, notApplicable: true };\n        }\n        return {\n          score: 1,\n          // Always pass for now.\n          details: {\n            ...details,\n            debugData\n          }\n        };\n      }\n    };\n    js_libraries_default = JsLibrariesAudit;\n  }\n});\n\n// core/audits/dobetterweb/notification-on-start.js\nvar notification_on_start_exports = {};\n__export(notification_on_start_exports, {\n  UIStrings: () => UIStrings98,\n  default: () => notification_on_start_default\n});\nvar UIStrings98, str_78, NotificationOnStart, notification_on_start_default;\nvar init_notification_on_start = __esm({\n  \"core/audits/dobetterweb/notification-on-start.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_violation_audit();\n    init_i18n();\n    /**\n     * @license\n     * Copyright 2016 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    UIStrings98 = {\n      /** Title of a Lighthouse audit that provides detail on the page's notification permission requests. This descriptive title is shown to users when the page does not ask for notification permission on load. */\n      title: \"Avoids requesting the notification permission on page load\",\n      /** Title of a Lighthouse audit that provides detail on the page's notification permission requests. This descriptive title is shown to users when the page does ask for notification permission on load. */\n      failureTitle: \"Requests the notification permission on page load\",\n      /** Description of a Lighthouse audit that tells the user why they should not ask for notification permission on load. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */\n      description: \"Users are mistrustful of or confused by sites that request to send notifications without context. Consider tying the request to user gestures instead. [Learn more about responsibly getting permission for notifications](https://developer.chrome.com/docs/lighthouse/best-practices/notification-on-start/).\"\n    };\n    str_78 = createIcuMessageFn({ url: \"core/audits/dobetterweb/notification-on-start.js\" }.url, UIStrings98);\n    NotificationOnStart = class extends violation_audit_default {\n      static {\n        __name(this, \"NotificationOnStart\");\n      }\n      /**\n       * @return {LH.Audit.Meta}\n       */\n      static get meta() {\n        return {\n          id: \"notification-on-start\",\n          title: str_78(UIStrings98.title),\n          failureTitle: str_78(UIStrings98.failureTitle),\n          description: str_78(UIStrings98.description),\n          supportedModes: [\"navigation\"],\n          requiredArtifacts: [\"ConsoleMessages\", \"SourceMaps\", \"Scripts\"]\n        };\n      }\n      /**\n       * @param {LH.Artifacts} artifacts\n       * @param {LH.Audit.Context} context\n       * @return {Promise<LH.Audit.Product>}\n       */\n      static async audit(artifacts, context) {\n        const results = await violation_audit_default.getViolationResults(artifacts, context, /notification permission/);\n        const headings = [\n          { key: \"source\", valueType: \"source-location\", label: str_78(UIStrings.columnSource) }\n        ];\n        const details = violation_audit_default.makeTableDetails(headings, results);\n        return {\n          score: Number(results.length === 0),\n          details\n        };\n      }\n    };\n    notification_on_start_default = NotificationOnStart;\n  }\n});\n\n// core/audits/dobetterweb/paste-preventing-inputs.js\nvar paste_preventing_inputs_exports = {};\n__export(paste_preventing_inputs_exports, {\n  UIStrings: () => UIStrings99,\n  default: () => paste_preventing_inputs_default\n});\nvar UIStrings99, str_79, PastePreventingInputsAudit, paste_preventing_inputs_default;\nvar init_paste_preventing_inputs = __esm({\n  \"core/audits/dobetterweb/paste-preventing-inputs.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_audit();\n    init_i18n();\n    /**\n     * @license\n     * Copyright 2023 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    UIStrings99 = {\n      /** Title of a Lighthouse audit that provides detail on the ability to paste into input fields. This descriptive title is shown to users when the page allows pasting of content into input fields. */\n      title: \"Allows users to paste into input fields\",\n      /** Title of a Lighthouse audit that provides detail on the ability to paste into input fields. This descriptive title is shown to users when the page does not allow pasting of content into input fields. */\n      failureTitle: \"Prevents users from pasting into input fields\",\n      /** Description of a Lighthouse audit that tells the user why they should allow pasting of content into input fields. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */\n      description: \"Preventing input pasting is a bad practice for the UX, and weakens security by blocking password managers.[Learn more about user-friendly input fields](https://developer.chrome.com/docs/lighthouse/best-practices/paste-preventing-inputs/).\"\n    };\n    str_79 = createIcuMessageFn({ url: \"core/audits/dobetterweb/paste-preventing-inputs.js\" }.url, UIStrings99);\n    PastePreventingInputsAudit = class extends Audit {\n      static {\n        __name(this, \"PastePreventingInputsAudit\");\n      }\n      /**\n       * @return {LH.Audit.Meta}\n       */\n      static get meta() {\n        return {\n          id: \"paste-preventing-inputs\",\n          title: str_79(UIStrings99.title),\n          failureTitle: str_79(UIStrings99.failureTitle),\n          description: str_79(UIStrings99.description),\n          requiredArtifacts: [\"Inputs\"]\n        };\n      }\n      /**\n       * @param {LH.Artifacts} artifacts\n       * @return {LH.Audit.Product}\n       */\n      static audit(artifacts) {\n        const inputsWithPreventsPaste = artifacts.Inputs.inputs.filter((input) => input.preventsPaste);\n        const items = [];\n        inputsWithPreventsPaste.forEach((input) => {\n          items.push({\n            node: Audit.makeNodeItem(input.node),\n            type: input.type\n          });\n        });\n        const headings = [\n          { key: \"node\", valueType: \"node\", label: str_79(UIStrings.columnFailingElem) }\n        ];\n        return {\n          score: Number(inputsWithPreventsPaste.length === 0),\n          details: Audit.makeTableDetails(headings, items)\n        };\n      }\n    };\n    paste_preventing_inputs_default = PastePreventingInputsAudit;\n  }\n});\n\n// core/audits/errors-in-console.js\nvar errors_in_console_exports = {};\n__export(errors_in_console_exports, {\n  UIStrings: () => UIStrings100,\n  default: () => errors_in_console_default\n});\nvar KB, MAX_CONSOLE_ERRORS, UIStrings100, str_80, ErrorLogs, errors_in_console_default;\nvar init_errors_in_console = __esm({\n  \"core/audits/errors-in-console.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_lighthouse_logger();\n    init_audit();\n    init_js_bundles();\n    init_i18n();\n    init_util();\n    /**\n     * @license\n     * Copyright 2017 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    KB = 1024;\n    MAX_CONSOLE_ERRORS = 1e3;\n    UIStrings100 = {\n      /** Title of a Lighthouse audit that provides detail on browser errors. This descriptive title is shown to users when no browser errors were logged into the devtools console. */\n      title: \"No browser errors logged to the console\",\n      /** Title of a Lighthouse audit that provides detail on browser errors. This descriptive title is shown to users when browser errors occurred and were logged into the devtools console. */\n      failureTitle: \"Browser errors were logged to the console\",\n      /** Description of a Lighthouse audit that tells the user why errors being logged to the devtools console are a cause for concern and so should be fixed. This is displayed after a user expands the section to see more. No character length limits. */\n      description: \"Errors logged to the console indicate unresolved problems. They can come from network request failures and other browser concerns. [Learn more about this errors in console diagnostic audit](https://developer.chrome.com/docs/lighthouse/best-practices/errors-in-console/)\"\n    };\n    str_80 = createIcuMessageFn({ url: \"core/audits/errors-in-console.js\" }.url, UIStrings100);\n    ErrorLogs = class _ErrorLogs extends Audit {\n      static {\n        __name(this, \"ErrorLogs\");\n      }\n      /**\n       * @return {LH.Audit.Meta}\n       */\n      static get meta() {\n        return {\n          id: \"errors-in-console\",\n          title: str_80(UIStrings100.title),\n          failureTitle: str_80(UIStrings100.failureTitle),\n          description: str_80(UIStrings100.description),\n          requiredArtifacts: [\"ConsoleMessages\", \"SourceMaps\", \"Scripts\"]\n        };\n      }\n      /** @return {AuditOptions} */\n      static get defaultOptions() {\n        return { ignoredPatterns: [\"ERR_BLOCKED_BY_CLIENT.Inspector\"] };\n      }\n      /**\n       * @template {{description: string | undefined}} T\n       * @param {Array<T>} items\n       * @param {AuditOptions} options\n       * @return {Array<T>}\n       */\n      static filterAccordingToOptions(items, options) {\n        const { ignoredPatterns, ...restOfOptions } = options;\n        const otherOptionKeys = Object.keys(restOfOptions);\n        if (otherOptionKeys.length) lighthouse_logger_default.warn(this.meta.id, \"Unrecognized options\", otherOptionKeys);\n        if (!ignoredPatterns) return items;\n        return items.filter(({ description }) => {\n          if (!description) return true;\n          for (const pattern of ignoredPatterns) {\n            if (pattern instanceof RegExp && pattern.test(description)) return false;\n            if (typeof pattern === \"string\" && description.includes(pattern)) return false;\n          }\n          return true;\n        });\n      }\n      /**\n       * @param {LH.Artifacts} artifacts\n       * @param {LH.Audit.Context} context\n       * @return {Promise<LH.Audit.Product>}\n       */\n      static async audit(artifacts, context) {\n        const auditOptions = context.options;\n        const bundles = await JSBundlesComputed.request(artifacts, context);\n        const consoleRows = artifacts.ConsoleMessages.filter((item) => item.level === \"error\").map((item) => {\n          const bundle = bundles.find((bundle2) => bundle2.script.scriptId === item.scriptId);\n          return {\n            source: item.source,\n            description: item.text ? Util.truncate(item.text, 10 * KB) : void 0,\n            sourceLocation: Audit.makeSourceLocationFromConsoleMessage(item, bundle)\n          };\n        }).slice(0, MAX_CONSOLE_ERRORS);\n        const tableRows = _ErrorLogs.filterAccordingToOptions(consoleRows, auditOptions).sort((a, b) => (a.description || \"\").localeCompare(b.description || \"\"));\n        const headings = [\n          /* eslint-disable max-len */\n          { key: \"sourceLocation\", valueType: \"source-location\", label: str_80(UIStrings.columnSource) },\n          { key: \"description\", valueType: \"code\", label: str_80(UIStrings.columnDescription) }\n          /* eslint-enable max-len */\n        ];\n        const details = Audit.makeTableDetails(headings, tableRows);\n        const numErrors = tableRows.length;\n        return {\n          score: Number(numErrors === 0),\n          details\n        };\n      }\n    };\n    errors_in_console_default = ErrorLogs;\n  }\n});\n\n// core/audits/has-hsts.js\nvar has_hsts_exports = {};\n__export(has_hsts_exports, {\n  UIStrings: () => UIStrings101,\n  default: () => has_hsts_default\n});\nvar UIStrings101, str_81, HasHsts, has_hsts_default;\nvar init_has_hsts = __esm({\n  \"core/audits/has-hsts.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_audit();\n    init_main_resource();\n    init_i18n();\n    /**\n     * @license\n     * Copyright 2024 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    UIStrings101 = {\n      /** Title of a Lighthouse audit that evaluates the security of a page's HSTS header. \"HSTS\" stands for \"HTTP Strict Transport Security\". */\n      title: \"Use a strong HSTS policy\",\n      /** Description of a Lighthouse audit that evaluates the security of a page's HSTS header. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. \"HSTS\" stands for \"HTTP Strict Transport Security\". */\n      description: \"Deployment of the HSTS header significantly reduces the risk of downgrading HTTP connections and eavesdropping attacks. A rollout in stages, starting with a low max-age is recommended. [Learn more about using a strong HSTS policy.](https://developer.chrome.com/docs/lighthouse/best-practices/has-hsts)\",\n      /** Summary text for the results of a Lighthouse audit that evaluates the HSTS header. This is displayed if no HSTS header is deployed. \"HSTS\" stands for \"HTTP Strict Transport Security\". */\n      noHsts: \"No HSTS header found\",\n      /** Summary text for the results of a Lighthouse audit that evaluates the HSTS header. This is displayed if the preload directive is missing. \"HSTS\" stands for \"HTTP Strict Transport Security\". */\n      noPreload: \"No `preload` directive found\",\n      /** Summary text for the results of a Lighthouse audit that evaluates the HSTS header. This is displayed if the includeSubDomains directive is missing. \"HSTS\" stands for \"HTTP Strict Transport Security\". */\n      noSubdomain: \"No `includeSubDomains` directive found\",\n      /** Summary text for the results of a Lighthouse audit that evaluates the HSTS header. This is displayed if the max-age directive is missing. \"HSTS\" stands for \"HTTP Strict Transport Security\". */\n      noMaxAge: \"No `max-age` directive\",\n      /** Summary text for the results of a Lighthouse audit that evaluates the HSTS header. This is displayed if the provided duration for the max-age directive is too low. \"HSTS\" stands for \"HTTP Strict Transport Security\". */\n      lowMaxAge: \"`max-age` is too low\",\n      /** Table item value calling out the presence of a syntax error. */\n      invalidSyntax: \"Invalid syntax\",\n      /** Label for a column in a data table; entries will be a directive of the HSTS header. \"HSTS\" stands for \"HTTP Strict Transport Security\". */\n      columnDirective: \"Directive\",\n      /** Label for a column in a data table; entries will be the severity of an issue with the HSTS header. \"HSTS\" stands for \"HTTP Strict Transport Security\". */\n      columnSeverity: \"Severity\"\n    };\n    str_81 = createIcuMessageFn({ url: \"core/audits/has-hsts.js\" }.url, UIStrings101);\n    HasHsts = class extends Audit {\n      static {\n        __name(this, \"HasHsts\");\n      }\n      /**\n       * @return {LH.Audit.Meta}\n       */\n      static get meta() {\n        return {\n          id: \"has-hsts\",\n          scoreDisplayMode: Audit.SCORING_MODES.INFORMATIVE,\n          title: str_81(UIStrings101.title),\n          description: str_81(UIStrings101.description),\n          requiredArtifacts: [\"DevtoolsLog\", \"URL\"],\n          supportedModes: [\"navigation\"]\n        };\n      }\n      /**\n       * @param {LH.Artifacts} artifacts\n       * @param {LH.Audit.Context} context\n       * @return {Promise<string[]>}\n       */\n      static async getRawHsts(artifacts, context) {\n        const devtoolsLog = artifacts.DevtoolsLog;\n        const mainResource = await MainResourceComputed.request({ devtoolsLog, URL: artifacts.URL }, context);\n        let hstsHeaders = mainResource.responseHeaders.filter((h) => {\n          return h.name.toLowerCase() === \"strict-transport-security\";\n        }).flatMap((h) => h.value.split(\";\"));\n        hstsHeaders = hstsHeaders.map((v) => v.toLowerCase().replace(/\\s/g, \"\"));\n        return hstsHeaders;\n      }\n      /**\n       * @param {string} hstsDirective\n       * @param {LH.IcuMessage | string} findingDescription\n       * @param {LH.IcuMessage=} severity\n       * @return {LH.Audit.Details.TableItem}\n       */\n      static findingToTableItem(hstsDirective, findingDescription, severity) {\n        return {\n          directive: hstsDirective,\n          description: findingDescription,\n          severity\n        };\n      }\n      /**\n       * @param {string[]} hstsHeaders\n       * @return {{score: number, results: LH.Audit.Details.TableItem[]}}\n       */\n      static constructResults(hstsHeaders) {\n        const rawHsts = [...hstsHeaders];\n        const allowedDirectives = [\"max-age\", \"includesubdomains\", \"preload\"];\n        const violations = [];\n        const warnings = [];\n        const syntax = [];\n        if (!rawHsts.length) {\n          return {\n            score: 0,\n            results: [{\n              severity: str_81(UIStrings.itemSeverityHigh),\n              description: str_81(UIStrings101.noHsts),\n              directive: void 0\n            }]\n          };\n        }\n        if (!hstsHeaders.toString().includes(\"max-age\")) {\n          violations.push({\n            severity: str_81(UIStrings.itemSeverityHigh),\n            description: str_81(UIStrings101.noMaxAge),\n            directive: \"max-age\"\n          });\n        }\n        if (!hstsHeaders.toString().includes(\"includesubdomains\")) {\n          warnings.push({\n            severity: str_81(UIStrings.itemSeverityMedium),\n            description: str_81(UIStrings101.noSubdomain),\n            directive: \"includeSubDomains\"\n          });\n        }\n        if (!hstsHeaders.toString().includes(\"preload\")) {\n          warnings.push({\n            severity: str_81(UIStrings.itemSeverityMedium),\n            description: str_81(UIStrings101.noPreload),\n            directive: \"preload\"\n          });\n        }\n        for (const actualDirective of hstsHeaders) {\n          if (actualDirective.includes(\"max-age\") && parseInt(actualDirective.split(\"=\")[1], 10) < 31536e3) {\n            violations.push({\n              severity: str_81(UIStrings.itemSeverityHigh),\n              description: str_81(UIStrings101.lowMaxAge),\n              directive: \"max-age\"\n            });\n          }\n          if (!allowedDirectives.includes(actualDirective) && !actualDirective.includes(\"max-age\")) {\n            syntax.push({\n              severity: str_81(UIStrings.itemSeverityLow),\n              description: str_81(UIStrings101.invalidSyntax),\n              directive: actualDirective\n            });\n          }\n        }\n        const results = [\n          ...violations.map(\n            (f) => this.findingToTableItem(\n              f.directive,\n              f.description,\n              str_81(UIStrings.itemSeverityHigh)\n            )\n          ),\n          ...warnings.map(\n            (f) => this.findingToTableItem(\n              f.directive,\n              f.description,\n              str_81(UIStrings.itemSeverityMedium)\n            )\n          ),\n          ...syntax.map(\n            (f) => this.findingToTableItem(\n              f.directive,\n              f.description,\n              str_81(UIStrings.itemSeverityLow)\n            )\n          )\n        ];\n        return { score: violations.length || syntax.length ? 0 : 1, results };\n      }\n      /**\n       * @param {LH.Artifacts} artifacts\n       * @param {LH.Audit.Context} context\n       * @return {Promise<LH.Audit.Product>}\n       */\n      static async audit(artifacts, context) {\n        const hstsHeaders = await this.getRawHsts(artifacts, context);\n        const { score, results } = this.constructResults(hstsHeaders);\n        const headings = [\n          /* eslint-disable max-len */\n          { key: \"description\", valueType: \"text\", subItemsHeading: { key: \"description\" }, label: str_81(UIStrings.columnDescription) },\n          { key: \"directive\", valueType: \"code\", subItemsHeading: { key: \"directive\" }, label: str_81(UIStrings101.columnDirective) },\n          { key: \"severity\", valueType: \"text\", subItemsHeading: { key: \"severity\" }, label: str_81(UIStrings101.columnSeverity) }\n          /* eslint-enable max-len */\n        ];\n        const details = Audit.makeTableDetails(headings, results);\n        return {\n          score,\n          notApplicable: !results.length,\n          details\n        };\n      }\n    };\n    has_hsts_default = HasHsts;\n  }\n});\n\n// core/audits/image-aspect-ratio.js\nvar image_aspect_ratio_exports = {};\n__export(image_aspect_ratio_exports, {\n  UIStrings: () => UIStrings102,\n  default: () => image_aspect_ratio_default\n});\nvar UIStrings102, str_82, THRESHOLD_PX, ImageAspectRatio, image_aspect_ratio_default;\nvar init_image_aspect_ratio = __esm({\n  \"core/audits/image-aspect-ratio.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_audit();\n    init_url_utils();\n    init_i18n();\n    /**\n     * @license\n     * Copyright 2017 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    UIStrings102 = {\n      /** Title of a Lighthouse audit that provides detail on the aspect ratios of all images on the page. This descriptive title is shown to users when all images use correct aspect ratios. */\n      title: \"Displays images with correct aspect ratio\",\n      /** Title of a Lighthouse audit that provides detail on the aspect ratios of all images on the page. This descriptive title is shown to users when not all images use correct aspect ratios. */\n      failureTitle: \"Displays images with incorrect aspect ratio\",\n      /** Description of a Lighthouse audit that tells the user why they should maintain the correct aspect ratios for all images. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */\n      description: \"Image display dimensions should match natural aspect ratio. [Learn more about image aspect ratio](https://developer.chrome.com/docs/lighthouse/best-practices/image-aspect-ratio/).\",\n      /**  Label for a column in a data table; entries in the column will be the numeric aspect ratio of an image as displayed in a web page. */\n      columnDisplayed: \"Aspect Ratio (Displayed)\",\n      /**  Label for a column in a data table; entries in the column will be the numeric aspect ratio of the raw (actual) image. */\n      columnActual: \"Aspect Ratio (Actual)\"\n    };\n    str_82 = createIcuMessageFn({ url: \"core/audits/image-aspect-ratio.js\" }.url, UIStrings102);\n    THRESHOLD_PX = 2;\n    ImageAspectRatio = class _ImageAspectRatio extends Audit {\n      static {\n        __name(this, \"ImageAspectRatio\");\n      }\n      /**\n       * @return {LH.Audit.Meta}\n       */\n      static get meta() {\n        return {\n          id: \"image-aspect-ratio\",\n          title: str_82(UIStrings102.title),\n          failureTitle: str_82(UIStrings102.failureTitle),\n          description: str_82(UIStrings102.description),\n          requiredArtifacts: [\"ImageElements\"]\n        };\n      }\n      /**\n       * @param {WellDefinedImage} image\n       * @return {{url: string, node: LH.Audit.Details.NodeValue, displayedAspectRatio: string, actualAspectRatio: string, doRatiosMatch: boolean}}\n       */\n      static computeAspectRatios(image) {\n        const url = url_utils_default.elideDataURI(image.src);\n        const actualAspectRatio = image.naturalDimensions.width / image.naturalDimensions.height;\n        const displayedAspectRatio = image.displayedWidth / image.displayedHeight;\n        const targetDisplayHeight = image.displayedWidth / actualAspectRatio;\n        const targetDisplayWidth = image.displayedHeight * actualAspectRatio;\n        const doRatiosMatch = targetDisplayHeight < targetDisplayWidth ? Math.abs(targetDisplayHeight - image.displayedHeight) < THRESHOLD_PX : Math.abs(targetDisplayWidth - image.displayedWidth) < THRESHOLD_PX;\n        return {\n          url,\n          node: Audit.makeNodeItem(image.node),\n          displayedAspectRatio: `${image.displayedWidth} x ${image.displayedHeight}\n        (${displayedAspectRatio.toFixed(2)})`,\n          actualAspectRatio: `${image.naturalDimensions.width} x ${image.naturalDimensions.height}\n        (${actualAspectRatio.toFixed(2)})`,\n          doRatiosMatch\n        };\n      }\n      /**\n       * @param {LH.Artifacts} artifacts\n       * @return {LH.Audit.Product}\n       */\n      static audit(artifacts) {\n        const images = artifacts.ImageElements;\n        const results = [];\n        images.filter((image) => {\n          return !image.isCss && url_utils_default.guessMimeType(image.src) !== \"image/svg+xml\" && image.naturalDimensions && image.naturalDimensions.height > 5 && image.naturalDimensions.width > 5 && image.displayedWidth && image.displayedHeight && image.computedStyles.objectFit === \"fill\";\n        }).forEach((image) => {\n          const wellDefinedImage = (\n            /** @type {WellDefinedImage} */\n            image\n          );\n          const processed = _ImageAspectRatio.computeAspectRatios(wellDefinedImage);\n          if (!processed.doRatiosMatch) results.push(processed);\n        });\n        const headings = [\n          { key: \"node\", valueType: \"node\", label: \"\" },\n          { key: \"url\", valueType: \"url\", label: str_82(UIStrings.columnURL) },\n          { key: \"displayedAspectRatio\", valueType: \"text\", label: str_82(UIStrings102.columnDisplayed) },\n          { key: \"actualAspectRatio\", valueType: \"text\", label: str_82(UIStrings102.columnActual) }\n        ];\n        return {\n          score: Number(results.length === 0),\n          details: Audit.makeTableDetails(headings, results)\n        };\n      }\n    };\n    image_aspect_ratio_default = ImageAspectRatio;\n  }\n});\n\n// core/computed/image-records.js\nvar ImageRecords, ImageRecordsComputed;\nvar init_image_records = __esm({\n  \"core/computed/image-records.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_url_utils();\n    init_computed_artifact();\n    /**\n     * @license\n     * Copyright 2021 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    ImageRecords = class _ImageRecords {\n      static {\n        __name(this, \"ImageRecords\");\n      }\n      /**\n       * @param {LH.Artifacts.NetworkRequest[]} networkRecords\n       */\n      static indexNetworkRecords(networkRecords) {\n        return networkRecords.reduce(\n          (map, record) => {\n            const isImage = /^image/.test(record.mimeType) || /\\.(avif|webp)$/i.test(record.url);\n            if (isImage && record.finished && record.statusCode === 200) {\n              map[record.url] = record;\n            }\n            return map;\n          },\n          /** @type {Record<string, LH.Artifacts.NetworkRequest>} */\n          {}\n        );\n      }\n      /**\n       * @param {{ImageElements: LH.Artifacts['ImageElements'], networkRecords: LH.Artifacts.NetworkRequest[]}} data\n       * @return {Promise<LH.Artifacts.ImageElementRecord[]>}\n       */\n      static async compute_(data31) {\n        const indexedNetworkRecords = _ImageRecords.indexNetworkRecords(data31.networkRecords);\n        const imageRecords = [];\n        for (const element of data31.ImageElements) {\n          const networkRecord = indexedNetworkRecords[element.src];\n          const mimeType = networkRecord?.mimeType;\n          imageRecords.push({\n            ...element,\n            mimeType: mimeType ? mimeType : url_utils_default.guessMimeType(element.src)\n          });\n        }\n        imageRecords.sort((a, b) => {\n          const aRecord = indexedNetworkRecords[a.src] || {};\n          const bRecord = indexedNetworkRecords[b.src] || {};\n          return bRecord.resourceSize - aRecord.resourceSize;\n        });\n        return imageRecords;\n      }\n    };\n    ImageRecordsComputed = makeComputedArtifact(ImageRecords, [\"ImageElements\", \"networkRecords\"]);\n  }\n});\n\n// core/audits/image-size-responsive.js\nvar image_size_responsive_exports = {};\n__export(image_size_responsive_exports, {\n  UIStrings: () => UIStrings103,\n  default: () => image_size_responsive_default\n});\nfunction isVisible(imageRect, viewportDimensions) {\n  return (imageRect.bottom - imageRect.top) * (imageRect.right - imageRect.left) > 0 && imageRect.top <= viewportDimensions.innerHeight && imageRect.bottom >= 0 && imageRect.left <= viewportDimensions.innerWidth && imageRect.right >= 0;\n}\nfunction isSmallerThanViewport(imageRect, viewportDimensions) {\n  return imageRect.bottom - imageRect.top <= viewportDimensions.innerHeight && imageRect.right - imageRect.left <= viewportDimensions.innerWidth;\n}\nfunction isCandidate(image, imageRecord) {\n  const artisticImageRenderingValues = [\"pixelated\", \"crisp-edges\"];\n  const densityDescriptorRegex = / \\d+(\\.\\d+)?x/;\n  if (image.displayedWidth <= 1 || image.displayedHeight <= 1) {\n    return false;\n  }\n  if (!image.naturalDimensions || !image.naturalDimensions.width || !image.naturalDimensions.height) {\n    return false;\n  }\n  if (imageRecord?.mimeType === \"image/svg+xml\") {\n    return false;\n  }\n  if (url_utils_default.guessMimeType(image.src) === \"image/svg+xml\") {\n    return false;\n  }\n  if (image.isCss) {\n    return false;\n  }\n  if (image.computedStyles.objectFit !== \"fill\") {\n    return false;\n  }\n  if (artisticImageRenderingValues.includes(image.computedStyles.imageRendering)) {\n    return false;\n  }\n  if (densityDescriptorRegex.test(image.srcset)) {\n    return false;\n  }\n  return true;\n}\nfunction imageHasNaturalDimensions(image) {\n  return !!image.naturalDimensions;\n}\nfunction imageHasRightSize(image, DPR) {\n  const [expectedWidth, expectedHeight] = allowedImageSize(image.displayedWidth, image.displayedHeight, DPR);\n  return image.naturalDimensions.width >= expectedWidth && image.naturalDimensions.height >= expectedHeight;\n}\nfunction getResult(image, DPR) {\n  const [expectedWidth, expectedHeight] = expectedImageSize(image.displayedWidth, image.displayedHeight, DPR);\n  return {\n    url: url_utils_default.elideDataURI(image.src),\n    node: Audit.makeNodeItem(image.node),\n    displayedSize: `${image.displayedWidth} x ${image.displayedHeight}`,\n    actualSize: `${image.naturalDimensions.width} x ${image.naturalDimensions.height}`,\n    actualPixels: image.naturalDimensions.width * image.naturalDimensions.height,\n    expectedSize: `${expectedWidth} x ${expectedHeight}`,\n    expectedPixels: expectedWidth * expectedHeight\n  };\n}\nfunction allowedImageSize(displayedWidth, displayedHeight, DPR) {\n  let factor = SMALL_IMAGE_FACTOR;\n  if (displayedWidth > SMALL_IMAGE_THRESHOLD || displayedHeight > SMALL_IMAGE_THRESHOLD) {\n    factor = LARGE_IMAGE_FACTOR;\n  }\n  const requiredDpr = quantizeDpr(DPR);\n  const width = Math.ceil(factor * requiredDpr * displayedWidth);\n  const height = Math.ceil(factor * requiredDpr * displayedHeight);\n  return [width, height];\n}\nfunction expectedImageSize(displayedWidth, displayedHeight, DPR) {\n  const width = Math.ceil(quantizeDpr(DPR) * displayedWidth);\n  const height = Math.ceil(quantizeDpr(DPR) * displayedHeight);\n  return [width, height];\n}\nfunction deduplicateResultsByUrl(results) {\n  results.sort((a, b) => a.url === b.url ? 0 : a.url < b.url ? -1 : 1);\n  const deduplicated = [];\n  for (const r of results) {\n    const previousResult = deduplicated[deduplicated.length - 1];\n    if (previousResult && previousResult.url === r.url) {\n      if (previousResult.expectedPixels < r.expectedPixels) {\n        deduplicated[deduplicated.length - 1] = r;\n      }\n    } else {\n      deduplicated.push(r);\n    }\n  }\n  return deduplicated;\n}\nfunction sortResultsBySizeDelta(results) {\n  return results.sort(\n    (a, b) => b.expectedPixels - b.actualPixels - (a.expectedPixels - a.actualPixels)\n  );\n}\nfunction quantizeDpr(dpr) {\n  if (dpr >= 2) {\n    return 2;\n  }\n  if (dpr >= 1.5) {\n    return 1.5;\n  }\n  return 1;\n}\nvar UIStrings103, str_83, SMALL_IMAGE_FACTOR, LARGE_IMAGE_FACTOR, SMALL_IMAGE_THRESHOLD, ImageSizeResponsive, image_size_responsive_default;\nvar init_image_size_responsive = __esm({\n  \"core/audits/image-size-responsive.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_audit();\n    init_image_records();\n    init_network_records();\n    init_url_utils();\n    init_i18n();\n    /**\n     * @license\n     * Copyright 2020 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    UIStrings103 = {\n      /** Title of a Lighthouse audit that provides detail on the size of visible images on the page. This descriptive title is shown to users when all images have correct sizes. */\n      title: \"Serves images with appropriate resolution\",\n      /** Title of a Lighthouse audit that provides detail on the size of visible images on the page. This descriptive title is shown to users when not all images have correct sizes. */\n      failureTitle: \"Serves images with low resolution\",\n      /** Description of a Lighthouse audit that tells the user why they should maintain an appropriate size for all images. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */\n      description: \"Image natural dimensions should be proportional to the display size and the pixel ratio to maximize image clarity. [Learn how to provide responsive images](https://web.dev/articles/serve-responsive-images).\",\n      /**  Label for a column in a data table; entries in the column will be a string representing the displayed size of the image. */\n      columnDisplayed: \"Displayed size\",\n      /**  Label for a column in a data table; entries in the column will be a string representing the actual size of the image. */\n      columnActual: \"Actual size\",\n      /**  Label for a column in a data table; entries in the column will be a string representing the expected size of the image. */\n      columnExpected: \"Expected size\"\n    };\n    str_83 = createIcuMessageFn({ url: \"core/audits/image-size-responsive.js\" }.url, UIStrings103);\n    SMALL_IMAGE_FACTOR = 1;\n    LARGE_IMAGE_FACTOR = 0.75;\n    SMALL_IMAGE_THRESHOLD = 64;\n    __name(isVisible, \"isVisible\");\n    __name(isSmallerThanViewport, \"isSmallerThanViewport\");\n    __name(isCandidate, \"isCandidate\");\n    __name(imageHasNaturalDimensions, \"imageHasNaturalDimensions\");\n    __name(imageHasRightSize, \"imageHasRightSize\");\n    __name(getResult, \"getResult\");\n    __name(allowedImageSize, \"allowedImageSize\");\n    __name(expectedImageSize, \"expectedImageSize\");\n    __name(deduplicateResultsByUrl, \"deduplicateResultsByUrl\");\n    __name(sortResultsBySizeDelta, \"sortResultsBySizeDelta\");\n    ImageSizeResponsive = class extends Audit {\n      static {\n        __name(this, \"ImageSizeResponsive\");\n      }\n      /**\n       * @return {LH.Audit.Meta}\n       */\n      static get meta() {\n        return {\n          id: \"image-size-responsive\",\n          title: str_83(UIStrings103.title),\n          failureTitle: str_83(UIStrings103.failureTitle),\n          description: str_83(UIStrings103.description),\n          requiredArtifacts: [\"ImageElements\", \"ViewportDimensions\"],\n          __internalOptionalArtifacts: [\"DevtoolsLog\"]\n        };\n      }\n      /**\n       * @param {LH.Artifacts} artifacts\n       * @param {LH.Audit.Context} context\n       * @return {Promise<LH.Audit.Product>}\n       */\n      static async audit(artifacts, context) {\n        const DPR = artifacts.ViewportDimensions.devicePixelRatio;\n        const imageRecordsByURL = /* @__PURE__ */ new Map();\n        if (artifacts.DevtoolsLog) {\n          const networkRecords = await NetworkRecordsComputed.request(artifacts.DevtoolsLog, context);\n          const images = await ImageRecordsComputed.request({\n            ImageElements: artifacts.ImageElements,\n            networkRecords\n          }, context);\n          images.forEach((img) => imageRecordsByURL.set(img.src, img));\n        }\n        const results = Array.from(artifacts.ImageElements).filter((image) => isCandidate(image, imageRecordsByURL.get(image.src))).filter(imageHasNaturalDimensions).filter((image) => !imageHasRightSize(image, DPR)).filter((image) => isVisible(image.clientRect, artifacts.ViewportDimensions)).filter((image) => isSmallerThanViewport(image.clientRect, artifacts.ViewportDimensions)).map((image) => getResult(image, DPR));\n        const headings = [\n          { key: \"node\", valueType: \"node\", label: \"\" },\n          { key: \"url\", valueType: \"url\", label: str_83(UIStrings.columnURL) },\n          { key: \"displayedSize\", valueType: \"text\", label: str_83(UIStrings103.columnDisplayed) },\n          { key: \"actualSize\", valueType: \"text\", label: str_83(UIStrings103.columnActual) },\n          { key: \"expectedSize\", valueType: \"text\", label: str_83(UIStrings103.columnExpected) }\n        ];\n        const finalResults = sortResultsBySizeDelta(deduplicateResultsByUrl(results));\n        return {\n          score: Number(results.length === 0),\n          details: Audit.makeTableDetails(headings, finalResults)\n        };\n      }\n    };\n    __name(quantizeDpr, \"quantizeDpr\");\n    image_size_responsive_default = ImageSizeResponsive;\n  }\n});\n\n// core/audits/is-on-https.js\nvar is_on_https_exports = {};\n__export(is_on_https_exports, {\n  UIStrings: () => UIStrings104,\n  default: () => is_on_https_default\n});\nvar UIStrings104, resolutionToString, str_84, HTTPS, is_on_https_default;\nvar init_is_on_https = __esm({\n  \"core/audits/is-on-https.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_audit();\n    init_url_utils();\n    init_network_request();\n    init_network_records();\n    init_i18n();\n    /**\n     * @license\n     * Copyright 2016 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    UIStrings104 = {\n      /** Title of a Lighthouse audit that provides detail on the useage of HTTPS on a page. This descriptive title is shown to users when all requests on a page are fufilled using HTTPS. */\n      title: \"Uses HTTPS\",\n      /** Title of a Lighthouse audit that provides detail on the useage of HTTPS on a page. This descriptive title is shown to users when some, or all, requests on the page use HTTP instead of HTTPS. */\n      failureTitle: \"Does not use HTTPS\",\n      /** Description of a Lighthouse audit that tells the user *why* HTTPS use *for all resources* is important. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */\n      description: \"All sites should be protected with HTTPS, even ones that don't handle sensitive data. This includes avoiding [mixed content](https://developers.google.com/web/fundamentals/security/prevent-mixed-content/what-is-mixed-content), where some resources are loaded over HTTP despite the initial request being served over HTTPS. HTTPS prevents intruders from tampering with or passively listening in on the communications between your app and your users, and is a prerequisite for HTTP/2 and many new web platform APIs. [Learn more about HTTPS](https://developer.chrome.com/docs/lighthouse/pwa/is-on-https/).\",\n      /** [ICU Syntax] Label identifying the number of insecure network requests found by an audit of a web page. */\n      displayValue: `{itemCount, plural,\n    =1 {1 insecure request found}\n    other {# insecure requests found}\n    }`,\n      /** Label for a column in a data table; entries in the column will be the URLs of insecure (non-HTTPS) network requests. */\n      columnInsecureURL: \"Insecure URL\",\n      /** Label for a column in a data table; entries in the column will be how the browser handled insecure (non-HTTPS) network requests. */\n      columnResolution: \"Request Resolution\",\n      /** Value for the resolution column in a data table; denotes that the insecure URL was allowed by the browser. */\n      allowed: \"Allowed\",\n      /** Value for the resolution column in a data table; denotes that the insecure URL was blocked by the browser. */\n      blocked: \"Blocked\",\n      /** Value for the resolution column in a data table; denotes that the insecure URL may be blocked by the browser in the future. */\n      warning: \"Allowed with warning\",\n      /** Value for the resolution column in a data table; denotes that the insecure URL was upgraded to a secure request by the browser. */\n      upgraded: \"Automatically upgraded to HTTPS\"\n    };\n    resolutionToString = {\n      MixedContentAutomaticallyUpgraded: UIStrings104.upgraded,\n      MixedContentBlocked: UIStrings104.blocked,\n      MixedContentWarning: UIStrings104.warning\n    };\n    str_84 = createIcuMessageFn({ url: \"core/audits/is-on-https.js\" }.url, UIStrings104);\n    HTTPS = class extends Audit {\n      static {\n        __name(this, \"HTTPS\");\n      }\n      /**\n       * @return {LH.Audit.Meta}\n       */\n      static get meta() {\n        return {\n          id: \"is-on-https\",\n          title: str_84(UIStrings104.title),\n          failureTitle: str_84(UIStrings104.failureTitle),\n          description: str_84(UIStrings104.description),\n          requiredArtifacts: [\"DevtoolsLog\", \"InspectorIssues\"]\n        };\n      }\n      /**\n       * @param {LH.Artifacts} artifacts\n       * @param {LH.Audit.Context} context\n       * @return {Promise<LH.Audit.Product>}\n       */\n      static async audit(artifacts, context) {\n        const devtoolsLogs = artifacts.DevtoolsLog;\n        const networkRecords = await NetworkRecordsComputed.request(devtoolsLogs, context);\n        const insecureURLs = networkRecords.filter((record) => !NetworkRequest.isSecureRequest(record)).map((record) => url_utils_default.elideDataURI(record.url));\n        const items = Array.from(new Set(insecureURLs)).map((url) => ({ url, resolution: void 0 }));\n        const headings = [\n          { key: \"url\", valueType: \"url\", label: str_84(UIStrings104.columnInsecureURL) },\n          { key: \"resolution\", valueType: \"text\", label: str_84(UIStrings104.columnResolution) }\n        ];\n        for (const details of artifacts.InspectorIssues.mixedContentIssue ?? []) {\n          let item = items.find((item2) => item2.url === details.insecureURL);\n          if (!item) {\n            item = { url: details.insecureURL };\n            items.push(item);\n          }\n          item.resolution = resolutionToString[details.resolutionStatus] ? str_84(resolutionToString[details.resolutionStatus]) : details.resolutionStatus;\n        }\n        for (const item of items) {\n          if (!item.resolution) item.resolution = str_84(UIStrings104.allowed);\n        }\n        let displayValue;\n        if (items.length > 0) {\n          displayValue = str_84(UIStrings104.displayValue, { itemCount: items.length });\n        }\n        return {\n          score: Number(items.length === 0),\n          displayValue,\n          details: Audit.makeTableDetails(headings, items)\n        };\n      }\n    };\n    is_on_https_default = HTTPS;\n  }\n});\n\n// core/audits/origin-isolation.js\nvar origin_isolation_exports = {};\n__export(origin_isolation_exports, {\n  UIStrings: () => UIStrings105,\n  default: () => origin_isolation_default\n});\nvar UIStrings105, str_85, OriginIsolation, origin_isolation_default;\nvar init_origin_isolation = __esm({\n  \"core/audits/origin-isolation.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_audit();\n    init_main_resource();\n    init_i18n();\n    /**\n     * @license\n     * Copyright 2024 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    UIStrings105 = {\n      /** Title of a Lighthouse audit that evaluates the security of a page's COOP header for origin isolation. \"COOP\" stands for \"Cross-Origin-Opener-Policy\" and should not be translated. */\n      title: \"Ensure proper origin isolation with COOP\",\n      /** Description of a Lighthouse audit that evaluates the security of a page's COOP header for origin isolation. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. \"COOP\" stands for \"Cross-Origin-Opener-Policy\", neither should be translated. */\n      description: \"The Cross-Origin-Opener-Policy (COOP) can be used to isolate the top-level window from other documents such as pop-ups. [Learn more about deploying the COOP header.](https://web.dev/articles/why-coop-coep#coop)\",\n      /** Summary text for the results of a Lighthouse audit that evaluates the COOP header for origin isolation. This is displayed if no COOP header is deployed. \"COOP\" stands for \"Cross-Origin-Opener-Policy\" and should not be translated. */\n      noCoop: \"No COOP header found\",\n      /** Table item value calling out the presence of a syntax error. */\n      invalidSyntax: \"Invalid syntax\",\n      /** Label for a column in a data table; entries will be a directive of the COOP header. \"COOP\" stands for \"Cross-Origin-Opener-Policy\". */\n      columnDirective: \"Directive\",\n      /** Label for a column in a data table; entries will be the severity of an issue with the COOP header. \"COOP\" stands for \"Cross-Origin-Opener-Policy\". */\n      columnSeverity: \"Severity\"\n    };\n    str_85 = createIcuMessageFn({ url: \"core/audits/origin-isolation.js\" }.url, UIStrings105);\n    OriginIsolation = class extends Audit {\n      static {\n        __name(this, \"OriginIsolation\");\n      }\n      /**\n       * @return {LH.Audit.Meta}\n       */\n      static get meta() {\n        return {\n          id: \"origin-isolation\",\n          scoreDisplayMode: Audit.SCORING_MODES.INFORMATIVE,\n          title: str_85(UIStrings105.title),\n          description: str_85(UIStrings105.description),\n          requiredArtifacts: [\"DevtoolsLog\", \"URL\"],\n          supportedModes: [\"navigation\"]\n        };\n      }\n      /**\n       * @param {LH.Artifacts} artifacts\n       * @param {LH.Audit.Context} context\n       * @return {Promise<string[]>}\n       */\n      static async getRawCoop(artifacts, context) {\n        const devtoolsLog = artifacts.DevtoolsLog;\n        const mainResource = await MainResourceComputed.request({ devtoolsLog, URL: artifacts.URL }, context);\n        let coopHeaders = mainResource.responseHeaders.filter((h) => {\n          return h.name.toLowerCase() === \"cross-origin-opener-policy\";\n        }).flatMap((h) => h.value);\n        coopHeaders = coopHeaders.map((v) => v.toLowerCase().replace(/\\s/g, \"\"));\n        return coopHeaders;\n      }\n      /**\n       * @param {string | undefined} coopDirective\n       * @param {LH.IcuMessage | string} findingDescription\n       * @param {LH.IcuMessage=} severity\n       * @return {LH.Audit.Details.TableItem}\n       */\n      static findingToTableItem(coopDirective, findingDescription, severity) {\n        return {\n          directive: coopDirective,\n          description: findingDescription,\n          severity\n        };\n      }\n      /**\n       * @param {string[]} coopHeaders\n       * @return {{score: number, results: LH.Audit.Details.TableItem[]}}\n       */\n      static constructResults(coopHeaders) {\n        const rawCoop = [...coopHeaders];\n        const allowedDirectives = [\n          \"unsafe-none\",\n          \"same-origin-allow-popups\",\n          \"same-origin\",\n          \"noopener-allow-popups\"\n        ];\n        const violations = [];\n        const syntax = [];\n        if (!rawCoop.length) {\n          violations.push({\n            severity: str_85(UIStrings.itemSeverityHigh),\n            description: str_85(UIStrings105.noCoop),\n            directive: void 0\n          });\n        }\n        for (const actualDirective of coopHeaders) {\n          if (!allowedDirectives.includes(actualDirective)) {\n            syntax.push({\n              severity: str_85(UIStrings.itemSeverityLow),\n              description: str_85(UIStrings105.invalidSyntax),\n              directive: actualDirective\n            });\n          }\n        }\n        const results = [\n          ...violations.map(\n            (f) => this.findingToTableItem(\n              f.directive,\n              f.description,\n              str_85(UIStrings.itemSeverityHigh)\n            )\n          ),\n          ...syntax.map(\n            (f) => this.findingToTableItem(\n              f.directive,\n              f.description,\n              str_85(UIStrings.itemSeverityLow)\n            )\n          )\n        ];\n        return { score: violations.length || syntax.length ? 0 : 1, results };\n      }\n      /**\n       * @param {LH.Artifacts} artifacts\n       * @param {LH.Audit.Context} context\n       * @return {Promise<LH.Audit.Product>}\n       */\n      static async audit(artifacts, context) {\n        const coopHeaders = await this.getRawCoop(artifacts, context);\n        const { score, results } = this.constructResults(coopHeaders);\n        const headings = [\n          /* eslint-disable max-len */\n          { key: \"description\", valueType: \"text\", subItemsHeading: { key: \"description\" }, label: str_85(UIStrings.columnDescription) },\n          { key: \"directive\", valueType: \"code\", subItemsHeading: { key: \"directive\" }, label: str_85(UIStrings105.columnDirective) },\n          { key: \"severity\", valueType: \"text\", subItemsHeading: { key: \"severity\" }, label: str_85(UIStrings105.columnSeverity) }\n          /* eslint-enable max-len */\n        ];\n        const details = Audit.makeTableDetails(headings, results);\n        return {\n          score,\n          notApplicable: !results.length,\n          details\n        };\n      }\n    };\n    origin_isolation_default = OriginIsolation;\n  }\n});\n\n// core/audits/redirects-http.js\nvar redirects_http_exports = {};\n__export(redirects_http_exports, {\n  UIStrings: () => UIStrings106,\n  default: () => redirects_http_default\n});\nvar UIStrings106, str_86, RedirectsHTTP, redirects_http_default;\nvar init_redirects_http = __esm({\n  \"core/audits/redirects-http.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_audit();\n    init_i18n();\n    init_url_utils();\n    /**\n     * @license Copyright 2024 The Lighthouse Authors. All Rights Reserved.\n     * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0\n     * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.\n     */\n    UIStrings106 = {\n      /** Title of a Lighthouse audit that provides detail on HTTP to HTTPS redirects. This descriptive title is shown to users when HTTP traffic is redirected to HTTPS. */\n      title: \"Redirects HTTP traffic to HTTPS\",\n      /** Title of a Lighthouse audit that provides detail on HTTP to HTTPS redirects. This descriptive title is shown to users when HTTP traffic is not redirected to HTTPS. */\n      failureTitle: \"Does not redirect HTTP traffic to HTTPS\",\n      /** Description of a Lighthouse audit that tells the user why they should direct HTTP traffic to HTTPS. This is displayed after a user expands the section to see more. No character length limits. 'Learn More' becomes link text to additional documentation. */\n      description: \"Make sure that you redirect all HTTP traffic to HTTPS in order to enable secure web features for all your users. [Learn more](https://developer.chrome.com/docs/lighthouse/pwa/redirects-http/).\"\n    };\n    str_86 = createIcuMessageFn({ url: \"core/audits/redirects-http.js\" }.url, UIStrings106);\n    RedirectsHTTP = class extends Audit {\n      static {\n        __name(this, \"RedirectsHTTP\");\n      }\n      /**\n       * @return {LH.Audit.Meta}\n       */\n      static get meta() {\n        return {\n          id: \"redirects-http\",\n          title: str_86(UIStrings106.title),\n          failureTitle: str_86(UIStrings106.failureTitle),\n          description: str_86(UIStrings106.description),\n          requiredArtifacts: [\"URL\"],\n          supportedModes: [\"navigation\"]\n        };\n      }\n      /**\n       * @param {LH.Artifacts} artifacts\n       * @return {LH.Audit.Product}\n       */\n      static audit(artifacts) {\n        if (!artifacts.URL.requestedUrl) {\n          throw new Error(\"Missing requestedUrl\");\n        }\n        const requestedUrl = new URL(artifacts.URL.requestedUrl);\n        const finalDisplayedUrl = new URL(artifacts.URL.finalDisplayedUrl);\n        const startedInsecure = requestedUrl.protocol === \"http:\";\n        const isLocalhost = url_utils_default.isLikeLocalhost(finalDisplayedUrl.hostname);\n        if (!startedInsecure || isLocalhost) {\n          return {\n            score: null,\n            notApplicable: true\n          };\n        }\n        const endedSecure = finalDisplayedUrl.protocol === \"https:\";\n        return {\n          score: Number(endedSecure)\n        };\n      }\n    };\n    redirects_http_default = RedirectsHTTP;\n  }\n});\n\n// core/audits/seo/canonical.js\nvar canonical_exports = {};\n__export(canonical_exports, {\n  UIStrings: () => UIStrings107,\n  default: () => canonical_default\n});\nvar UIStrings107, str_87, Canonical, canonical_default;\nvar init_canonical = __esm({\n  \"core/audits/seo/canonical.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_audit();\n    init_url_utils();\n    init_main_resource();\n    init_i18n();\n    /**\n     * @license\n     * Copyright 2017 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    UIStrings107 = {\n      /** Title of a Lighthouse audit that provides detail on a page's rel=canonical link. This descriptive title is shown to users when the rel=canonical link is valid. \"rel=canonical\" is an HTML attribute and value and so should not be translated. */\n      title: \"Document has a valid `rel=canonical`\",\n      /** Title of a Lighthouse audit that provides detail on a page's rel=canonical link. This descriptive title is shown to users when the rel=canonical link is invalid and should be fixed. \"rel=canonical\" is an HTML attribute and value and so should not be translated. */\n      failureTitle: \"Document does not have a valid `rel=canonical`\",\n      /** Description of a Lighthouse audit that tells the user *why* they need to have a valid rel=canonical link. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */\n      description: \"Canonical links suggest which URL to show in search results. [Learn more about canonical links](https://developer.chrome.com/docs/lighthouse/seo/canonical/).\",\n      /**\n       * @description Explanatory message stating that there was a failure in an audit caused by multiple URLs conflicting with each other.\n       * @example {https://example.com, https://example2.com} urlList\n       * */\n      explanationConflict: \"Multiple conflicting URLs ({urlList})\",\n      /**\n       * @description Explanatory message stating that there was a failure in an audit caused by a URL being invalid.\n       * @example {https://example.com/} url\n       * */\n      explanationInvalid: \"Invalid URL ({url})\",\n      /**\n       * @description Explanatory message stating that there was a failure in an audit caused by a URL being relative instead of absolute.\n       * @example {https://example.com/} url\n       * */\n      explanationRelative: \"Is not an absolute URL ({url})\",\n      /**\n       * @description Explanatory message stating that there was a failure in an audit caused by a URL pointing to a different hreflang than the current context.'hreflang' is an HTML attribute and should not be translated.\n       * @example {https://example.com/} url\n       */\n      explanationPointsElsewhere: \"Points to another `hreflang` location ({url})\",\n      /** Explanatory message stating that the page's canonical URL was pointing to the domain's root URL, which is a common mistake. \"points\" refers to the action of the 'rel=canonical' referencing another link. \"root\" refers to the starting/home page of the website. \"domain\" refers to the registered domain name of the website. */\n      explanationRoot: \"Points to the domain's root URL (the homepage), instead of an equivalent page of content\"\n    };\n    str_87 = createIcuMessageFn({ url: \"core/audits/seo/canonical.js\" }.url, UIStrings107);\n    Canonical = class _Canonical extends Audit {\n      static {\n        __name(this, \"Canonical\");\n      }\n      /**\n       * @return {LH.Audit.Meta}\n       */\n      static get meta() {\n        return {\n          id: \"canonical\",\n          title: str_87(UIStrings107.title),\n          failureTitle: str_87(UIStrings107.failureTitle),\n          description: str_87(UIStrings107.description),\n          supportedModes: [\"navigation\"],\n          requiredArtifacts: [\"LinkElements\", \"URL\", \"DevtoolsLog\"]\n        };\n      }\n      /**\n       * @param {LH.Artifacts.LinkElement[]} linkElements\n       * @return {CanonicalURLData}\n       */\n      static collectCanonicalURLs(linkElements) {\n        const uniqueCanonicalURLs = /* @__PURE__ */ new Set();\n        const hreflangURLs = /* @__PURE__ */ new Set();\n        let invalidCanonicalLink;\n        let relativeCanonicallink;\n        for (const link of linkElements) {\n          if (link.source === \"body\") continue;\n          if (link.rel === \"canonical\") {\n            if (!link.hrefRaw) continue;\n            if (!link.href) invalidCanonicalLink = link;\n            else if (!url_utils_default.isValid(link.hrefRaw)) relativeCanonicallink = link;\n            else uniqueCanonicalURLs.add(link.href);\n          } else if (link.rel === \"alternate\") {\n            if (link.href && link.hreflang) hreflangURLs.add(link.href);\n          }\n        }\n        return { uniqueCanonicalURLs, hreflangURLs, invalidCanonicalLink, relativeCanonicallink };\n      }\n      /**\n       * @param {CanonicalURLData} canonicalURLData\n       * @return {LH.Audit.Product|undefined}\n       */\n      static findInvalidCanonicalURLReason(canonicalURLData) {\n        const { uniqueCanonicalURLs, invalidCanonicalLink, relativeCanonicallink } = canonicalURLData;\n        if (invalidCanonicalLink) {\n          return {\n            score: 0,\n            explanation: str_87(UIStrings107.explanationInvalid, { url: invalidCanonicalLink.hrefRaw })\n          };\n        }\n        if (relativeCanonicallink) {\n          return {\n            score: 0,\n            explanation: str_87(UIStrings107.explanationRelative, { url: relativeCanonicallink.hrefRaw })\n          };\n        }\n        const canonicalURLs = Array.from(uniqueCanonicalURLs);\n        if (canonicalURLs.length === 0) {\n          return {\n            score: 1,\n            notApplicable: true\n          };\n        }\n        if (canonicalURLs.length > 1) {\n          return {\n            score: 0,\n            explanation: str_87(UIStrings107.explanationConflict, { urlList: canonicalURLs.join(\", \") })\n          };\n        }\n      }\n      /**\n       * @param {CanonicalURLData} canonicalURLData\n       * @param {URL} canonicalURL\n       * @param {URL} baseURL\n       * @return {LH.Audit.Product|undefined}\n       */\n      static findCommonCanonicalURLMistakes(canonicalURLData, canonicalURL, baseURL) {\n        const { hreflangURLs } = canonicalURLData;\n        if (hreflangURLs.has(baseURL.href) && hreflangURLs.has(canonicalURL.href) && baseURL.href !== canonicalURL.href) {\n          return {\n            score: 0,\n            explanation: str_87(UIStrings107.explanationPointsElsewhere, { url: baseURL.href })\n          };\n        }\n        if (canonicalURL.origin === baseURL.origin && canonicalURL.pathname === \"/\" && baseURL.pathname !== \"/\") {\n          return {\n            score: 0,\n            explanation: str_87(UIStrings107.explanationRoot)\n          };\n        }\n      }\n      /**\n       * @param {LH.Artifacts} artifacts\n       * @param {LH.Audit.Context} context\n       * @return {Promise<LH.Audit.Product>}\n       */\n      static async audit(artifacts, context) {\n        const devtoolsLog = artifacts.DevtoolsLog;\n        const mainResource = await MainResourceComputed.request({ devtoolsLog, URL: artifacts.URL }, context);\n        const baseURL = new URL(mainResource.url);\n        const canonicalURLData = _Canonical.collectCanonicalURLs(artifacts.LinkElements);\n        const invalidURLAuditProduct = _Canonical.findInvalidCanonicalURLReason(canonicalURLData);\n        if (invalidURLAuditProduct) return invalidURLAuditProduct;\n        const canonicalURL = new URL([...canonicalURLData.uniqueCanonicalURLs][0]);\n        const mistakeAuditProduct = _Canonical.findCommonCanonicalURLMistakes(\n          canonicalURLData,\n          canonicalURL,\n          baseURL\n        );\n        if (mistakeAuditProduct) return mistakeAuditProduct;\n        return {\n          score: 1\n        };\n      }\n    };\n    canonical_default = Canonical;\n  }\n});\n\n// core/audits/seo/crawlable-anchors.js\nvar crawlable_anchors_exports = {};\n__export(crawlable_anchors_exports, {\n  UIStrings: () => UIStrings108,\n  default: () => crawlable_anchors_default\n});\nvar UIStrings108, hrefAssociatedAttributes, str_88, CrawlableAnchors, crawlable_anchors_default;\nvar init_crawlable_anchors = __esm({\n  \"core/audits/seo/crawlable-anchors.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_audit();\n    init_i18n();\n    /**\n     * @license\n     * Copyright 2020 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    UIStrings108 = {\n      /** Title of a Lighthouse audit that provides detail on whether links have potentially-crawlable href attributes. This descriptive title is shown when all links on the page are potentially-crawlable. */\n      title: \"Links are crawlable\",\n      /** Descriptive title of a Lighthouse audit that provides detail on whether links have potentially-crawlable href attributes. This descriptive title is shown when there are href attributes which are not crawlable by search engines. */\n      failureTitle: \"Links are not crawlable\",\n      /** Description of a Lighthouse audit that tells the user why href attributes on links should be crawlable. This is displayed after a user expands the section to see more. The last sentence starting with 'Learn' becomes link text to additional documentation. */\n      description: \"Search engines may use `href` attributes on links to crawl websites. Ensure that the `href` attribute of anchor elements links to an appropriate destination, so more pages of the site can be discovered. [Learn how to make links crawlable](https://support.google.com/webmasters/answer/9112205)\",\n      /** Label for a column in a data table; entries will be the HTML anchor elements that failed the audit. Anchors are DOM elements that are links. */\n      columnFailingLink: \"Uncrawlable Link\"\n    };\n    hrefAssociatedAttributes = [\n      \"target\",\n      \"download\",\n      \"ping\",\n      \"rel\",\n      \"hreflang\",\n      \"type\",\n      \"referrerpolicy\"\n    ];\n    str_88 = createIcuMessageFn({ url: \"core/audits/seo/crawlable-anchors.js\" }.url, UIStrings108);\n    CrawlableAnchors = class extends Audit {\n      static {\n        __name(this, \"CrawlableAnchors\");\n      }\n      /**\n       * @return {LH.Audit.Meta}\n       */\n      static get meta() {\n        return {\n          id: \"crawlable-anchors\",\n          title: str_88(UIStrings108.title),\n          failureTitle: str_88(UIStrings108.failureTitle),\n          description: str_88(UIStrings108.description),\n          requiredArtifacts: [\"AnchorElements\", \"URL\"]\n        };\n      }\n      /**\n       * @param {LH.Artifacts} artifacts\n       * @return {LH.Audit.Product}\n       */\n      static audit({ AnchorElements: anchorElements, URL: url }) {\n        const failingAnchors = anchorElements.filter(({\n          rawHref,\n          name = \"\",\n          role = \"\",\n          id,\n          href,\n          attributeNames = [],\n          listeners = []\n        }) => {\n          rawHref = rawHref.replace(/\\s/g, \"\");\n          name = name.trim();\n          role = role.trim();\n          if (role.length > 0) return;\n          if (rawHref.startsWith(\"mailto:\")) return;\n          if (rawHref === \"\" && id) return;\n          const javaScriptVoidRegExp = /javascript:void(\\(|)0(\\)|)/;\n          if (rawHref.startsWith(\"file:\")) return true;\n          if (name.length > 0) return;\n          if (!attributeNames.includes(\"href\") && hrefAssociatedAttributes.every((attribute) => !attributeNames.includes(attribute))) {\n            return Boolean(listeners.length);\n          }\n          if (href === \"\") return true;\n          if (javaScriptVoidRegExp.test(rawHref)) return true;\n          try {\n            new URL(rawHref, url.finalDisplayedUrl);\n          } catch (e) {\n            return true;\n          }\n        });\n        const headings = [{\n          key: \"node\",\n          valueType: \"node\",\n          label: str_88(UIStrings108.columnFailingLink)\n        }];\n        const itemsToDisplay = failingAnchors.map((anchor) => {\n          return {\n            node: Audit.makeNodeItem(anchor.node)\n          };\n        });\n        return {\n          score: Number(failingAnchors.length === 0),\n          details: Audit.makeTableDetails(headings, itemsToDisplay)\n        };\n      }\n    };\n    crawlable_anchors_default = CrawlableAnchors;\n  }\n});\n\n// third-party/axe/valid-langs.js\nfunction isValidLang(lang) {\n  let array = langs;\n  while (lang.length < 3) {\n    lang += \"`\";\n  }\n  for (let i = 0; i <= lang.length - 1; i++) {\n    const index = lang.charCodeAt(i) - 96;\n    array = array[index];\n    if (!array) {\n      return false;\n    }\n  }\n  return true;\n}\nvar langs;\nvar init_valid_langs = __esm({\n  \"third-party/axe/valid-langs.js\"() {\n    \"use strict\";\n    init_process_global();\n    langs = [, [, [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1, , 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [, 1, 1, , 1, 1, 1, , 1, 1, , 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [, 1, 1, , 1, 1, 1, 1, 1, 1, 1, , 1, , 1, 1, 1, 1, 1, 1, 1, 1, , 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, , , , , , 1, 1, 1, 1, , , 1, 1, 1, , 1, , 1, , 1, 1], [1, 1, 1, , 1, 1, , 1, 1, 1, , 1, , , 1, 1, 1, , , 1, 1, 1, , , , , 1], [, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [, 1, 1, , , , , 1, 1, 1, , 1, 1, 1, 1, 1, 1, , 1, 1, 1], [, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, , , 1, 1, 1], [, 1, , , , , , 1, , 1, , , , , 1, , 1, , , 1, 1, 1, , 1, , , 1], [1, , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [, 1, , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, , 1, 1, 1, , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n    1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, , , , 1, 1, 1, 1, , , 1, , 1], [, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [, 1, , 1, 1, , , 1, , , , 1, 1, 1, 1, , 1, , 1, , 1, , , , , , 1], [1, , 1, 1, 1, 1, , , 1, 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [, 1, 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, , 1, 1, 1, 1], [1, , 1, , 1, , , , , 1, , 1, 1, 1, 1, 1, , , , 1, 1, 1, 1], [, 1, 1, 1, 1, 1, , 1, 1, 1, , 1, , 1, 1, 1, , , 1, 1, 1, 1, 1, 1, 1, 1], [, , 1, , , 1, , 1, , , , 1, 1, 1, , , , , , , , , , , 1], [1, 1, 1, 1, 1, 1, , 1, 1, 1, , 1, 1, , 1, 1, 1, 1, 1, 1, 1, 1, , , 1, 1, 1], [1, 1, 1, 1, 1, , , 1, , , 1, , , 1, 1, 1, , , , , 1, , , , , , 1]], [, [1, 1, 1, 1, 1, 1,\n    1, 1, 1, 1, 1, , 1, , 1, 1, 1, , 1, 1, 1, 1, 1, 1, 1, 1, 1], [, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, , 1, 1], [, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, , 1, , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, , 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, , , 1, 1, 1, 1, 1, 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1, 1], [, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [, 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, , 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, , , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1, 1], [, 1, 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [, 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, , 1, 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1, 1, 1], [, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1, 1], [, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, , 1, 1, 1, 1], [, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, , 1, 1, 1, 1, , 1], [, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ,\n    1, 1, 1, 1, 1], [, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]], [, [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1], [, 1, 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1, , 1, 1, , 1, 1, 1, 1, 1, 1, 1, , 1], [, 1, , 1, 1, 1, , 1, 1, , 1, , 1, 1, 1, 1, 1, 1, 1, 1], [, 1, , 1, 1, 1, 1, 1, 1, 1, 1, , , 1, 1, 1, , , 1, 1, , , , , , 1, 1], [1, 1, 1, , , , , 1, , , , 1, 1, , 1, , , , , , 1, , , , , 1], [, 1, , , 1, , , 1, , , , , , 1], [, 1, , 1, , , , 1, , , , 1], [1, , 1, 1, 1, , 1, 1, 1, , 1, 1, 1, 1, 1, 1, 1, 1, 1, , 1, , , 1, 1, 1, 1], [, 1, 1, 1, 1, 1, , , 1, , , 1, , 1, 1, , 1, , 1, , , , , 1, , 1], [, 1, , , , 1, , , 1, 1, , 1, , 1, 1, 1, 1, , 1, 1, , , 1, , , 1], [, 1, 1, , , , , , 1, , , , 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1, , 1, 1, 1], [, 1, , 1, 1, 1, , , 1, 1, 1, 1, 1, 1, , 1, , , , 1, 1, 1, , 1, , 1], [, 1, , 1, , 1, , 1, , 1, , 1, 1, 1, 1, 1, , , 1, 1, 1], [, 1, 1, 1, , , , 1, 1, 1, , 1, 1, , , 1, 1, 1, 1, 1, 1, 1, , 1, 1], [1,\n    1, 1, 1, 1, 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1, 1, 1, , , 1, 1, 1, 1, 1, 1, 1], [, 1, 1, 1, , 1, 1, 1, , 1, , , , , 1, 1, 1, , , 1, , 1, , , 1, 1], [, , , , 1, , , , , , , , , , , , , , , , , 1], [1, 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, , 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [, 1, , 1, 1, 1, , 1, 1, , , , 1, 1, 1, 1, 1, , , 1, 1, 1, , , , 1, 1], [1, 1, 1, 1, , , , 1, 1, 1, 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, , , , , , , 1, , , , , , , 1], [, 1, 1, , 1, 1, , 1, , , , , , , , , , , , , 1], [, , , , , , , , 1], [1, 1, 1, , , , , , , , , , , , , 1], [, , , , , , , , 1, , , 1, , , 1, 1, , , , , 1]], [, [1, 1, , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, , 1, 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1], [, 1, 1, , 1, 1, 1, 1, , 1, 1, , 1, 1, 1, 1, 1, 1, 1, , 1, 1, 1, 1, , 1], [, , , 1, , , , , , , , , , , , , , , 1], [, 1, , , 1, 1, , 1, , 1, 1, , , , 1, 1, , , 1, 1, , , , 1], [1, , , 1, 1, 1, 1, 1, 1, 1, , 1, 1, 1,\n    1, , 1, 1, 1, 1, , , 1, , , , 1], , [, 1, 1, 1, 1, 1, , 1, 1, 1, , 1, 1, , 1, 1, , , 1, 1, 1, 1, , 1, 1, , 1], [, 1, , , 1, , , 1, , 1, , , 1, 1, 1, 1, , , 1, 1, , 1, 1, 1, 1], [, 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, , 1, 1, 1, 1], [, 1, 1, 1, 1, 1, 1, , , 1, 1, 1, 1, 1, 1, 1, , , 1, , , 1, , 1], [, 1, , , , , , 1, , , , 1, 1, , , , , , 1, 1, , , , , 1], [, , , , , , , 1, , , , 1, , 1, 1], [, 1, 1, 1, 1, 1, 1, 1, , , , 1, 1, 1, 1, 1, , , 1, 1, , 1, 1, 1, 1, 1], [, 1, , , 1, 1, , 1, , 1, 1, 1, , , 1, 1, , , 1, , 1, 1, 1, 1, , 1], [, 1, 1, 1, , 1, 1, , 1, 1, , 1, 1, , 1, 1, 1, 1, 1, 1, 1, , 1, 1, 1, 1, 1], [, , , , , , , , , , , , , , , , 1], , [, 1, 1, 1, 1, 1, , 1, 1, 1, , , 1, , 1, 1, , 1, 1, 1, 1, 1, , 1, , 1], [, , 1, , , 1, , , 1, 1, , 1, 1, , 1, 1, , 1, , , , , , , , , 1], [, 1, 1, , 1, , , , 1, 1, , 1, , 1, 1, 1, 1, , 1, 1, 1, 1, , , , 1], [, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1], [1, 1], [, 1, , , , , , , , , , 1,\n    1, , , , , , 1, 1, , 1, , 1, , 1, 1], , [, 1, 1, , 1, , , 1, , 1, , , , 1, 1, 1, , , 1, , , 1, , , , 1], [1, 1, , , 1, 1, , 1, , , , , 1, , 1]], [, [, 1], [, , , 1, , , , 1, , , , 1, , , , 1, , , 1, , , 1], [, , , , , , , , , , , , , , , , , , 1, 1, , , , , , 1], , [1, , , , , 1], [, 1, , , , 1, , , , 1], [, 1, , , , , , , , , , , 1, 1, , 1, , , , , , , , , 1, 1], [, , , , , , , , , , , , , , , , , , , 1, , 1], [, , , , , , , , , , , , , , , , 1, , , , 1, , 1], [, 1], [, 1, , 1, , 1, , 1, , 1, , 1, 1, 1, , 1, 1, , 1, , , , , , , 1], [1, , , , , 1, , , 1, 1, , 1, , 1, , 1, 1, , , , , 1, , , 1], [, 1, 1, , , 1, , 1, , 1, , 1, , 1, 1, 1, 1, 1, , 1, , 1, , 1, 1, 1, 1], [1, 1, 1, 1, 1, , 1, , 1, , , , 1, 1, 1, 1, , 1, 1, , , 1, 1, 1, 1], [1, , , , , , , , , , , , , , , , , , , , 1], [, , , , , , , , , 1], , [, 1, , , , , , 1, 1, 1, , 1, , , , 1, , , 1, 1, 1, , , 1], [1, , , , , 1, , 1, 1, 1, , 1, 1, 1, 1, 1, , 1, , 1, , 1, , , 1, 1], [1, , 1, 1, , , , , 1, , , , , , 1, 1, , , 1, 1, 1, 1,\n    , , 1, , 1], [1, , , , 1, , , , , , , , , , , , , 1], [, , , , , 1, , , 1, , , , , , 1], [, , , , , , , , , , , , , , , 1], [, , , , , , , , , , , , , , , , , , , , 1], [, 1, , , , , , , , , , , , , , 1], [, 1, , , , 1]], [, [1, 1, 1, , 1, , 1, 1, 1, 1, 1, 1, 1, 1, 1, , 1, , 1, , 1, 1, , , 1, 1, 1], [, , , , , , , , , , , , 1], [, , , , , , , , , , , , , , , , , , , 1], , [, , , , , , , , , , , , , , , , , , 1], [1, , , , , , , , , 1, , , , 1], [, , , , , , , , , , , , , , , , , , 1], , [1, 1, , , , 1, 1, , , , , , 1, , , , 1, , 1, , 1, 1, , 1], [1], [, , , , , , , , , , , 1, , , , , , , , , , , 1], [, 1, , , , , , , 1, 1, , , 1, , 1, , , , 1, , , , , , , 1], [, , , , , , , , , , , , , , , , 1, , , , , 1], [, , 1, , , , , 1, , 1], [1, , , , 1, , , , , 1, , , , 1, 1, , , , 1, 1, , , , , 1], [, , , , , 1], [, , , , , , , , , , , , , , , , , , , 1], [1, , , 1, 1, , , , , , , 1, , 1, , 1, 1, 1, 1, 1, 1], [, , , , , 1, , , , , , , 1, , , , , , , 1], , [, , 1, 1, 1, 1, 1, , 1, 1, 1, , , 1,\n    1, , , 1, 1, , 1, 1, 1, , , 1], [, , , , , , , , , , , , , , , , , , 1], [, 1, , , , 1], , [1]], [, [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1], [, , , 1, 1, 1, 1, , , , , , 1, , 1, , , , 1, , 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, , 1, 1, 1, 1, 1, , , 1], [, 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1, 1, 1, , , , 1, , 1, , , 1, 1, 1, 1, 1], [, , , , , , , , , , , 1, , , , , , , , , 1, , , , 1], [, 1, 1, , 1, 1, , 1, , , , 1, 1, , 1, 1, , , 1, , 1, 1, , 1], [, 1, , 1, , 1, , , 1, , , 1, 1, , 1, 1, , , 1, 1, 1], [, 1, 1, 1, 1, 1, , 1, 1, 1, , , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, , 1, 1, 1, 1], [, , , , , , , , , 1, , 1, , 1, 1, , , , 1, , , 1], [, 1, , , 1, 1, , , , , , , , , 1, 1, 1, , , , , 1], [1, , 1, 1, 1, , , , 1, 1, 1, 1, 1, , , 1, , , 1, , , 1, , 1, , 1], [, 1, 1, , 1, 1, , 1, 1, , , , 1, 1, 1, , , 1, 1, , , 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, , 1, 1, 1, 1, 1,\n    1, 1, 1, 1, , 1, 1, , 1, 1, , 1, , , 1], [, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [, 1, , , , 1, , , , , , , , , 1], [, 1, , , , , , , , 1, , , , , 1, , , , 1, , , 1], [, 1, 1, 1, 1, , , 1, 1, 1, 1, 1, , 1, , 1, , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [, , , , , 1, , 1, , , , , 1, 1, 1, 1, 1, , , 1, , , , 1], [, 1, , , , , , , , 1, , , , , , , , , , , , 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, , 1], [1, 1, , 1, , 1, 1, , , , 1, , 1, 1, 1, 1, 1, , 1, 1, , , , , , 1], [, 1, 1, 1, 1, 1, 1, 1, , 1, 1, , , 1, 1, , , , 1, , 1, 1, , 1, 1], [, , , , , , , , , , , , , , , , , , , , , , , , 1], [, 1, 1, , 1, 1, 1, 1, , 1, , , 1, 1, 1, 1, , , 1, , , , , , , 1, 1], [, 1, , , , , , , , 1, , , , , 1]], [, [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, , , 1, 1, 1, 1, 1], [, 1, 1, , , , , , , , , , , , 1, 1, , , , , , 1], [, 1, , , , , , , 1], [, , , , , , , , , , , , , , 1, , , , , 1, , , , , , 1], [1, 1, , , 1,\n    , , 1, 1, 1, , , , 1], , [, , , , , , , , , , , , , 1, , , , , , , , , , 1], [, , , , , , , , , 1, , , , , , , , , 1, , , , , , , 1], [1, 1, 1, , 1, , 1, 1, 1, 1, 1, 1, 1, 1, , 1, , , 1, , 1, , , 1, 1], [, , , , , , , , , 1], [, 1, , , , 1, , , 1, , , 1, , , 1, , , , , 1], [, 1, 1, , 1, 1, , , , , , , , , , , , , , , 1, 1], [, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [, 1, , , 1, 1, , 1, 1, 1, 1, , , 1, 1, 1, , , , 1, , 1], [1, 1, 1, 1, 1, 1, , , 1, 1, 1, 1, 1, 1, , 1, 1, , 1, 1, 1, , 1, 1, , 1, 1], [, , , , , , , , , , , , , , , 1, , , , 1], , [1, 1, , 1, , 1, , , , , , 1, , 1, , 1, 1, , 1, , 1, 1, , 1, 1, , 1], [, , 1, , , , , , 1, , , , 1, , 1, , , , , 1], [1, , , , , , , , , 1, , , , , , 1, , , , 1, , 1, , , 1], [1, , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [, , , 1, , 1, , , , , , 1, , , 1, , , , , , , , 1], [, 1, , 1, , , , , , , , , , , , 1], , [1, 1, , , , , , , , , , , , , , , , , , , , , , 1, 1], [1]],\n    [, [1, , , , , , , , , 1, , , , , 1, , 1, , 1], [, 1, 1, , 1, 1, , 1, 1, 1, , , 1, 1, 1, , , , 1, , , 1, , , , 1], [, 1, , , , , , , 1, , , , 1, , , , , , 1], [1, 1, 1, 1, 1, 1, , , , 1, , , , , , , , , 1, 1, 1, 1], [1], [, 1, 1, , , 1, 1, , , , , 1, , 1, , , , , , , , 1, , , , 1], [1, , 1, , , 1, , 1, , , , , 1, 1, 1, 1, , , , 1, , , , 1], [, , 1, , , , , , , 1, , , , , , , 1, , , , , , , 1], [1, , , , , , , , , , , , , , 1, , , , 1], [, , , 1, , 1, , , , , 1, , , , 1, 1, , , , 1], [1, , , , , 1, , , 1, 1, , 1, 1, , , 1, 1, , 1, 1, 1, , 1, 1, 1, , 1], [, 1, 1, , , , , 1, , 1, , 1, 1, 1, , 1, 1, , , 1, , 1, 1, 1], [, 1, , , , 1, , , , 1, , , 1, , 1, 1, , , 1, 1, 1, , , , , 1], [1, , 1, 1, , 1, , 1, 1, , 1, , 1, 1, 1, 1, 1, , , 1, 1, , , , , , 1], [1, , , , , , , , , , , , , , , , , , 1, , , 1, , 1], [, , , , , , , , , 1, , , , , , 1], [, , , , , , , , , , , , , , , , , , , , , 1, , 1], [, 1, , , , 1, , , 1, 1, , 1, , , 1, 1, , , 1, , , 1, , , 1, 1], [1, 1, , 1, 1, 1, , 1, 1, 1, , 1,\n    , 1, 1, 1, , , 1, , 1, 1, 1], [1, , 1, 1, 1, 1, , , , 1, , 1, 1, 1, , 1, , , 1, 1, 1, , 1, 1, 1, 1, 1], [1, , , , , , , , , , , , , 1], [, , 1, , , , , , , , , , , , , , , , , , , , 1], [1, , , , , , , , , , , 1, , 1, , 1, , , , 1], [, , , 1, , , , , , , , , 1], [, 1, , , , , , , , , , , , , , 1, , , , , , , , , 1], [, , , , , , , , 1, 1, , , , 1, , , , , 1, , , , , , , , 1]], [, [1, 1, 1, 1, 1, 1, 1, , 1, , 1, 1, 1, 1, 1, 1, , 1, 1, 1, 1, 1, , , 1, 1, 1], [, , , , , 1, , , , 1, 1, 1, , 1, 1, 1, , , 1, , 1, 1, , 1], [, , , , , , , , , , , , , , , , , , , 1, 1], [, 1, , , , , , 1, , , , , , , , , , , , , 1], [, , 1, , , 1, , 1, 1, 1, , 1, 1, , 1, , , , 1, , 1, 1], , [, , 1, , , 1, , , , , , 1, , , , 1], [, , , , , , , , , 1, , , , , , , , , , 1], [1, 1, 1, 1, 1, 1, , 1, 1, 1, , , 1, 1, , 1, , 1, , , 1, 1, 1, , , 1], [, , , , , 1, , , , , , , , , , , , , 1], [, 1, , , , , , , , , , , , 1, , 1, 1, , 1, 1, , 1], [, , , , , 1, , , , , , , , , , , , , , 1], [, 1, 1, 1, 1, , , , , 1, , , 1,\n    , 1, , , , 1, 1, , , , 1, 1], [, 1, , , 1, , , 1, , 1, 1, , 1, , , , , , , 1], [, , 1, , 1, , , 1, , , , , , , , , , , 1, 1, , , , 1], [, 1, , , , , , , , , , , , , , , , , 1, , , , , , 1], [, , , , , , , , , , , , , , , , , , 1], [, 1, 1, , , , , , , , , , , , , , , , 1, , 1, 1], [, , , , , , , , , , , , 1], , [, 1, 1, 1, 1, , , , 1, 1, , 1, 1, 1, 1, 1, 1, , 1, 1, 1, 1, , 1, , 1], [1, , , , 1, , , , , , , , , , 1], [1, , , , , , , , , 1], , [, 1, , , , 1, , , , , , , , , , , , , , , , , , , , 1]], [, [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, , 1, , 1, 1, 1, 1, , , , 1, 1, 1, 1], [, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [, 1, , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1, 1], [, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1,\n    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, , 1, 1, , 1, 1, 1, , 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, , 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, , , 1, 1, 1, , 1, 1, 1, 1, 1, 1, 1, 1], [, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1,\n    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [, 1, 1, 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]], [, [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, , 1, 1, 1, 1, , 1, , 1, 1, 1, 1], [1, 1, 1, 1, , 1, 1, 1, , 1, 1, 1, 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [, , , 1, 1, 1, 1, , 1, , , , 1, 1, , , 1, 1, , 1], [, 1, 1, , 1, , , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [, 1, , , , , , ,\n    , , , , , , 1], [1, 1, 1, , , , , 1, 1, 1, , 1, 1, 1, 1, 1, , 1, 1, 1, 1, 1, , , , , 1], [, 1, , , , , , , 1, 1, , , 1, 1, 1, , 1, , , 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, , , 1, 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1], [, 1, , , , 1, , , , 1, , , 1, , , , 1, , , , , , , 1, 1], [, 1, 1, 1, 1, 1, , , 1, 1, 1, , 1, 1, 1, 1, , , 1, 1, 1, 1, , , , 1], [, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, , 1, , 1, , , 1], [, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, , , 1, 1, 1, 1, 1, 1], [1, 1, 1, , 1, , , 1, 1, 1, 1, , 1, 1, 1, 1, , , , 1, , 1, , 1, , , 1], [1, 1, 1, 1, , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [, 1, , , , 1, , , , , , , , , 1, 1, , , , , , , , , 1], [, , , , , , , , , , , , , , , , , , 1], [, 1, , 1, , 1, , 1, , 1, , 1, 1, 1, 1, 1, , , 1, , 1, , 1, , , , 1], [, 1, 1, 1, 1, 1, , 1, 1, 1, , , 1, 1, 1, 1, 1, , 1, 1, 1, , 1, 1, , 1], [1, , , 1, , , , 1, 1, 1, , , , , 1, 1, , , , 1, , 1], [1, 1, , 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1,\n    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, , 1, 1], [1, 1, , , , , , , , 1, , 1, 1, , , , , , , 1, , 1], [, 1, , , , 1, , 1, 1, , , , 1, 1, , 1, , , , 1, 1, 1, , 1], [, , , , , , , , , , , , , 1], [, 1, , , , , , 1, , , , , , , 1], [, , , , , , , , 1, , , , 1, , 1, , , , , , , , , , , , 1]], [, [, 1, 1, , 1, 1, 1, 1, , 1, 1, 1, , 1, 1, , 1, 1, , 1, 1, 1, 1, 1, 1, , 1], [, 1, 1, 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, , 1, 1], [, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, , 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n    , 1, 1, 1, 1], [, 1, 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, , 1, 1, 1, 1, , 1], [, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, , 1, 1, 1, 1, 1, 1, 1, 1, 1, , 1, , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [, 1, 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [, 1, 1, 1, , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [, 1, 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, , 1, 1, 1], [, 1, 1,\n    , 1, 1, 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [, 1, 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]], [, [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, , , 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, , , 1, , 1], [1, 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, , 1, 1, 1, , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [, 1, , , 1, , , , , , , , 1, , , , , , 1, , , 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [, 1, 1, 1, 1, 1, 1, 1, 1, 1, , 1, , 1, 1, 1, 1, 1, 1, , 1,\n    1, 1, 1, 1, 1, 1], [, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [, 1, 1, , 1, , , , 1, 1, 1, , 1, 1, 1, 1, , , 1, 1, 1, 1, , , 1, 1, 1], [, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, , 1], [1, 1, , 1, , 1, , 1, , 1, 1, 1, 1, 1, 1, 1, , 1, 1, , , 1, 1, 1, 1, 1, 1], [, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, , 1, 1, 1, 1, 1, , 1, 1], [, 1, 1, , , , , 1, 1, 1, , , 1, , 1, 1, , , , 1, , 1, , , 1, 1], [, , , , , , , 1, , , , 1, 1, 1, 1, 1, , 1, , , 1, , , , , 1], [1, 1, 1, 1, , 1, 1, 1, , 1, , 1, 1, 1, 1, , 1, , 1, , 1, 1, , , 1, , 1], [, 1, 1, 1, 1, 1, 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [, , , , 1, 1, , 1, , 1, 1, 1, , 1, , 1, 1, , 1, 1, , 1, , 1, 1, 1, 1], [, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n    1, 1, 1, 1], [1, , , , , , , , 1, , , , , 1, , 1], [, 1, 1, 1, , 1, , 1, , 1, , , , 1, , 1, , , 1, , , , , 1, 1, 1], [, 1, , , 1, 1, , 1, , 1, , 1, 1, 1, 1, 1, , 1, 1, , , 1, , , 1], [1, , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [, 1, 1, , 1, , , , , 1, , 1, , 1, , , , , 1, 1, , 1, , , , 1, 1]], [, [, 1, , 1, , , , , , , , 1, , , , , , , 1, , , , 1], [, , , , , , , , , 1, , 1, 1, 1, , 1, , , 1, , 1, 1], [1, 1, , , , , , , 1, , , , , 1, , 1, , , , , , 1], [, 1, , , , , , , , , , 1, , , , , , , , , 1, 1], , [, , , , , , , , , , , , , , , 1, , , , 1, , 1], [, , 1, 1, , 1, , 1, , , , , , , , 1, , , , , , 1], [, , , , , , , , , , , , , , , , , , , , 1, 1], [, 1, , , , 1, , , , , , , , , 1], [1, , 1, 1, , , , 1, , , , , , , , , 1, , , 1, , , 1, 1], [, 1, 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1, 1, 1, 1, , , 1, 1, , 1, 1, , 1, , 1], [, 1, , , 1, 1, , , , , , 1, , 1, , 1, , , 1, , 1, 1], [1, 1, 1, 1, , 1, , 1, , 1, , 1, 1, , 1, 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1], [, 1,\n    1, , , 1, , 1, , 1, 1, 1, , , 1, 1, 1, , 1, 1, 1, 1, , 1, 1], [, , , , 1, , , 1, , , , , , , 1, , , , 1, 1], [, 1, , , , , , , , , , 1, , 1, , 1, , , , , 1, , , , , 1], , [1, 1, , 1, , 1, , 1, 1, , , , , , 1, 1, , , 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, , 1, , , , , , 1, , , , , 1, 1, 1, , , , 1, 1, , , 1], [, 1, 1, , 1, 1, , , , 1, , 1, 1, 1, 1, 1, , 1, 1, 1, 1, 1, , 1, 1, 1, 1], [, 1, 1, , , 1, , , , 1, , , , 1, 1], [, , , , 1], [, , , , , , , , , 1, , , 1], , [, , 1, , 1, , , , , , , , , 1, , , , , , , , , , , , 1], [, , , , , , , , , , , , , 1]], [, [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, , 1, 1, 1, , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [, , 1, 1, , 1, 1, 1, 1, 1, , , 1, 1, 1, 1, 1, , 1, 1, 1, 1, 1, , , 1, 1], [, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, , 1, , 1, , , , , 1], [, 1, , 1, , , , , , 1, , , , , 1, 1, , , , , 1, 1], [, 1, 1, , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, , 1, 1, 1, , 1, , , 1, , 1, 1, 1], [, 1, , , , 1, , , , , , , 1], [, 1, , , 1, , , 1, , 1, , 1, 1, , 1, , , , , 1, , 1, , ,\n    , 1, 1], [, 1, , , 1, , , 1, 1, 1, 1, 1, 1, 1, 1, 1, , 1, 1, , 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, , 1, 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1, 1, 1, 1], [, , , , , , , , , , , , , , , , , , , , 1], [, 1, 1, 1, , , , 1, 1, , , , , , 1, 1, 1, , 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, , 1, 1, 1, , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, , 1, 1], [, 1, 1, 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1, 1, 1, , 1, 1, 1, 1, 1, , 1, 1, 1, 1], [, 1, 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [, , , 1, 1, 1, 1, 1, 1, 1, , 1, , 1, 1, 1, 1, 1, , 1, 1, , 1, 1, 1, 1, 1], [, 1, , , , 1, , , , 1, , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [, 1, , , , 1, , , , , , , , 1, , , , , , , , , , 1], [, 1, 1, 1, 1, 1, 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, , 1, 1, 1, 1], [1, 1, , 1, 1, 1, , 1, 1, 1, , , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, , 1, , 1], [1, 1, , , , , , , 1, 1, , , , , 1, 1, 1, 1, 1, , 1, 1, 1, 1, , 1], [, 1, 1, 1, 1, 1, 1, 1, , 1, 1, 1, , 1, , 1, 1, 1, 1, , 1, 1, , 1, 1, 1, 1], , [, 1,\n    1, , , , , 1, , 1, , , , 1, 1, 1, , , 1, , , , , 1], [, , , , , , , , , , , , , 1], [, , , , , 1, , , , , , , , 1, 1, , , , , 1, , 1, , , 1, 1], [, , , , , 1, , , 1, , , , , , 1]], [, [, 1], , , , , , , , , , , , , , , , , , , , [1, 1, 1, 1, 1, , 1, 1, 1, 1, , 1, 1, 1, 1, , 1, 1, 1, 1, , , 1, 1, 1, 1, 1], [, 1, , 1, , 1, , , 1, 1, 1, , 1, 1, 1, 1, 1, , , 1, , , , 1, , 1, 1], [, 1, , 1, , 1, , , 1, , , , , 1, , , , , , 1, 1], [, 1, , 1, , , , , 1, , , , 1, , 1, 1, 1, 1, 1, 1, 1, 1, , 1], [, 1, , , , , , , , , , , , , , , 1]], [, [, 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [, , 1, , , , , , , , , 1, 1, , , , 1], [, , , , , , 1], [, , 1], [, 1, 1, , , 1, , 1, , 1, 1, , 1, 1, 1, , , , 1, 1, 1, , , , , 1], , [, 1, , , , 1, , , , , , 1, , , 1, , , , 1, 1, , 1], [, , , , , , , 1, , , , , , , , , 1], [, 1, 1, , , 1, 1, , , , , , 1, 1, 1, , , , 1, , 1, 1], [, , , , , , , 1, , 1, , , , , , , , , , 1], [, 1, 1, , , , , , 1, 1, , , , 1, , , , , , , 1, , , 1],\n    , [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, , 1, , , 1, , , , , 1, , 1, , 1, , 1, , , , , 1], [1, 1, 1, 1, 1, 1, 1, 1, , , , , 1, 1, , 1, 1, , 1, , , 1, , 1], [, , , , , , , , , , , , , , 1, , , , , , 1], , [, , , , , , , , , 1, , , , 1, , 1, , , , , 1], [, , 1, , , , , , , 1, , 1, 1, 1, 1, , , , , , , , , 1], [, , , 1, , , , , 1, , , , , 1, , , , , , 1, , , , 1], [1, , 1, 1, , 1, 1, 1, 1, 1, , 1, , , , 1, 1, 1, , , 1, 1, , , , 1, 1], , [1, 1, , , , , , , , , , 1, 1, 1, , 1, , , 1], [, , , , 1, , , , , , , , , , , , , , , , , , , 1], [, , , , , , , , , , , , , , 1, , , , , 1, , 1], [, , , , , , , , 1]], [, [1, 1, 1, 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, , , 1, 1, 1, 1, 1, , 1, 1, , 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, , 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, , 1, , 1], [1, 1, 1, 1, 1, 1,\n    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, , 1, 1], [, , 1, , , 1, , , , , , , , 1, , , , , , 1, , , , 1], [1, 1, 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, , 1, 1, 1, 1, , 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [, 1, 1, 1, 1, 1, , 1, , , , 1, 1, 1, 1, 1, 1, , 1, 1, 1, 1, , 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, , 1, 1, 1, 1, 1, 1, 1, 1, , 1, 1, 1, , 1, 1, 1, 1, 1, 1, , 1, 1, 1, 1], [1, 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, , 1, 1, , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1], [, , 1, 1, 1, 1, , 1, , 1, , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, , 1, 1], [1, 1, , , , , , , 1, , 1, 1, , 1, 1, 1, , 1, 1, 1, 1, 1, , , 1], [1, 1, 1, 1, , 1, 1, 1, 1,\n    1, , 1, 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, , 1, 1, 1], [1, 1, 1, , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, , 1], [1, 1, 1, 1, , 1, , 1, , 1, 1, 1, 1, 1, , 1, , 1, 1, 1, 1, , 1, 1, 1, 1, 1], [1, 1, 1, 1, , 1, , , , , , 1, , 1, , , , , 1, 1, , , , , 1], [1, , 1, 1, , , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [, , 1, 1, , 1, , 1, , , , 1, 1, 1, 1, 1, , , 1, 1, , 1, , 1], [, 1, 1, 1, 1, , , , , 1, , 1, 1, 1, 1, 1, , , 1, 1, , , , 1, 1, 1], [, 1, 1, 1, 1, 1, , 1, , , , , 1, , 1, , 1, , , 1, , , 1, 1, , 1]], [, [1, 1, 1, 1, 1, 1, 1, 1, , 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1], [, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [, 1, 1, 1, 1, 1, 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1, 1, , 1, 1, 1, , 1, 1, 1, 1], [, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1, , 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, , 1, , 1, 1, 1,\n    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [, , , , , , , , , 1, , , , , 1, 1, , , 1, , 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, , , , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, , , 1, 1, 1, 1, , 1, 1, , 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1, 1, 1], [, 1, , , , , , 1, , 1, 1, , 1, 1, 1, 1, 1, , , 1, , 1, , 1], [1, 1, 1, , 1, 1, 1, 1, , , , 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1, 1, 1, 1, , 1], [1, 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, , 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, , 1, 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1], [, 1, , 1, , 1, 1, 1, , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1, 1], [, , 1, , , , , , , , , , 1, 1, 1, 1, 1, 1, 1, , 1, 1, , 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n    1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, , , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, , 1, 1], [, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1, 1, 1], [, 1, , , 1, 1, , , , 1, , 1, 1, 1, 1, 1, , , , 1, 1, 1, , 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, , , , 1, 1, 1, 1, 1, 1, 1, , 1, 1, , 1, 1, 1], [, 1, 1, 1, , 1, , 1, 1, 1, 1, , , 1, 1, 1, , 1, 1, 1, 1, 1, , , 1, 1], [1, 1, , , , 1, , , 1, 1, 1, , 1, , 1, , 1, , 1, 1, 1, 1, 1, , 1, 1, 1], [, 1, , , , , , , 1, , 1, , 1, 1, 1, 1, , , , , , , , , 1]], [, [, , , , , , , , , , , , , 1, 1, , , , 1], [, 1, , , , , , , , 1, , , 1, , , , , , 1, , , 1, , , , 1], , [, 1, , , , 1, , 1, , 1, 1, , 1, 1, , , , , , , , 1], [, , , , , , , , , , , , , , , , , , , 1], [, , , , , , , , , 1], [1, 1, 1, , , 1, , , 1, , , , , , 1, 1, , , , , , , , , , 1], [, 1, , , , , , , , , , , , , 1], [, , , , , , , , , , , , , , , , , , , 1, , , 1], [, , , , , , , , , 1],\n    [1, 1, , , , , , 1, 1, 1, , 1, 1, , , , 1, 1, , 1, , 1, 1, 1, , 1], [, 1, 1, 1, , 1, 1, , , 1, , 1, 1, 1, 1, , , , , , , 1, , 1, , 1], [, 1, 1, 1, 1, , , 1, , 1, , , , 1, 1, 1, 1, , 1, 1, , 1], [, 1, , , 1, 1, , 1, , 1, , 1, , 1, 1, , 1, , 1, , , 1, , , 1, , 1], [, , , , , , , , , , , 1, , , 1], [, , , , , , , , , 1, , , , , , , , , , , , , 1], , [1, 1, 1, 1, , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, , 1, , 1, 1, 1, 1, 1, 1, 1], [, 1, , , , , , , 1, 1, , 1, , , , , 1, , , 1, , 1], [, 1, , , , 1, , , 1, , , , , , , , 1, , 1, , , 1], [, , , , , , , , , , , , , 1, 1, , , , 1, , , 1], [, , , , , 1, , , 1, , , , 1], [, 1], , [, 1], [1, , , , , , , , , , , , , , 1, , , , , 1]], [, [, 1, , , , 1, 1, 1, 1, 1, 1, , 1, 1, 1, 1, 1, , 1, 1, , 1, 1, , , 1], [, , 1, , , , , , , , , 1], , , [1, , , 1, 1, , , , , , , , 1, 1, , 1, 1, , 1], , [, , , , , , , , , , , , , , , , , , 1, , 1], , [1, , , 1, 1, , 1, 1, , , , , 1, , 1, , , , , 1, 1, , 1], [, , , , , , , , , , , 1], [, 1, , , , , , , , 1, 1, 1, 1,\n    1, 1, 1, 1, , , , 1, 1, , , , , 1], [, , , , , , , , , , , , , , , , 1, , , 1], [, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, , , 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1], [, , , , , , , , , , , 1, , 1, , , 1], [1, , , , , , , , , , , , , , , , , , 1, , 1], , , [, 1, , , , , , , , , , , , , , 1, , , , 1, 1], [, , , , , , , , , 1, , , 1, , 1, , , , , , , , 1], [, , , , , , , , , , , , , , , 1], [, , , , , , , , , , , , , 1, 1, , , , , , 1], , [, 1]], [, [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [, 1, 1, , , 1, 1, , 1, 1, 1, 1, 1, 1, , , 1, 1, 1, 1, 1, , 1, 1], [, 1, , , , , , , , 1], [, , , , 1, , , 1, , , 1, 1, , , , , , , , , 1, 1, , , , 1], [, 1, , 1, 1, , , 1, 1, 1, , , , 1, 1, 1, 1, , 1, 1, 1, 1, , 1], [, , , , , , , 1], [, 1, 1, , , , , 1, , 1, , , , , , 1, , , , , , 1, , 1, , 1], [, 1, , , , , , 1, , , , 1, , , , , , , , , , 1], [, , 1, 1, , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, , , , 1, , 1, 1, 1, 1, , 1], [, 1, , , , , , , , 1], [, 1, 1, , 1, , , , , , ,\n    , 1, , , , , , 1, , , 1, , 1, , 1], [, 1, , 1, , 1, , 1, 1, 1, , 1, 1, 1, , 1, , , 1, 1, , 1, 1, 1, 1, 1], [, 1, 1, 1, 1, 1, , 1, 1, 1, , , , 1, 1, 1, , , , 1, 1, , , 1, 1], [, , 1, 1, 1, 1, , 1, , 1, , 1, , 1, 1, 1, 1, , , , , 1, , 1, , 1], [1, 1, 1, 1, 1, 1, 1, 1, , 1, , 1, , 1, 1, 1, , , 1, 1, , , , 1, , 1], [, , , 1], , [, 1, 1, , 1, , , 1, 1, 1, , 1, 1, 1, 1, 1, 1, , 1, 1, , 1, 1, 1, 1, 1, 1], [, 1, , , , , , 1, , 1, , 1, , , , , , , 1, 1, , 1, 1], [, , 1, , , , 1, , 1, 1, , 1, , 1, , , , , , , , , , 1], [, 1, 1, , 1, , , , 1, , , , 1, 1, 1, , , , 1, , 1, 1, 1, , 1, 1], , [, 1, 1, , , , , , , , , , , , , 1, , , 1, , , , , 1], [, 1, , , , , , , , , , , , , , , , , , , , , , 1], [, 1, 1, , , , , , , 1, , , , 1, 1, , , , 1, , , , , , , 1]], [, [, 1, 1, 1, 1, 1, , 1, , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, , 1], [, 1, 1, 1, 1, 1, , 1, , 1, 1, , , 1, 1, 1, 1, , 1, , , , , 1, 1, 1], [, , 1, 1, , 1, , 1, 1, , , , 1, 1, 1, 1, , , 1, , 1, 1, 1, 1, , 1], [, 1, , 1, , , , , , , , 1,\n    , 1, , 1, , 1, , , , , , , , 1], [, , 1, , 1, , , 1, , , , , 1, 1, , , 1, , 1, 1, 1, 1], [, 1], [, 1, 1, , 1, , 1, 1, , 1, , , 1, 1, 1, , , , 1, , , 1, , 1], [1, 1, , 1, 1, 1, , , , , , , , 1, , , , , 1, , 1, 1, 1], [, 1, 1, , , , , , , 1, , , 1, , 1, , 1, , 1, 1, , , 1, , , 1], [, , 1, , , , , , , , , , , , , , , , , , 1], [, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [, 1, 1, 1, 1, 1, , 1, , 1, , , , , 1, 1, 1, , , 1, , 1, , , , 1], [, 1, 1, 1, 1, 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [, 1, 1, , 1, , , 1, 1, 1, 1, 1, , 1, 1, 1, , 1, 1, 1, 1, 1, , , , 1, 1], [, , , 1, 1, , , 1, , 1, , 1, , 1, 1, 1, 1, , 1, , , , , 1], [, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [, 1, , , , , , , , , , , , , , , , , , , 1], [, 1, 1, , 1, 1, , 1, , 1, , , , 1, 1, , , 1, 1, , 1, 1, , 1], [, 1, 1, 1, 1, 1, , , 1, 1, 1, , 1, 1, 1, 1, 1, 1, 1, 1, , 1, 1, , , 1], [, 1, 1, 1, 1, 1, , 1, 1, 1, 1, , 1, 1, 1,\n    1, 1, 1, 1, 1, 1, 1, 1, 1, , 1, 1], [, 1, 1, , 1, , , 1, , , 1, , 1, 1, 1, 1, 1, , 1, , 1, 1], [, , , , , 1, , , , 1, , , , , 1, 1, , , , 1], [, 1, , 1, 1, 1, , 1, , , 1, 1, 1, , , 1, , , 1, , 1, , , 1], [, , 1, , , , , , , , , 1, , 1, , , , , 1, , 1], [, 1, 1, , , , , , , , 1, 1, 1, , , , , , , , 1, , , , , 1], [, , , , , , , , 1, , , , , 1, , , 1]], [, [, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [, 1, 1, , 1, 1, , , 1, 1, 1, 1, 1, 1, 1, 1, , , , , , , , , 1, 1], [, , , , , , , , 1, , , , 1, , 1, , 1, , 1], [, 1, , , 1, 1, , 1, , , , 1, , , , , , , , 1], [, 1, , 1, , 1, , , , 1, 1, , 1, , 1, , , , 1, 1, 1, 1, 1, , , 1], , [, 1, , , , , , , , 1, , , 1, 1, , , 1, , 1, 1, , 1, , 1], [, 1, , , 1, , , , , , , , 1, , , , , , , 1], [1, 1, , , , , 1, 1, 1, 1, 1, 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1, 1, , 1, 1, 1], , [, 1, , , , , , 1, 1, 1, , 1, 1, 1, 1, 1, , , 1, , 1, 1, , , , 1], [, 1, 1, , , 1, , 1, , 1, , , 1, 1, 1, 1, , , 1, , , 1, , , , 1], [, 1, 1, 1,\n    1, 1, , 1, 1, 1, , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, , , , 1, , 1], [, 1, 1, , 1, 1, , 1, 1, , , 1, 1, , 1, 1, , 1, , 1, , 1], [1, , 1, , , , , 1, , 1, , 1, 1, 1, 1, , , , , 1, 1, , , , 1, 1], [, 1, 1, , , , , 1, 1, , , 1, , 1, 1, 1, 1, , , , , , , , , , 1], , [, 1, 1, , , 1, , , , 1, , 1, 1, 1, 1, 1, , , , 1, , , , 1, , 1], [, , , 1, 1, , , 1, , , , , 1, 1, 1, 1, 1, , 1, 1, , , , , , 1], [, 1, , , , , , , , , , , 1, , , , 1, , , , , , , 1, , 1], [, 1, 1, 1, 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1, , 1, 1, 1, , 1, 1, , 1, 1, 1, 1], [, 1, , , , , , , , , , , , , , , , , , , 1], [, 1, , , , , , 1, , , , , 1, , 1, , , 1, 1, , 1, 1, , 1], [, 1, , , , , , 1, , , , , 1, 1, , , , , , , , 1, , , , 1], [, , , , , , , , , , , , , , , , , , 1, , , 1, , , , , 1], [, , , , , , , 1, , , , 1]], [, [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [, 1, , 1, , 1, , , , , , , 1, , , , , , , , 1, 1, , 1], [, 1, , , 1, , , , 1], [, , , , , , , , , , 1], [, 1, , , , , , 1, 1, , , , ,\n    1, 1], , [, 1, 1, , , , , , 1, , , , , 1, 1, , , , 1], [1, , 1, , 1, , , , , 1, , , , , 1, , , , , , , , , 1, 1], [, 1, 1, , , , , , , , , 1, 1, 1, 1, , , , 1, , , , , 1, , , 1], , [, 1, 1, , 1, , , 1, 1, , , 1, , , 1, 1, 1, , 1, , 1, 1, 1, , , , 1], [, 1, , , , 1, , , , , 1, , , 1, 1, , , 1, , 1, , 1, , 1], [, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [, 1, , , 1, 1, , 1, , , , 1, , , , , , , , 1], [, , , 1, , , , , 1, , , , , 1, , 1, , 1, 1, 1], [, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [, , , , , 1], [, 1, , , , , , 1, , , , , , , 1, 1, 1, , , 1], [, 1, , , , , , , , , , 1, 1, 1, , , , , 1, , , 1], [, , , , , 1, , 1, , , , , 1, 1, 1, , 1, 1, , 1, 1, 1, , , 1, 1], [1, 1, , , , , , , 1, , , , , 1, 1, , , , , , , , , , , 1], , [, 1], [, , , , , , , , , , , , , , , , , , , , , , , , 1], [, , 1, , , , , 1, , , 1, , , , 1, , 1], [, 1, , , , , , , , , 1]]];\n    __name(isValidLang, \"isValidLang\");\n  }\n});\n\n// core/audits/seo/hreflang.js\nvar hreflang_exports = {};\n__export(hreflang_exports, {\n  UIStrings: () => UIStrings109,\n  default: () => hreflang_default\n});\nfunction isFullyQualified(href) {\n  return href.startsWith(\"http:\") || href.startsWith(\"https:\");\n}\nfunction isExpectedLanguageCode(hreflang) {\n  if (hreflang.toLowerCase() === NO_LANGUAGE) {\n    return true;\n  }\n  const [lang] = hreflang.split(\"-\");\n  return isValidLang(lang.toLowerCase());\n}\nvar NO_LANGUAGE, UIStrings109, str_89, Hreflang, hreflang_default;\nvar init_hreflang = __esm({\n  \"core/audits/seo/hreflang.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_audit();\n    init_i18n();\n    init_valid_langs();\n    /**\n     * @license\n     * Copyright 2017 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    NO_LANGUAGE = \"x-default\";\n    UIStrings109 = {\n      /** Title of a Lighthouse audit that provides detail on the `hreflang` attribute on a page. This descriptive title is shown when the page's `hreflang` attribute is configured correctly. \"hreflang\" is an HTML attribute and should not be translated. */\n      title: \"Document has a valid `hreflang`\",\n      /** Title of a Lighthouse audit that provides detail on the `hreflang` attribute on a page. This descriptive title is shown when the page's `hreflang` attribute is not valid and needs to be fixed. \"hreflang\" is an HTML attribute and should not be translated. */\n      failureTitle: \"Document doesn't have a valid `hreflang`\",\n      /** Description of a Lighthouse audit that tells the user *why* they need to have an hreflang link on their page. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. \"hreflang\" is an HTML attribute and should not be translated. */\n      description: \"hreflang links tell search engines what version of a page they should list in search results for a given language or region. [Learn more about `hreflang`](https://developer.chrome.com/docs/lighthouse/seo/hreflang/).\",\n      /** A failure reason for a Lighthouse audit that flags incorrect use of the `hreflang` attribute on `link` elements. This failure reason is shown when the hreflang language code is unexpected. */\n      unexpectedLanguage: \"Unexpected language code\",\n      /** A failure reason for a Lighthouse audit that flags incorrect use of the `hreflang` attribute on `link` elements. This failure reason is shown when the `href` attribute value is not fully-qualified. */\n      notFullyQualified: \"Relative href value\"\n    };\n    str_89 = createIcuMessageFn({ url: \"core/audits/seo/hreflang.js\" }.url, UIStrings109);\n    __name(isFullyQualified, \"isFullyQualified\");\n    __name(isExpectedLanguageCode, \"isExpectedLanguageCode\");\n    Hreflang = class extends Audit {\n      static {\n        __name(this, \"Hreflang\");\n      }\n      /**\n       * @return {LH.Audit.Meta}\n       */\n      static get meta() {\n        return {\n          id: \"hreflang\",\n          title: str_89(UIStrings109.title),\n          failureTitle: str_89(UIStrings109.failureTitle),\n          description: str_89(UIStrings109.description),\n          supportedModes: [\"navigation\"],\n          requiredArtifacts: [\"LinkElements\", \"URL\"]\n        };\n      }\n      /**\n       * @param {LH.Artifacts} artifacts\n       * @return {LH.Audit.Product}\n       */\n      static audit({ LinkElements: LinkElements2 }) {\n        const invalidHreflangs = [];\n        const auditableLinkElements = LinkElements2.filter((linkElement) => {\n          const isAlternate = linkElement.rel === \"alternate\";\n          const hasHreflang = linkElement.hreflang;\n          const isInBody = linkElement.source === \"body\";\n          return isAlternate && hasHreflang && !isInBody;\n        });\n        for (const link of auditableLinkElements) {\n          const reasons = [];\n          let source;\n          if (!isExpectedLanguageCode(link.hreflang)) {\n            reasons.push(str_89(UIStrings109.unexpectedLanguage));\n          }\n          if (!isFullyQualified(link.hrefRaw.toLowerCase())) {\n            reasons.push(str_89(UIStrings109.notFullyQualified));\n          }\n          if (link.source === \"head\") {\n            if (link.node) {\n              source = {\n                ...Audit.makeNodeItem(link.node),\n                snippet: `<link rel=\"alternate\" hreflang=\"${link.hreflang}\" href=\"${link.hrefRaw}\" />`\n              };\n            } else {\n              source = {\n                type: \"node\",\n                snippet: `<link rel=\"alternate\" hreflang=\"${link.hreflang}\" href=\"${link.hrefRaw}\" />`\n              };\n            }\n          } else if (link.source === \"headers\") {\n            source = `Link: <${link.hrefRaw}>; rel=\"alternate\"; hreflang=\"${link.hreflang}\"`;\n          }\n          if (!source || !reasons.length) continue;\n          invalidHreflangs.push({\n            source,\n            subItems: {\n              type: \"subitems\",\n              items: reasons.map((reason) => ({ reason }))\n            }\n          });\n        }\n        const headings = [{\n          key: \"source\",\n          valueType: \"code\",\n          subItemsHeading: {\n            key: \"reason\",\n            valueType: \"text\"\n          },\n          label: \"\"\n        }];\n        const details = Audit.makeTableDetails(headings, invalidHreflangs);\n        return {\n          score: Number(invalidHreflangs.length === 0),\n          details\n        };\n      }\n    };\n    hreflang_default = Hreflang;\n  }\n});\n\n// core/audits/seo/http-status-code.js\nvar http_status_code_exports = {};\n__export(http_status_code_exports, {\n  UIStrings: () => UIStrings110,\n  default: () => http_status_code_default\n});\nvar HTTP_UNSUCCESSFUL_CODE_LOW, HTTP_UNSUCCESSFUL_CODE_HIGH, UIStrings110, str_90, HTTPStatusCode, http_status_code_default;\nvar init_http_status_code = __esm({\n  \"core/audits/seo/http-status-code.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_audit();\n    init_i18n();\n    init_main_resource();\n    /**\n     * @license\n     * Copyright 2017 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    HTTP_UNSUCCESSFUL_CODE_LOW = 400;\n    HTTP_UNSUCCESSFUL_CODE_HIGH = 599;\n    UIStrings110 = {\n      /** Title of a Lighthouse audit that provides detail on the HTTP status code a page responds with. This descriptive title is shown when the page has responded with a valid HTTP status code. */\n      title: \"Page has successful HTTP status code\",\n      /** Descriptive title of a Lighthouse audit that provides detail on the HTTP status code a page responds with. This descriptive title is shown when the page responds to requests with an HTTP status code that indicates the request was unsuccessful. */\n      failureTitle: \"Page has unsuccessful HTTP status code\",\n      /** Description of a Lighthouse audit that tells the user *why* they need to serve pages with a valid HTTP status code. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */\n      description: \"Pages with unsuccessful HTTP status codes may not be indexed properly. [Learn more about HTTP status codes](https://developer.chrome.com/docs/lighthouse/seo/http-status-code/).\"\n    };\n    str_90 = createIcuMessageFn({ url: \"core/audits/seo/http-status-code.js\" }.url, UIStrings110);\n    HTTPStatusCode = class extends Audit {\n      static {\n        __name(this, \"HTTPStatusCode\");\n      }\n      /**\n       * @return {LH.Audit.Meta}\n       */\n      static get meta() {\n        return {\n          id: \"http-status-code\",\n          title: str_90(UIStrings110.title),\n          failureTitle: str_90(UIStrings110.failureTitle),\n          description: str_90(UIStrings110.description),\n          requiredArtifacts: [\"DevtoolsLog\", \"URL\", \"GatherContext\"],\n          supportedModes: [\"navigation\"]\n        };\n      }\n      /**\n       * @param {LH.Artifacts} artifacts\n       * @param {LH.Audit.Context} context\n       * @return {Promise<LH.Audit.Product>}\n       */\n      static async audit(artifacts, context) {\n        const devtoolsLog = artifacts.DevtoolsLog;\n        const URL3 = artifacts.URL;\n        const mainResource = await MainResourceComputed.request({ devtoolsLog, URL: URL3 }, context);\n        const statusCode = mainResource.statusCode;\n        if (statusCode >= HTTP_UNSUCCESSFUL_CODE_LOW && statusCode <= HTTP_UNSUCCESSFUL_CODE_HIGH) {\n          return {\n            score: 0,\n            displayValue: `${statusCode}`\n          };\n        }\n        return {\n          score: 1\n        };\n      }\n    };\n    http_status_code_default = HTTPStatusCode;\n  }\n});\n\n// node_modules/robots-parser/Robots.js\nvar require_Robots = __commonJS({\n  \"node_modules/robots-parser/Robots.js\"(exports2, module2) {\n    init_process_global();\n    function trimLine(line) {\n      if (!line) {\n        return null;\n      }\n      if (Array.isArray(line)) {\n        return line.map(trimLine);\n      }\n      return String(line).trim();\n    }\n    __name(trimLine, \"trimLine\");\n    function removeComments(line) {\n      var commentStartIndex = line.indexOf(\"#\");\n      if (commentStartIndex > -1) {\n        return line.substr(0, commentStartIndex);\n      }\n      return line;\n    }\n    __name(removeComments, \"removeComments\");\n    function splitLine(line) {\n      var idx = String(line).indexOf(\":\");\n      if (!line || idx < 0) {\n        return null;\n      }\n      return [line.slice(0, idx), line.slice(idx + 1)];\n    }\n    __name(splitLine, \"splitLine\");\n    function formatUserAgent(userAgent) {\n      var formattedUserAgent = userAgent.toLowerCase();\n      var idx = formattedUserAgent.indexOf(\"/\");\n      if (idx > -1) {\n        formattedUserAgent = formattedUserAgent.substr(0, idx);\n      }\n      return formattedUserAgent.trim();\n    }\n    __name(formatUserAgent, \"formatUserAgent\");\n    function normaliseEncoding(path7) {\n      try {\n        return urlEncodeToUpper(encodeURI(path7).replace(/%25/g, \"%\"));\n      } catch (e) {\n        return path7;\n      }\n    }\n    __name(normaliseEncoding, \"normaliseEncoding\");\n    function urlEncodeToUpper(path7) {\n      return path7.replace(/%[0-9a-fA-F]{2}/g, function(match) {\n        return match.toUpperCase();\n      });\n    }\n    __name(urlEncodeToUpper, \"urlEncodeToUpper\");\n    function matches(pattern, path7) {\n      var matchingLengths = new Array(path7.length + 1);\n      var numMatchingLengths = 1;\n      matchingLengths[0] = 0;\n      for (var p = 0; p < pattern.length; p++) {\n        if (pattern[p] === \"$\" && p + 1 === pattern.length) {\n          return matchingLengths[numMatchingLengths - 1] === path7.length;\n        }\n        if (pattern[p] == \"*\") {\n          numMatchingLengths = path7.length - matchingLengths[0] + 1;\n          for (var i = 1; i < numMatchingLengths; i++) {\n            matchingLengths[i] = matchingLengths[i - 1] + 1;\n          }\n        } else {\n          var numMatches = 0;\n          for (var i = 0; i < numMatchingLengths; i++) {\n            if (matchingLengths[i] < path7.length && path7[matchingLengths[i]] === pattern[p]) {\n              matchingLengths[numMatches++] = matchingLengths[i] + 1;\n            }\n          }\n          if (numMatches == 0) {\n            return false;\n          }\n          numMatchingLengths = numMatches;\n        }\n      }\n      return true;\n    }\n    __name(matches, \"matches\");\n    function parseRobots(contents, robots) {\n      var newlineRegex = /\\r\\n|\\r|\\n/;\n      var lines = contents.split(newlineRegex).map(removeComments).map(splitLine).map(trimLine);\n      var currentUserAgents = [];\n      var isNoneUserAgentState = true;\n      for (var i = 0; i < lines.length; i++) {\n        var line = lines[i];\n        if (!line || !line[0]) {\n          continue;\n        }\n        switch (line[0].toLowerCase()) {\n          case \"user-agent\":\n            if (isNoneUserAgentState) {\n              currentUserAgents.length = 0;\n            }\n            if (line[1]) {\n              currentUserAgents.push(formatUserAgent(line[1]));\n            }\n            break;\n          case \"disallow\":\n            robots.addRule(currentUserAgents, line[1], false, i + 1);\n            break;\n          case \"allow\":\n            robots.addRule(currentUserAgents, line[1], true, i + 1);\n            break;\n          case \"crawl-delay\":\n            robots.setCrawlDelay(currentUserAgents, line[1]);\n            break;\n          case \"sitemap\":\n            if (line[1]) {\n              robots.addSitemap(line[1]);\n            }\n            break;\n          case \"host\":\n            if (line[1]) {\n              robots.setPreferredHost(line[1].toLowerCase());\n            }\n            break;\n        }\n        isNoneUserAgentState = line[0].toLowerCase() !== \"user-agent\";\n      }\n    }\n    __name(parseRobots, \"parseRobots\");\n    function findRule(path7, rules) {\n      var matchedRule = null;\n      for (var i = 0; i < rules.length; i++) {\n        var rule = rules[i];\n        if (!matches(rule.pattern, path7)) {\n          continue;\n        }\n        if (!matchedRule || rule.pattern.length > matchedRule.pattern.length) {\n          matchedRule = rule;\n        } else if (rule.pattern.length == matchedRule.pattern.length && rule.allow && !matchedRule.allow) {\n          matchedRule = rule;\n        }\n      }\n      return matchedRule;\n    }\n    __name(findRule, \"findRule\");\n    function parseUrl(url) {\n      try {\n        var url = new URL(url, \"http://robots-relative.samclarke.com/\");\n        if (!url.port) {\n          url.port = url.protocol === \"https:\" ? 443 : 80;\n        }\n        return url;\n      } catch (e) {\n        return null;\n      }\n    }\n    __name(parseUrl, \"parseUrl\");\n    function Robots(url, contents) {\n      this._url = parseUrl(url) || {};\n      this._rules = /* @__PURE__ */ Object.create(null);\n      this._sitemaps = [];\n      this._preferredHost = null;\n      parseRobots(contents || \"\", this);\n    }\n    __name(Robots, \"Robots\");\n    Robots.prototype.addRule = function(userAgents2, pattern, allow, lineNumber) {\n      var rules = this._rules;\n      userAgents2.forEach(function(userAgent) {\n        rules[userAgent] = rules[userAgent] || [];\n        if (!pattern) {\n          return;\n        }\n        rules[userAgent].push({\n          pattern: normaliseEncoding(pattern),\n          allow,\n          lineNumber\n        });\n      });\n    };\n    Robots.prototype.setCrawlDelay = function(userAgents2, delayStr) {\n      var rules = this._rules;\n      var delay = Number(delayStr);\n      userAgents2.forEach(function(userAgent) {\n        rules[userAgent] = rules[userAgent] || [];\n        if (isNaN(delay)) {\n          return;\n        }\n        rules[userAgent].crawlDelay = delay;\n      });\n    };\n    Robots.prototype.addSitemap = function(url) {\n      this._sitemaps.push(url);\n    };\n    Robots.prototype.setPreferredHost = function(url) {\n      this._preferredHost = url;\n    };\n    Robots.prototype._getRule = function(url, ua) {\n      var parsedUrl = parseUrl(url) || {};\n      var userAgent = formatUserAgent(ua || \"*\");\n      if (parsedUrl.protocol !== this._url.protocol || parsedUrl.hostname !== this._url.hostname || parsedUrl.port !== this._url.port) {\n        return;\n      }\n      var rules = this._rules[userAgent] || this._rules[\"*\"] || [];\n      var path7 = urlEncodeToUpper(parsedUrl.pathname + parsedUrl.search);\n      var rule = findRule(path7, rules);\n      return rule;\n    };\n    Robots.prototype.isAllowed = function(url, ua) {\n      var rule = this._getRule(url, ua);\n      if (typeof rule === \"undefined\") {\n        return;\n      }\n      return !rule || rule.allow;\n    };\n    Robots.prototype.getMatchingLineNumber = function(url, ua) {\n      var rule = this._getRule(url, ua);\n      return rule ? rule.lineNumber : -1;\n    };\n    Robots.prototype.isDisallowed = function(url, ua) {\n      return !this.isAllowed(url, ua);\n    };\n    Robots.prototype.getCrawlDelay = function(ua) {\n      var userAgent = formatUserAgent(ua || \"*\");\n      return (this._rules[userAgent] || this._rules[\"*\"] || {}).crawlDelay;\n    };\n    Robots.prototype.getPreferredHost = function() {\n      return this._preferredHost;\n    };\n    Robots.prototype.getSitemaps = function() {\n      return this._sitemaps.slice(0);\n    };\n    module2.exports = Robots;\n  }\n});\n\n// node_modules/robots-parser/index.js\nvar require_robots_parser = __commonJS({\n  \"node_modules/robots-parser/index.js\"(exports2, module2) {\n    init_process_global();\n    var Robots = require_Robots();\n    module2.exports = function(url, contents) {\n      return new Robots(url, contents);\n    };\n  }\n});\n\n// core/audits/seo/is-crawlable.js\nvar is_crawlable_exports = {};\n__export(is_crawlable_exports, {\n  UIStrings: () => UIStrings111,\n  default: () => is_crawlable_default\n});\nfunction isUnavailable(directive) {\n  const parts = directive.split(\":\");\n  if (parts.length <= 1 || parts[0] !== UNAVAILABLE_AFTER) {\n    return false;\n  }\n  const date = Date.parse(parts.slice(1).join(\":\"));\n  return !isNaN(date) && date < Date.now();\n}\nfunction hasBlockingDirective(directives) {\n  return directives.split(\",\").map((d) => d.toLowerCase().trim()).some((d) => BLOCKLIST.has(d) || isUnavailable(d));\n}\nfunction getUserAgentFromHeaderDirectives(directives) {\n  const parts = directives.match(/^([^,:]+):/);\n  if (!!parts && parts[1].toLowerCase() !== UNAVAILABLE_AFTER) {\n    return parts[1];\n  }\n}\nvar import_robots_parser, BOT_USER_AGENTS, BLOCKLIST, ROBOTS_HEADER, UNAVAILABLE_AFTER, UIStrings111, str_91, IsCrawlable, is_crawlable_default;\nvar init_is_crawlable = __esm({\n  \"core/audits/seo/is-crawlable.js\"() {\n    \"use strict\";\n    init_process_global();\n    import_robots_parser = __toESM(require_robots_parser(), 1);\n    init_audit();\n    init_main_resource();\n    init_i18n();\n    /**\n     * @license\n     * Copyright 2017 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    BOT_USER_AGENTS = /* @__PURE__ */ new Set([\n      void 0,\n      \"Googlebot\",\n      \"bingbot\",\n      \"DuckDuckBot\",\n      \"archive.org_bot\"\n    ]);\n    BLOCKLIST = /* @__PURE__ */ new Set([\n      \"noindex\",\n      \"none\"\n    ]);\n    ROBOTS_HEADER = \"x-robots-tag\";\n    UNAVAILABLE_AFTER = \"unavailable_after\";\n    UIStrings111 = {\n      /** Title of a Lighthouse audit that provides detail on if search-engine crawlers are blocked from indexing the page. This title is shown when the page is not blocked from indexing and can be crawled. */\n      title: \"Page isn’t blocked from indexing\",\n      /** Title of a Lighthouse audit that provides detail on if search-engine crawlers are blocked from indexing the page. This title is shown when the page has been configured to block indexing and therefore cannot be indexed by search engines. */\n      failureTitle: \"Page is blocked from indexing\",\n      /** Description of a Lighthouse audit that tells the user *why* allowing search-engine crawling of their page is beneficial. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */\n      description: \"Search engines are unable to include your pages in search results if they don't have permission to crawl them. [Learn more about crawler directives](https://developer.chrome.com/docs/lighthouse/seo/is-crawlable/).\"\n    };\n    str_91 = createIcuMessageFn({ url: \"core/audits/seo/is-crawlable.js\" }.url, UIStrings111);\n    __name(isUnavailable, \"isUnavailable\");\n    __name(hasBlockingDirective, \"hasBlockingDirective\");\n    __name(getUserAgentFromHeaderDirectives, \"getUserAgentFromHeaderDirectives\");\n    IsCrawlable = class _IsCrawlable extends Audit {\n      static {\n        __name(this, \"IsCrawlable\");\n      }\n      /**\n       * @return {LH.Audit.Meta}\n       */\n      static get meta() {\n        return {\n          id: \"is-crawlable\",\n          title: str_91(UIStrings111.title),\n          failureTitle: str_91(UIStrings111.failureTitle),\n          description: str_91(UIStrings111.description),\n          supportedModes: [\"navigation\"],\n          requiredArtifacts: [\"MetaElements\", \"RobotsTxt\", \"URL\", \"DevtoolsLog\"]\n        };\n      }\n      /**\n       * @param {LH.Artifacts.MetaElement} metaElement\n       */\n      static handleMetaElement(metaElement) {\n        const content = metaElement.content || \"\";\n        if (hasBlockingDirective(content)) {\n          return {\n            source: {\n              ...Audit.makeNodeItem(metaElement.node),\n              snippet: `<meta name=\"${metaElement.name}\" content=\"${content}\" />`\n            }\n          };\n        }\n      }\n      /**\n       * @param {string|undefined} userAgent\n       * @param {LH.Artifacts.NetworkRequest} mainResource\n       * @param {LH.Artifacts.MetaElement[]} metaElements\n       * @param {import('robots-parser').Robot|undefined} parsedRobotsTxt\n       * @param {URL} robotsTxtUrl\n       */\n      static determineIfCrawlableForUserAgent(userAgent, mainResource, metaElements, parsedRobotsTxt, robotsTxtUrl) {\n        const blockingDirectives = [];\n        let meta;\n        if (userAgent) meta = metaElements.find((meta2) => meta2.name === userAgent.toLowerCase());\n        if (!meta) meta = metaElements.find((meta2) => meta2.name === \"robots\");\n        if (meta) {\n          const blockingDirective = _IsCrawlable.handleMetaElement(meta);\n          if (blockingDirective) blockingDirectives.push(blockingDirective);\n        }\n        for (const header of mainResource.responseHeaders || []) {\n          if (header.name.toLowerCase() !== ROBOTS_HEADER) continue;\n          const directiveUserAgent = getUserAgentFromHeaderDirectives(header.value);\n          if (directiveUserAgent !== userAgent && directiveUserAgent !== void 0) continue;\n          let directiveWithoutUserAgentPrefix = header.value.trim();\n          if (userAgent && header.value.startsWith(`${userAgent}:`)) {\n            directiveWithoutUserAgentPrefix = header.value.replace(`${userAgent}:`, \"\");\n          }\n          if (!hasBlockingDirective(directiveWithoutUserAgentPrefix)) continue;\n          blockingDirectives.push({ source: `${header.name}: ${header.value}` });\n        }\n        if (parsedRobotsTxt && !parsedRobotsTxt.isAllowed(mainResource.url, userAgent)) {\n          const line = parsedRobotsTxt.getMatchingLineNumber(mainResource.url) || 1;\n          blockingDirectives.push({\n            source: {\n              type: (\n                /** @type {const} */\n                \"source-location\"\n              ),\n              url: robotsTxtUrl.href,\n              urlProvider: (\n                /** @type {const} */\n                \"network\"\n              ),\n              line: line - 1,\n              column: 0\n            }\n          });\n        }\n        return blockingDirectives;\n      }\n      /**\n       * @param {LH.Artifacts} artifacts\n       * @param {LH.Audit.Context} context\n       * @return {Promise<LH.Audit.Product>}\n       */\n      static async audit(artifacts, context) {\n        const devtoolsLog = artifacts.DevtoolsLog;\n        const mainResource = await MainResourceComputed.request({ devtoolsLog, URL: artifacts.URL }, context);\n        const robotsTxtUrl = new URL(\"/robots.txt\", mainResource.url);\n        const parsedRobotsTxt = artifacts.RobotsTxt.content ? (0, import_robots_parser.default)(robotsTxtUrl.href, artifacts.RobotsTxt.content) : void 0;\n        const blockedUserAgents = [];\n        const genericBlockingDirectives = [];\n        for (const userAgent of BOT_USER_AGENTS) {\n          const blockingDirectives = _IsCrawlable.determineIfCrawlableForUserAgent(\n            userAgent,\n            mainResource,\n            artifacts.MetaElements,\n            parsedRobotsTxt,\n            robotsTxtUrl\n          );\n          if (blockingDirectives.length > 0) {\n            blockedUserAgents.push(userAgent);\n          }\n          if (userAgent === void 0) {\n            genericBlockingDirectives.push(...blockingDirectives);\n          }\n        }\n        const score = blockedUserAgents.length === BOT_USER_AGENTS.size ? 0 : 1;\n        const warnings = [];\n        if (score && blockedUserAgents.length > 0) {\n          const list = blockedUserAgents.filter(Boolean).join(\", \");\n          warnings.push(`The following bot user agents are blocked from crawling: ${list}. The audit is otherwise passing, because at least one bot was explicitly allowed.`);\n        }\n        const headings = [\n          { key: \"source\", valueType: \"code\", label: \"Blocking Directive Source\" }\n        ];\n        const details = Audit.makeTableDetails(headings, score === 0 ? genericBlockingDirectives : []);\n        return {\n          score,\n          details,\n          warnings\n        };\n      }\n    };\n    is_crawlable_default = IsCrawlable;\n  }\n});\n\n// core/audits/seo/link-text.js\nvar link_text_exports = {};\n__export(link_text_exports, {\n  UIStrings: () => UIStrings112,\n  default: () => link_text_default\n});\nvar nonDescriptiveLinkTexts, UIStrings112, str_92, LinkText, link_text_default;\nvar init_link_text = __esm({\n  \"core/audits/seo/link-text.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_audit();\n    init_url_utils();\n    init_i18n();\n    /**\n     * @license\n     * Copyright 2017 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    nonDescriptiveLinkTexts = {\n      // English\n      \"en\": /* @__PURE__ */ new Set([\n        \"click here\",\n        \"click this\",\n        \"go\",\n        \"here\",\n        \"information\",\n        \"learn more\",\n        \"more\",\n        \"more info\",\n        \"more information\",\n        \"right here\",\n        \"read more\",\n        \"see more\",\n        \"start\",\n        \"this\"\n      ]),\n      // Japanese\n      \"ja\": /* @__PURE__ */ new Set([\n        \"ここをクリック\",\n        \"こちらをクリック\",\n        \"リンク\",\n        \"続きを読む\",\n        \"続く\",\n        \"全文表示\"\n      ]),\n      // Spanish\n      \"es\": /* @__PURE__ */ new Set([\n        \"click aquí\",\n        \"click aqui\",\n        \"clicka aquí\",\n        \"clicka aqui\",\n        \"pincha aquí\",\n        \"pincha aqui\",\n        \"aquí\",\n        \"aqui\",\n        \"más\",\n        \"mas\",\n        \"más información\",\n        \"más informacion\",\n        \"mas información\",\n        \"mas informacion\",\n        \"este\",\n        \"enlace\",\n        \"este enlace\",\n        \"empezar\"\n      ]),\n      // Portuguese\n      \"pt\": /* @__PURE__ */ new Set([\n        \"clique aqui\",\n        \"ir\",\n        \"mais informação\",\n        \"mais informações\",\n        \"mais\",\n        \"veja mais\"\n      ]),\n      // Korean\n      \"ko\": /* @__PURE__ */ new Set([\n        \"여기\",\n        \"여기를 클릭\",\n        \"클릭\",\n        \"링크\",\n        \"자세히\",\n        \"자세히 보기\",\n        \"계속\",\n        \"이동\",\n        \"전체 보기\"\n      ]),\n      // Swedish\n      \"sv\": /* @__PURE__ */ new Set([\n        \"här\",\n        \"klicka här\",\n        \"läs mer\",\n        \"mer\",\n        \"mer info\",\n        \"mer information\"\n      ]),\n      // German\n      \"de\": /* @__PURE__ */ new Set([\n        \"klicke hier\",\n        \"hier klicken\",\n        \"hier\",\n        \"mehr\",\n        \"siehe\",\n        \"dies\",\n        \"das\",\n        \"weiterlesen\"\n      ]),\n      // Tamil\n      \"ta\": /* @__PURE__ */ new Set([\n        \"அடுத்த பக்கம்\",\n        \"மறுபக்கம்\",\n        \"முந்தைய பக்கம்\",\n        \"முன்பக்கம்\",\n        \"மேலும் அறிக\",\n        \"மேலும் தகவலுக்கு\",\n        \"மேலும் தரவுகளுக்கு\",\n        \"தயவுசெய்து இங்கே அழுத்தவும்\",\n        \"இங்கே கிளிக் செய்யவும்\"\n      ]),\n      // Persian\n      \"fa\": /* @__PURE__ */ new Set([\n        \"اطلاعات بیشتر\",\n        \"اطلاعات\",\n        \"این\",\n        \"اینجا بزنید\",\n        \"اینجا کلیک کنید\",\n        \"اینجا\",\n        \"برو\",\n        \"بیشتر بخوانید\",\n        \"بیشتر بدانید\",\n        \"بیشتر\",\n        \"شروع\"\n      ])\n    };\n    UIStrings112 = {\n      /** Title of a Lighthouse audit that tests if each link on a page contains a sufficient description of what a user will find when they click it. Generic, non-descriptive text like \"click here\" doesn't give an indication of what the link leads to. This descriptive title is shown when all links on the page have sufficient textual descriptions. */\n      title: \"Links have descriptive text\",\n      /** Title of a Lighthouse audit that tests if each link on a page contains a sufficient description of what a user will find when they click it. Generic, non-descriptive text like \"click here\" doesn't give an indication of what the link leads to. This descriptive title is shown when one or more links on the page contain generic, non-descriptive text. */\n      failureTitle: \"Links do not have descriptive text\",\n      /** Description of a Lighthouse audit that tells the user *why* they need to have descriptive text on the links in their page. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */\n      description: \"Descriptive link text helps search engines understand your content. [Learn how to make links more accessible](https://developer.chrome.com/docs/lighthouse/seo/link-text/).\",\n      /** [ICU Syntax] Label for the audit identifying the number of links found. \"link\" here refers to the links in a web page to other web pages. */\n      displayValue: `{itemCount, plural,\n    =1 {1 link found}\n    other {# links found}\n    }`\n    };\n    str_92 = createIcuMessageFn({ url: \"core/audits/seo/link-text.js\" }.url, UIStrings112);\n    LinkText = class extends Audit {\n      static {\n        __name(this, \"LinkText\");\n      }\n      /**\n       * @return {LH.Audit.Meta}\n       */\n      static get meta() {\n        return {\n          id: \"link-text\",\n          title: str_92(UIStrings112.title),\n          failureTitle: str_92(UIStrings112.failureTitle),\n          description: str_92(UIStrings112.description),\n          requiredArtifacts: [\"URL\", \"AnchorElements\"]\n        };\n      }\n      /**\n       * @param {LH.Artifacts} artifacts\n       * @return {LH.Audit.Product}\n       */\n      static audit(artifacts) {\n        const failingLinks = artifacts.AnchorElements.filter((link) => {\n          if (!link.href || link.rel.includes(\"nofollow\")) return false;\n          const href = link.href.toLowerCase();\n          if (href.startsWith(\"javascript:\") || href.startsWith(\"mailto:\") || // This line prevents the audit from flagging anchor links.\n          // In this case it is better to use `finalDisplayedUrl` than `mainDocumentUrl`.\n          url_utils_default.equalWithExcludedFragments(link.href, artifacts.URL.finalDisplayedUrl)) {\n            return false;\n          }\n          const searchTerm = link.text.trim().toLowerCase();\n          if (searchTerm) {\n            if (link.textLang) {\n              const lang = link.textLang.split(\"-\")[0];\n              if (nonDescriptiveLinkTexts[lang] && nonDescriptiveLinkTexts[lang].has(searchTerm)) {\n                return true;\n              }\n            } else {\n              for (const texts of Object.values(nonDescriptiveLinkTexts)) {\n                if (texts.has(searchTerm)) {\n                  return true;\n                }\n              }\n            }\n          }\n          return false;\n        }).map((link) => {\n          return {\n            href: link.href,\n            text: link.text.trim(),\n            textLang: link.textLang\n          };\n        });\n        const headings = [\n          { key: \"href\", valueType: \"url\", label: \"Link destination\" },\n          { key: \"text\", valueType: \"text\", label: \"Link Text\" }\n        ];\n        const details = Audit.makeTableDetails(headings, failingLinks);\n        let displayValue;\n        if (failingLinks.length) {\n          displayValue = str_92(UIStrings112.displayValue, { itemCount: failingLinks.length });\n        }\n        return {\n          score: Number(failingLinks.length === 0),\n          details,\n          displayValue\n        };\n      }\n    };\n    link_text_default = LinkText;\n  }\n});\n\n// core/audits/seo/manual/structured-data.js\nvar structured_data_exports = {};\n__export(structured_data_exports, {\n  UIStrings: () => UIStrings113,\n  default: () => structured_data_default\n});\nvar UIStrings113, str_93, StructuredData, structured_data_default;\nvar init_structured_data = __esm({\n  \"core/audits/seo/manual/structured-data.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_manual_audit();\n    init_i18n();\n    /**\n     * @license\n     * Copyright 2017 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    UIStrings113 = {\n      /** Description of a Lighthouse audit that provides detail on the structured data in a page. \"Structured data\" is a standardized data format on a page that helps a search engine categorize and understand its contents. This description is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */\n      description: \"Run the [Structured Data Testing Tool](https://developers.google.com/search/docs/appearance/structured-data/) to validate structured data. [Learn more about Structured Data](https://developer.chrome.com/docs/lighthouse/seo/structured-data/).\",\n      /** Title of a Lighthouse audit that prompts users to manually check their page for valid structured data. \"Structured data\" is a standardized data format on a page that helps a search engine categorize and understand its contents. */\n      title: \"Structured data is valid\"\n    };\n    str_93 = createIcuMessageFn({ url: \"core/audits/seo/manual/structured-data.js\" }.url, UIStrings113);\n    StructuredData = class extends manual_audit_default {\n      static {\n        __name(this, \"StructuredData\");\n      }\n      /**\n       * @return {LH.Audit.Meta}\n       */\n      static get meta() {\n        return Object.assign({\n          id: \"structured-data\",\n          description: str_93(UIStrings113.description),\n          title: str_93(UIStrings113.title)\n        }, super.partialMeta);\n      }\n    };\n    structured_data_default = StructuredData;\n  }\n});\n\n// core/audits/seo/meta-description.js\nvar meta_description_exports = {};\n__export(meta_description_exports, {\n  UIStrings: () => UIStrings114,\n  default: () => meta_description_default\n});\nvar UIStrings114, str_94, Description, meta_description_default;\nvar init_meta_description = __esm({\n  \"core/audits/seo/meta-description.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_audit();\n    init_i18n();\n    /**\n     * @license\n     * Copyright 2017 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    UIStrings114 = {\n      /** Title of a Lighthouse audit that provides detail on the web page's document meta description. This descriptive title is shown when the document has a meta description. \"meta\" should be left untranslated because it refers to an HTML element. */\n      title: \"Document has a meta description\",\n      /** Title of a Lighthouse audit that provides detail on the web page's document meta description. This descriptive title is shown when the document does not have a meta description. \"meta\" should be left untranslated because it refers to an HTML element. */\n      failureTitle: \"Document does not have a meta description\",\n      /** Description of a Lighthouse audit that tells the user *why* they need to have meta descriptions on their page. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */\n      description: \"Meta descriptions may be included in search results to concisely summarize page content. [Learn more about the meta description](https://developer.chrome.com/docs/lighthouse/seo/meta-description/).\",\n      /** Explanatory message stating that there was a failure in an audit caused by the page's meta description text being empty. */\n      explanation: \"Description text is empty.\"\n    };\n    str_94 = createIcuMessageFn({ url: \"core/audits/seo/meta-description.js\" }.url, UIStrings114);\n    Description = class extends Audit {\n      static {\n        __name(this, \"Description\");\n      }\n      /**\n       * @return {LH.Audit.Meta}\n       */\n      static get meta() {\n        return {\n          id: \"meta-description\",\n          title: str_94(UIStrings114.title),\n          failureTitle: str_94(UIStrings114.failureTitle),\n          description: str_94(UIStrings114.description),\n          requiredArtifacts: [\"MetaElements\"]\n        };\n      }\n      /**\n       * @param {LH.Artifacts} artifacts\n       * @return {LH.Audit.Product}\n       */\n      static audit(artifacts) {\n        const metaDescription = artifacts.MetaElements.find((meta) => meta.name === \"description\");\n        if (!metaDescription) {\n          return {\n            score: 0\n          };\n        }\n        const description = metaDescription.content || \"\";\n        if (description.trim().length === 0) {\n          return {\n            score: 0,\n            explanation: str_94(UIStrings114.explanation)\n          };\n        }\n        return {\n          score: 1\n        };\n      }\n    };\n    meta_description_default = Description;\n  }\n});\n\n// core/audits/seo/robots-txt.js\nvar robots_txt_exports2 = {};\n__export(robots_txt_exports2, {\n  UIStrings: () => UIStrings115,\n  default: () => robots_txt_default2\n});\nfunction verifyDirective(directiveName, directiveValue) {\n  if (!DIRECTIVE_SAFELIST.has(directiveName)) {\n    throw new Error(\"Unknown directive\");\n  }\n  if (directiveName === DIRECTIVE_SITEMAP) {\n    let sitemapUrl;\n    try {\n      sitemapUrl = new URL(directiveValue);\n    } catch (e) {\n      throw new Error(\"Invalid sitemap URL\");\n    }\n    if (!SITEMAP_VALID_PROTOCOLS.has(sitemapUrl.protocol)) {\n      throw new Error(\"Invalid sitemap URL protocol\");\n    }\n  }\n  if (directiveName === DIRECTIVE_USER_AGENT && !directiveValue) {\n    throw new Error(\"No user-agent specified\");\n  }\n  if (directiveName === DIRECTIVE_ALLOW || directiveName === DIRECTIVE_DISALLOW) {\n    if (directiveValue !== \"\" && directiveValue[0] !== \"/\" && directiveValue[0] !== \"*\") {\n      throw new Error('Pattern should either be empty, start with \"/\" or \"*\"');\n    }\n    const dollarIndex = directiveValue.indexOf(\"$\");\n    if (dollarIndex !== -1 && dollarIndex !== directiveValue.length - 1) {\n      throw new Error('\"$\" should only be used at the end of the pattern');\n    }\n  }\n}\nfunction parseLine(line) {\n  const hashIndex = line.indexOf(\"#\");\n  if (hashIndex !== -1) {\n    line = line.substr(0, hashIndex);\n  }\n  line = line.trim();\n  if (line.length === 0) {\n    return null;\n  }\n  const colonIndex = line.indexOf(\":\");\n  if (colonIndex === -1) {\n    throw new Error(\"Syntax not understood\");\n  }\n  const directiveName = line.slice(0, colonIndex).trim().toLowerCase();\n  const directiveValue = line.slice(colonIndex + 1).trim();\n  verifyDirective(directiveName, directiveValue);\n  return {\n    directive: directiveName,\n    value: directiveValue\n  };\n}\nfunction validateRobots(content) {\n  const errors = [];\n  let inGroup = false;\n  content.split(/\\r\\n|\\r|\\n/).forEach((line, index) => {\n    let parsedLine;\n    try {\n      parsedLine = parseLine(line);\n    } catch (e) {\n      errors.push({\n        index: (index + 1).toString(),\n        line,\n        message: e.message.toString()\n      });\n    }\n    if (!parsedLine) {\n      return;\n    }\n    if (parsedLine.directive === DIRECTIVE_USER_AGENT) {\n      inGroup = true;\n    } else if (!inGroup && DIRECTIVES_GROUP_MEMBERS.has(parsedLine.directive)) {\n      errors.push({\n        index: (index + 1).toString(),\n        line,\n        message: \"No user-agent specified\"\n      });\n    }\n  });\n  return errors;\n}\nvar HTTP_CLIENT_ERROR_CODE_LOW, HTTP_SERVER_ERROR_CODE_LOW, DIRECTIVE_SITEMAP, DIRECTIVE_USER_AGENT, DIRECTIVE_ALLOW, DIRECTIVE_DISALLOW, DIRECTIVES_GROUP_MEMBERS, DIRECTIVE_SAFELIST, SITEMAP_VALID_PROTOCOLS, UIStrings115, str_95, RobotsTxt2, robots_txt_default2;\nvar init_robots_txt2 = __esm({\n  \"core/audits/seo/robots-txt.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_audit();\n    init_i18n();\n    /**\n     * @license\n     * Copyright 2018 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    HTTP_CLIENT_ERROR_CODE_LOW = 400;\n    HTTP_SERVER_ERROR_CODE_LOW = 500;\n    DIRECTIVE_SITEMAP = \"sitemap\";\n    DIRECTIVE_USER_AGENT = \"user-agent\";\n    DIRECTIVE_ALLOW = \"allow\";\n    DIRECTIVE_DISALLOW = \"disallow\";\n    DIRECTIVES_GROUP_MEMBERS = /* @__PURE__ */ new Set([DIRECTIVE_ALLOW, DIRECTIVE_DISALLOW]);\n    DIRECTIVE_SAFELIST = /* @__PURE__ */ new Set([\n      DIRECTIVE_USER_AGENT,\n      DIRECTIVE_DISALLOW,\n      // standard\n      DIRECTIVE_ALLOW,\n      DIRECTIVE_SITEMAP,\n      // universally supported\n      \"crawl-delay\",\n      // yahoo, bing, yandex\n      \"clean-param\",\n      \"host\",\n      // yandex\n      \"request-rate\",\n      \"visit-time\",\n      \"noindex\",\n      \"content-signal\"\n      // not officially supported, but used in the wild\n    ]);\n    SITEMAP_VALID_PROTOCOLS = /* @__PURE__ */ new Set([\"https:\", \"http:\", \"ftp:\"]);\n    UIStrings115 = {\n      /** Title of a Lighthouse audit that provides detail on the site's robots.txt file. Note: \"robots.txt\" is a canonical filename and should not be translated. This descriptive title is shown when the robots.txt file is present and configured correctly. */\n      title: \"robots.txt is valid\",\n      /** Title of a Lighthouse audit that provides detail on the site's robots.txt file. Note: \"robots.txt\" is a canonical filename and should not be translated. This descriptive title is shown when the robots.txt file is misconfigured, which makes the page hard or impossible to scan via web crawler. */\n      failureTitle: \"robots.txt is not valid\",\n      /** Description of a Lighthouse audit that tells the user *why* they need to have a valid robots.txt file. Note: \"robots.txt\" is a canonical filename and should not be translated. This is displayed after a user expands the section to see more. No character length limits. */\n      description: \"If your robots.txt file is malformed, crawlers may not be able to understand how you want your website to be crawled or indexed. [Learn more about robots.txt](https://developer.chrome.com/docs/lighthouse/seo/invalid-robots-txt/).\",\n      /**\n       * @description Label for the audit identifying that the robots.txt request has returned a specific HTTP status code. Note: \"robots.txt\" is a canonical filename and should not be translated.\n       * @example {500} statusCode\n       * */\n      displayValueHttpBadCode: \"Request for robots.txt returned HTTP status: {statusCode}\",\n      /** [ICU Syntax] Label for the audit identifying the number of errors that occured while validating the robots.txt file. \"itemCount\" will be replaced by the integer count of errors encountered. */\n      displayValueValidationError: `{itemCount, plural,\n    =1 {1 error found}\n    other {# errors found}\n    }`,\n      /** Explanatory message stating that there was a failure in an audit caused by Lighthouse not being able to download the robots.txt file for the site.  Note: \"robots.txt\" is a canonical filename and should not be translated. */\n      explanation: \"Lighthouse was unable to download a robots.txt file\"\n    };\n    str_95 = createIcuMessageFn({ url: \"core/audits/seo/robots-txt.js\" }.url, UIStrings115);\n    __name(verifyDirective, \"verifyDirective\");\n    __name(parseLine, \"parseLine\");\n    __name(validateRobots, \"validateRobots\");\n    RobotsTxt2 = class extends Audit {\n      static {\n        __name(this, \"RobotsTxt\");\n      }\n      /**\n       * @return {LH.Audit.Meta}\n       */\n      static get meta() {\n        return {\n          id: \"robots-txt\",\n          title: str_95(UIStrings115.title),\n          failureTitle: str_95(UIStrings115.failureTitle),\n          description: str_95(UIStrings115.description),\n          requiredArtifacts: [\"RobotsTxt\"]\n        };\n      }\n      /**\n       * @param {LH.Artifacts} artifacts\n       * @return {LH.Audit.Product}\n       */\n      static audit(artifacts) {\n        const {\n          status,\n          content\n        } = artifacts.RobotsTxt;\n        if (!status) {\n          return {\n            score: 0,\n            explanation: str_95(UIStrings115.explanation)\n          };\n        }\n        if (status >= HTTP_SERVER_ERROR_CODE_LOW) {\n          return {\n            score: 0,\n            displayValue: str_95(UIStrings115.displayValueHttpBadCode, { statusCode: status })\n          };\n        } else if (status >= HTTP_CLIENT_ERROR_CODE_LOW || content === \"\") {\n          return {\n            score: 1,\n            notApplicable: true\n          };\n        }\n        if (content === null) {\n          throw new Error(`Status ${status} was valid, but content was null`);\n        }\n        const validationErrors = validateRobots(content);\n        const headings = [\n          { key: \"index\", valueType: \"text\", label: \"Line #\" },\n          { key: \"line\", valueType: \"code\", label: \"Content\" },\n          { key: \"message\", valueType: \"code\", label: \"Error\" }\n        ];\n        const details = Audit.makeTableDetails(headings, validationErrors);\n        let displayValue;\n        if (validationErrors.length) {\n          displayValue = str_95(UIStrings115.displayValueValidationError, { itemCount: validationErrors.length });\n        }\n        return {\n          score: Number(validationErrors.length === 0),\n          details,\n          displayValue\n        };\n      }\n    };\n    robots_txt_default2 = RobotsTxt2;\n  }\n});\n\n// core/audits/third-party-cookies.js\nvar third_party_cookies_exports = {};\n__export(third_party_cookies_exports, {\n  UIStrings: () => UIStrings116,\n  default: () => third_party_cookies_default\n});\nvar UIStrings116, str_96, ThirdPartyCookies, third_party_cookies_default;\nvar init_third_party_cookies = __esm({\n  \"core/audits/third-party-cookies.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_audit();\n    init_i18n();\n    /**\n     * @license\n     * Copyright 2023 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    UIStrings116 = {\n      /** Title of a Lighthouse audit that provides detail on the use of third party cookies. This descriptive title is shown to users when the page does not use third party cookies. */\n      title: \"Avoids third-party cookies\",\n      /** Title of a Lighthouse audit that provides detail on the use of third party cookies. This descriptive title is shown to users when the page uses third party cookies. */\n      failureTitle: \"Uses third-party cookies\",\n      /** Description of a Lighthouse audit that tells the user why they should not use third party cookies on their page. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */\n      description: \"Third-party cookies may be blocked in some contexts. [Learn more about preparing for third-party cookie restrictions](https://privacysandbox.google.com/cookies/prepare/overview).\",\n      /** [ICU Syntax] Label for the audit identifying the number of third-party cookies. */\n      displayValue: `{itemCount, plural,\n    =1 {1 cookie found}\n    other {# cookies found}\n    }`\n    };\n    str_96 = createIcuMessageFn({ url: \"core/audits/third-party-cookies.js\" }.url, UIStrings116);\n    ThirdPartyCookies = class extends Audit {\n      static {\n        __name(this, \"ThirdPartyCookies\");\n      }\n      /**\n       * @return {LH.Audit.Meta}\n       */\n      static get meta() {\n        return {\n          id: \"third-party-cookies\",\n          title: str_96(UIStrings116.title),\n          failureTitle: str_96(UIStrings116.failureTitle),\n          description: str_96(UIStrings116.description),\n          requiredArtifacts: [\"InspectorIssues\"]\n        };\n      }\n      /**\n       * https://source.chromium.org/chromium/chromium/src/+/d2fcd4ba302baeabf4b96d8fa9fdb7a215736c31:third_party/devtools-frontend/src/front_end/models/issues_manager/CookieIssue.ts;l=62-69\n       * @param {LH.Crdp.Audits.CookieIssueDetails} cookieIssue\n       * @return {string}\n       */\n      static getCookieId(cookieIssue) {\n        if (!cookieIssue.cookie) {\n          return cookieIssue.rawCookieLine ?? \"no-cookie-info\";\n        }\n        const { domain, path: path7, name } = cookieIssue.cookie;\n        const cookieId = `${domain};${path7};${name}`;\n        return cookieId;\n      }\n      /**\n       * @param {LH.Artifacts} artifacts\n       * @return {Promise<LH.Audit.Product>}\n       */\n      static async audit(artifacts) {\n        const seenCookies = /* @__PURE__ */ new Set();\n        const items = [];\n        for (const issue of artifacts.InspectorIssues.cookieIssue ?? []) {\n          const isPhaseoutWarn = issue.cookieWarningReasons.includes(\"WarnThirdPartyPhaseout\");\n          const isPhaseoutExclude = issue.cookieExclusionReasons.includes(\"ExcludeThirdPartyPhaseout\");\n          if (!isPhaseoutWarn && !isPhaseoutExclude) continue;\n          const name = issue.cookie?.name || issue.rawCookieLine;\n          if (!name) continue;\n          const cookieId = this.getCookieId(issue);\n          if (seenCookies.has(cookieId)) continue;\n          seenCookies.add(cookieId);\n          items.push({\n            name,\n            url: issue.cookieUrl\n          });\n        }\n        const headings = [\n          { key: \"name\", valueType: \"text\", label: str_96(UIStrings.columnName) },\n          { key: \"url\", valueType: \"url\", label: str_96(UIStrings.columnURL) }\n        ];\n        const details = Audit.makeTableDetails(headings, items);\n        let displayValue;\n        if (items.length > 0) {\n          displayValue = str_96(UIStrings116.displayValue, { itemCount: items.length });\n        }\n        return {\n          score: items.length ? 0 : 1,\n          displayValue,\n          details\n        };\n      }\n    };\n    third_party_cookies_default = ThirdPartyCookies;\n  }\n});\n\n// core/audits/trusted-types-xss.js\nvar trusted_types_xss_exports = {};\n__export(trusted_types_xss_exports, {\n  UIStrings: () => UIStrings117,\n  default: () => trusted_types_xss_default\n});\nvar import_csp2, UIStrings117, str_97, TrustedTypesXss, trusted_types_xss_default;\nvar init_trusted_types_xss = __esm({\n  \"core/audits/trusted-types-xss.js\"() {\n    \"use strict\";\n    init_process_global();\n    import_csp2 = __toESM(require_csp(), 1);\n    init_audit();\n    init_main_resource();\n    init_i18n();\n    init_csp_evaluator();\n    /**\n     * @license\n     * Copyright 2025 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    UIStrings117 = {\n      /** Title of a Lighthouse audit that evaluates whether the set CSP header and Trusted Types directive is mitigating DOM-based XSS. \"CSP\" stands for \"Content-Security-Policy\" and should not be translated. \"XSS\" stands for \"Cross Site Scripting\" and should not be translated. */\n      title: \"Mitigate DOM-based XSS with Trusted Types\",\n      /** Description of a Lighthouse audit that evaluates whether the set CSP header and Trusted Types directive is mitigating DOM-based XSS. This is displayed after a user expands the section to see more. \"CSP\" stands for \"Content-Security-Policy\" and should not be translated. \"XSS\" stands for \"Cross Site Scripting\" and should not be translated. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */\n      description: \"The `require-trusted-types-for` directive in the `Content-Security-Policy` (CSP) header instructs user agents to control the data passed to DOM XSS sink functions. [Learn more about mitigating DOM-based XSS with Trusted Types](https://developer.chrome.com/docs/lighthouse/best-practices/trusted-types-xss).\",\n      /** Summary text for the results of a Lighthouse audit that evaluates whether the set CSP header and Trusted Types directive is mitigating DOM-based XSS. This text is displayed if the page does not respond with a CSP header and a Trusted Types directive. \"CSP\" stands for \"Content-Security-Policy\" and should not be translated. \"XSS\" stands for \"Cross Site Scripting\" and should not be translated. */\n      noTrustedTypesToMitigateXss: \"No `Content-Security-Policy` header with Trusted Types directive found\",\n      /** Label for a column in a data table; entries will be the severity of an issue with the page's CSP and Trusted Types directive. */\n      columnSeverity: \"Severity\"\n    };\n    str_97 = createIcuMessageFn({ url: \"core/audits/trusted-types-xss.js\" }.url, UIStrings117);\n    TrustedTypesXss = class extends Audit {\n      static {\n        __name(this, \"TrustedTypesXss\");\n      }\n      /**\n       * @return {LH.Audit.Meta}\n       */\n      static get meta() {\n        return {\n          id: \"trusted-types-xss\",\n          scoreDisplayMode: Audit.SCORING_MODES.INFORMATIVE,\n          title: str_97(UIStrings117.title),\n          description: str_97(UIStrings117.description),\n          requiredArtifacts: [\"DevtoolsLog\", \"MetaElements\", \"URL\"],\n          supportedModes: [\"navigation\"]\n        };\n      }\n      /**\n       * @param {LH.Artifacts} artifacts\n       * @param {LH.Audit.Context} context\n       * @return {Promise<{cspHeaders: string[], cspMetaTags: string[]}>}\n       */\n      static async getRawCsps(artifacts, context) {\n        const devtoolsLog = artifacts.DevtoolsLog;\n        const mainResource = await MainResourceComputed.request({ devtoolsLog, URL: artifacts.URL }, context);\n        const cspMetaTags = artifacts.MetaElements.filter((m) => {\n          return m.httpEquiv && m.httpEquiv.toLowerCase() === \"content-security-policy\";\n        }).flatMap((m) => (m.content || \"\").split(\",\")).filter((rawCsp) => rawCsp.replace(/\\s/g, \"\"));\n        const cspHeaders = mainResource.responseHeaders.filter((h) => {\n          return h.name.toLowerCase() === \"content-security-policy\";\n        }).flatMap((h) => h.value.split(\",\")).filter((rawCsp) => rawCsp.replace(/\\s/g, \"\"));\n        return { cspHeaders, cspMetaTags };\n      }\n      /**\n       * @param {LH.IcuMessage | string} findingDescription\n       * @param {LH.IcuMessage=} severity\n       * @return {LH.Audit.Details.TableItem}\n       */\n      static findingToTableItem(findingDescription, severity) {\n        return {\n          description: findingDescription,\n          severity\n        };\n      }\n      /**\n       * @param {string[]} cspHeaders\n       * @param {string[]} cspMetaTags\n       * @return {{score: number, results: LH.Audit.Details.TableItem[]}}\n       */\n      static constructResults(cspHeaders, cspMetaTags) {\n        const rawCsps = [...cspHeaders, ...cspMetaTags];\n        const parsedCsps = rawCsps.map(parseCsp);\n        for (const pc of parsedCsps) {\n          const directiveValues = pc.directives[pc.getEffectiveDirective(\n            import_csp2.Directive.REQUIRE_TRUSTED_TYPES_FOR\n          )] || [];\n          if (directiveValues.includes(\"'script'\")) {\n            return { score: 1, results: [] };\n          }\n        }\n        return {\n          score: 0,\n          results: [{\n            severity: str_97(UIStrings.itemSeverityHigh),\n            description: str_97(UIStrings117.noTrustedTypesToMitigateXss)\n          }]\n        };\n      }\n      /**\n       * @param {LH.Artifacts} artifacts\n       * @param {LH.Audit.Context} context\n       * @return {Promise<LH.Audit.Product>}\n       */\n      static async audit(artifacts, context) {\n        const { cspHeaders, cspMetaTags } = await this.getRawCsps(artifacts, context);\n        const { score, results } = this.constructResults(cspHeaders, cspMetaTags);\n        const headings = [\n          /* eslint-disable max-len */\n          { key: \"description\", valueType: \"text\", subItemsHeading: { key: \"description\" }, label: str_97(UIStrings.columnDescription) },\n          { key: \"severity\", valueType: \"text\", subItemsHeading: { key: \"severity\" }, label: str_97(UIStrings117.columnSeverity) }\n          /* eslint-enable max-len */\n        ];\n        const details = Audit.makeTableDetails(headings, results);\n        return {\n          score,\n          notApplicable: !results.length,\n          details\n        };\n      }\n    };\n    trusted_types_xss_default = TrustedTypesXss;\n  }\n});\n\n// replace-modules:/Users/alexrudenko/src/lighthouse/core/computed/entity-classification.js\nvar entity_classification_exports = {};\n__export(entity_classification_exports, {\n  EntityClassification: () => EntityClassification,\n  EntityClassificationComputed: () => EntityClassificationComputed\n});\nvar EntityClassification, EntityClassificationComputed;\nvar init_entity_classification = __esm({\n  \"replace-modules:/Users/alexrudenko/src/lighthouse/core/computed/entity-classification.js\"() {\n    init_process_global();\n    init_computed_artifact();\n    EntityClassification = class {\n      static {\n        __name(this, \"EntityClassification\");\n      }\n      static async compute_() {\n        return {\n          entityByUrl: /* @__PURE__ */ new Map(),\n          urlsByEntity: /* @__PURE__ */ new Map(),\n          isFirstParty: /* @__PURE__ */ __name(() => false, \"isFirstParty\")\n        };\n      }\n    };\n    EntityClassificationComputed = makeComputedArtifact(EntityClassification, null);\n  }\n});\n\n// core/audits/valid-source-maps.js\nvar valid_source_maps_exports = {};\n__export(valid_source_maps_exports, {\n  UIStrings: () => UIStrings118,\n  default: () => valid_source_maps_default\n});\nvar UIStrings118, str_98, LARGE_JS_BYTE_THRESHOLD, ValidSourceMaps, valid_source_maps_default;\nvar init_valid_source_maps = __esm({\n  \"core/audits/valid-source-maps.js\"() {\n    \"use strict\";\n    init_process_global();\n    init_audit();\n    init_entity_classification();\n    init_i18n();\n    init_util();\n    init_url_utils();\n    /**\n     * @license Copyright 2020 Google LLC\n     * SPDX-License-Identifier: Apache-2.0\n     */\n    UIStrings118 = {\n      /** Title of a Lighthouse audit that provides detail on HTTP to HTTPS redirects. This descriptive title is shown to users when HTTP traffic is redirected to HTTPS. */\n      title: \"Page has valid source maps\",\n      /** Title of a Lighthouse audit that provides detail on HTTP to HTTPS redirects. This descriptive title is shown to users when HTTP traffic is not redirected to HTTPS. */\n      failureTitle: \"Missing source maps for large first-party JavaScript\",\n      /** Description of a Lighthouse audit that tells the user that their JavaScript source maps are invalid or missing. This is displayed after a user expands the section to see more. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */\n      description: \"Source maps translate minified code to the original source code. This helps developers debug in production. In addition, Lighthouse is able to provide further insights. Consider deploying source maps to take advantage of these benefits. [Learn more about source maps](https://developer.chrome.com/docs/devtools/javascript/source-maps/).\",\n      /** Label for a column in a data table. Entries will be URLs to JavaScript source maps. */\n      columnMapURL: \"Map URL\",\n      /** Label for a possible error message indicating that a source map for a large, first-party JavaScript script is missing. */\n      missingSourceMapErrorMessage: \"Large JavaScript file is missing a source map\",\n      /** Label for a possible error message indicating that the content of a source map is invalid because it is missing items in the sourcesContent attribute. */\n      missingSourceMapItemsWarningMesssage: `{missingItems, plural,\n    =1 {Warning: missing 1 item in \\`.sourcesContent\\`}\n    other {Warning: missing # items in \\`.sourcesContent\\`}\n    }`\n    };\n    str_98 = createIcuMessageFn({ url: \"core/audits/valid-source-maps.js\" }.url, UIStrings118);\n    LARGE_JS_BYTE_THRESHOLD = 500 * 1024;\n    ValidSourceMaps = class extends Audit {\n      static {\n        __name(this, \"ValidSourceMaps\");\n      }\n      /**\n       * @return {LH.Audit.Meta}\n       */\n      static get meta() {\n        return {\n          id: \"valid-source-maps\",\n          title: str_98(UIStrings118.title),\n          failureTitle: str_98(UIStrings118.failureTitle),\n          description: str_98(UIStrings118.description),\n          requiredArtifacts: [\"Scripts\", \"SourceMaps\", \"URL\", \"DevtoolsLog\"]\n        };\n      }\n      /**\n       * Returns true if the size of the script exceeds a static threshold.\n       * @param {LH.Artifacts.Script} script\n       * @param {LH.Artifacts.EntityClassification} classifiedEntities\n       * @return {boolean}\n       */\n      static isLargeFirstPartyJS(script, classifiedEntities) {\n        const url = script.url;\n        if (!script.length || !url) return false;\n        if (!url_utils_default.isValid(url)) return false;\n        if (!Util.createOrReturnURL(url).protocol.startsWith(\"http\")) return false;\n        const isLargeJS = script.length >= LARGE_JS_BYTE_THRESHOLD;\n        return classifiedEntities.isFirstParty(url) && isLargeJS;\n      }\n      /**\n       * @param {LH.Artifacts} artifacts\n       * @param {LH.Audit.Context} context\n       */\n      static async audit(artifacts, context) {\n        const { SourceMaps: SourceMaps2 } = artifacts;\n        const devtoolsLog = artifacts.DevtoolsLog;\n        const classifiedEntities = await EntityClassification.request(\n          { URL: artifacts.URL, devtoolsLog },\n          context\n        );\n        const isMissingMapForLargeFirstPartyScriptUrl = /* @__PURE__ */ new Set();\n        let missingMapsForLargeFirstPartyFile = false;\n        const results = [];\n        for (const script of artifacts.Scripts) {\n          const sourceMap = SourceMaps2.find((m) => m.scriptId === script.scriptId);\n          const errors = [];\n          const isLargeFirstParty = this.isLargeFirstPartyJS(script, classifiedEntities);\n          if (isLargeFirstParty && (!sourceMap || !sourceMap.map)) {\n            missingMapsForLargeFirstPartyFile = true;\n            isMissingMapForLargeFirstPartyScriptUrl.add(script.url);\n            errors.push({ error: str_98(UIStrings118.missingSourceMapErrorMessage) });\n          }\n          if (sourceMap && !sourceMap.map) {\n            errors.push({ error: sourceMap.errorMessage });\n          }\n          if (sourceMap?.map) {\n            const sourcesContent = sourceMap.map.sourcesContent || [];\n            let missingSourcesContentCount = 0;\n            for (let i = 0; i < sourceMap.map.sources.length; i++) {\n              if (sourcesContent.length < i || !sourcesContent[i]) missingSourcesContentCount += 1;\n            }\n            if (missingSourcesContentCount > 0) {\n              errors.push({ error: str_98(\n                UIStrings118.missingSourceMapItemsWarningMesssage,\n                { missingItems: missingSourcesContentCount }\n              ) });\n            }\n          }\n          if (sourceMap || errors.length) {\n            results.push({\n              scriptUrl: script.url,\n              sourceMapUrl: sourceMap?.sourceMapUrl,\n              subItems: {\n                type: (\n                  /** @type {const} */\n                  \"subitems\"\n                ),\n                items: errors\n              }\n            });\n          }\n        }\n        const headings = [\n          {\n            key: \"scriptUrl\",\n            valueType: \"url\",\n            subItemsHeading: { key: \"error\" },\n            label: str_98(UIStrings.columnURL)\n          },\n          { key: \"sourceMapUrl\", valueType: \"url\", label: str_98(UIStrings118.columnMapURL) }\n        ];\n        results.sort((a, b) => {\n          const missingMapA = isMissingMapForLargeFirstPartyScriptUrl.has(a.scriptUrl);\n          const missingMapB = isMissingMapForLargeFirstPartyScriptUrl.has(b.scriptUrl);\n          if (missingMapA && !missingMapB) return -1;\n          if (!missingMapA && missingMapB) return 1;\n          if (a.subItems.items.length && !b.subItems.items.length) return -1;\n          if (!a.subItems.items.length && b.subItems.items.length) return 1;\n          return b.scriptUrl.localeCompare(a.scriptUrl);\n        });\n        return {\n          score: missingMapsForLargeFirstPartyFile ? 0 : 1,\n          details: Audit.makeTableDetails(headings, results)\n        };\n      }\n    };\n    valid_source_maps_default = ValidSourceMaps;\n  }\n});\n\n// replace-modules:/Users/alexrudenko/src/lighthouse/core/computed/speedline.js\nvar speedline_exports = {};\n__export(speedline_exports, {\n  Speedline: () => Speedline,\n  SpeedlineComputed: () => SpeedlineComputed\n});\nvar Speedline, SpeedlineComputed;\nvar init_speedline = __esm({\n  \"replace-modules:/Users/alexrudenko/src/lighthouse/core/computed/speedline.js\"() {\n    init_process_global();\n    init_computed_artifact();\n    init_lh_error();\n    Speedline = class {\n      static {\n        __name(this, \"Speedline\");\n      }\n      static async compute_() {\n        throw new LighthouseError(LighthouseError.errors.NO_SPEEDLINE_FRAMES);\n      }\n    };\n    SpeedlineComputed = makeComputedArtifact(Speedline, null);\n  }\n});\n\n// replace-modules:/Users/alexrudenko/src/lighthouse/core/computed/metrics/timing-summary.js\nvar timing_summary_exports = {};\n__export(timing_summary_exports, {\n  TimingSummary: () => TimingSummary,\n  TimingSummaryComputed: () => TimingSummaryComputed\n});\nvar TimingSummary, TimingSummaryComputed;\nvar init_timing_summary = __esm({\n  \"replace-modules:/Users/alexrudenko/src/lighthouse/core/computed/metrics/timing-summary.js\"() {\n    init_process_global();\n    init_computed_artifact();\n    TimingSummary = class {\n      static {\n        __name(this, \"TimingSummary\");\n      }\n      static async compute_() {\n        return { metrics: {}, debugInfo: {} };\n      }\n    };\n    TimingSummaryComputed = makeComputedArtifact(TimingSummary, null);\n  }\n});\n\n// replace-modules:/Users/alexrudenko/src/lighthouse/core/computed/trace-engine-result.js\nvar trace_engine_result_exports = {};\n__export(trace_engine_result_exports, {\n  TraceEngineResult: () => TraceEngineResult,\n  TraceEngineResultComputed: () => TraceEngineResultComputed\n});\nvar TraceEngineResult, TraceEngineResultComputed;\nvar init_trace_engine_result = __esm({\n  \"replace-modules:/Users/alexrudenko/src/lighthouse/core/computed/trace-engine-result.js\"() {\n    init_process_global();\n    init_computed_artifact();\n    TraceEngineResult = class {\n      static {\n        __name(this, \"TraceEngineResult\");\n      }\n      static async compute_() {\n        return { data: {}, insights: /* @__PURE__ */ new Map() };\n      }\n      static localizeFunction(str, fn) {\n        return fn;\n      }\n    };\n    TraceEngineResultComputed = makeComputedArtifact(TraceEngineResult, null);\n  }\n});\n\n// lh-gatherer-shim:/Users/alexrudenko/src/lighthouse/core/gather/gatherers/bf-cache-failures.js\nvar bf_cache_failures_exports = {};\n__export(bf_cache_failures_exports, {\n  default: () => bf_cache_failures_default\n});\nvar ShimGatherer2, bf_cache_failures_default;\nvar init_bf_cache_failures = __esm({\n  \"lh-gatherer-shim:/Users/alexrudenko/src/lighthouse/core/gather/gatherers/bf-cache-failures.js\"() {\n    init_process_global();\n    init_base_gatherer();\n    ShimGatherer2 = class extends base_gatherer_default {\n      static {\n        __name(this, \"ShimGatherer\");\n      }\n      meta = { supportedModes: [\"navigation\", \"timespan\", \"snapshot\"] };\n      static getDefaultTraceCategories() {\n        return [];\n      }\n      getArtifact() {\n        return void 0;\n      }\n    };\n    bf_cache_failures_default = ShimGatherer2;\n  }\n});\n\n// lh-gatherer-shim:/Users/alexrudenko/src/lighthouse/core/gather/gatherers/css-usage.js\nvar css_usage_exports = {};\n__export(css_usage_exports, {\n  default: () => css_usage_default\n});\nvar ShimGatherer3, css_usage_default;\nvar init_css_usage = __esm({\n  \"lh-gatherer-shim:/Users/alexrudenko/src/lighthouse/core/gather/gatherers/css-usage.js\"() {\n    init_process_global();\n    init_base_gatherer();\n    ShimGatherer3 = class extends base_gatherer_default {\n      static {\n        __name(this, \"ShimGatherer\");\n      }\n      meta = { supportedModes: [\"navigation\", \"timespan\", \"snapshot\"] };\n      static getDefaultTraceCategories() {\n        return [];\n      }\n      getArtifact() {\n        return void 0;\n      }\n    };\n    css_usage_default = ShimGatherer3;\n  }\n});\n\n// lh-gatherer-shim:/Users/alexrudenko/src/lighthouse/core/gather/gatherers/full-page-screenshot.js\nvar full_page_screenshot_exports = {};\n__export(full_page_screenshot_exports, {\n  default: () => full_page_screenshot_default\n});\nvar ShimGatherer4, full_page_screenshot_default;\nvar init_full_page_screenshot = __esm({\n  \"lh-gatherer-shim:/Users/alexrudenko/src/lighthouse/core/gather/gatherers/full-page-screenshot.js\"() {\n    init_process_global();\n    init_base_gatherer();\n    ShimGatherer4 = class extends base_gatherer_default {\n      static {\n        __name(this, \"ShimGatherer\");\n      }\n      meta = { supportedModes: [\"navigation\", \"timespan\", \"snapshot\"] };\n      static getDefaultTraceCategories() {\n        return [];\n      }\n      getArtifact() {\n        return void 0;\n      }\n    };\n    full_page_screenshot_default = ShimGatherer4;\n  }\n});\n\n// lh-gatherer-shim:/Users/alexrudenko/src/lighthouse/core/gather/gatherers/iframe-elements.js\nvar iframe_elements_exports = {};\n__export(iframe_elements_exports, {\n  default: () => iframe_elements_default\n});\nvar ShimGatherer5, iframe_elements_default;\nvar init_iframe_elements = __esm({\n  \"lh-gatherer-shim:/Users/alexrudenko/src/lighthouse/core/gather/gatherers/iframe-elements.js\"() {\n    init_process_global();\n    init_base_gatherer();\n    ShimGatherer5 = class extends base_gatherer_default {\n      static {\n        __name(this, \"ShimGatherer\");\n      }\n      meta = { supportedModes: [\"navigation\", \"timespan\", \"snapshot\"] };\n      static getDefaultTraceCategories() {\n        return [];\n      }\n      getArtifact() {\n        return void 0;\n      }\n    };\n    iframe_elements_default = ShimGatherer5;\n  }\n});\n\n// lh-gatherer-shim:/Users/alexrudenko/src/lighthouse/core/gather/gatherers/js-usage.js\nvar js_usage_exports = {};\n__export(js_usage_exports, {\n  default: () => js_usage_default\n});\nvar ShimGatherer6, js_usage_default;\nvar init_js_usage = __esm({\n  \"lh-gatherer-shim:/Users/alexrudenko/src/lighthouse/core/gather/gatherers/js-usage.js\"() {\n    init_process_global();\n    init_base_gatherer();\n    ShimGatherer6 = class extends base_gatherer_default {\n      static {\n        __name(this, \"ShimGatherer\");\n      }\n      meta = { supportedModes: [\"navigation\", \"timespan\", \"snapshot\"] };\n      static getDefaultTraceCategories() {\n        return [];\n      }\n      getArtifact() {\n        return void 0;\n      }\n    };\n    js_usage_default = ShimGatherer6;\n  }\n});\n\n// lh-gatherer-shim:/Users/alexrudenko/src/lighthouse/core/gather/gatherers/network-user-agent.js\nvar network_user_agent_exports = {};\n__export(network_user_agent_exports, {\n  default: () => network_user_agent_default\n});\nvar ShimGatherer7, network_user_agent_default;\nvar init_network_user_agent = __esm({\n  \"lh-gatherer-shim:/Users/alexrudenko/src/lighthouse/core/gather/gatherers/network-user-agent.js\"() {\n    init_process_global();\n    init_base_gatherer();\n    ShimGatherer7 = class extends base_gatherer_default {\n      static {\n        __name(this, \"ShimGatherer\");\n      }\n      meta = { supportedModes: [\"navigation\", \"timespan\", \"snapshot\"] };\n      static getDefaultTraceCategories() {\n        return [];\n      }\n      getArtifact() {\n        return void 0;\n      }\n    };\n    network_user_agent_default = ShimGatherer7;\n  }\n});\n\n// lh-gatherer-shim:/Users/alexrudenko/src/lighthouse/core/gather/gatherers/stylesheets.js\nvar stylesheets_exports = {};\n__export(stylesheets_exports, {\n  default: () => stylesheets_default\n});\nvar ShimGatherer8, stylesheets_default;\nvar init_stylesheets = __esm({\n  \"lh-gatherer-shim:/Users/alexrudenko/src/lighthouse/core/gather/gatherers/stylesheets.js\"() {\n    init_process_global();\n    init_base_gatherer();\n    ShimGatherer8 = class extends base_gatherer_default {\n      static {\n        __name(this, \"ShimGatherer\");\n      }\n      meta = { supportedModes: [\"navigation\", \"timespan\", \"snapshot\"] };\n      static getDefaultTraceCategories() {\n        return [];\n      }\n      getArtifact() {\n        return void 0;\n      }\n    };\n    stylesheets_default = ShimGatherer8;\n  }\n});\n\n// lh-gatherer-shim:/Users/alexrudenko/src/lighthouse/core/gather/gatherers/trace-elements.js\nvar trace_elements_exports = {};\n__export(trace_elements_exports, {\n  default: () => trace_elements_default\n});\nvar ShimGatherer9, trace_elements_default;\nvar init_trace_elements = __esm({\n  \"lh-gatherer-shim:/Users/alexrudenko/src/lighthouse/core/gather/gatherers/trace-elements.js\"() {\n    init_process_global();\n    init_base_gatherer();\n    ShimGatherer9 = class extends base_gatherer_default {\n      static {\n        __name(this, \"ShimGatherer\");\n      }\n      meta = { supportedModes: [\"navigation\", \"timespan\", \"snapshot\"] };\n      static getDefaultTraceCategories() {\n        return [];\n      }\n      getArtifact() {\n        return void 0;\n      }\n    };\n    trace_elements_default = ShimGatherer9;\n  }\n});\n\n// lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/autocomplete.js\nvar autocomplete_exports = {};\n__export(autocomplete_exports, {\n  default: () => autocomplete_default\n});\nvar ShimAudit, autocomplete_default;\nvar init_autocomplete = __esm({\n  \"lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/autocomplete.js\"() {\n    init_process_global();\n    init_audit();\n    ShimAudit = class extends Audit {\n      static {\n        __name(this, \"ShimAudit\");\n      }\n      static get meta() {\n        return {\n          id: \"autocomplete\",\n          title: \"Shim Audit\",\n          description: \"This audit was filtered out and is not available in this bundle.\",\n          scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE,\n          requiredArtifacts: []\n        };\n      }\n      static audit() {\n        return { score: null, scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE };\n      }\n    };\n    autocomplete_default = ShimAudit;\n  }\n});\n\n// lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/bf-cache.js\nvar bf_cache_exports = {};\n__export(bf_cache_exports, {\n  default: () => bf_cache_default\n});\nvar ShimAudit2, bf_cache_default;\nvar init_bf_cache = __esm({\n  \"lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/bf-cache.js\"() {\n    init_process_global();\n    init_audit();\n    ShimAudit2 = class extends Audit {\n      static {\n        __name(this, \"ShimAudit\");\n      }\n      static get meta() {\n        return {\n          id: \"bf-cache\",\n          title: \"Shim Audit\",\n          description: \"This audit was filtered out and is not available in this bundle.\",\n          scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE,\n          requiredArtifacts: []\n        };\n      }\n      static audit() {\n        return { score: null, scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE };\n      }\n    };\n    bf_cache_default = ShimAudit2;\n  }\n});\n\n// lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/bootup-time.js\nvar bootup_time_exports = {};\n__export(bootup_time_exports, {\n  default: () => bootup_time_default\n});\nvar ShimAudit3, bootup_time_default;\nvar init_bootup_time = __esm({\n  \"lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/bootup-time.js\"() {\n    init_process_global();\n    init_audit();\n    ShimAudit3 = class extends Audit {\n      static {\n        __name(this, \"ShimAudit\");\n      }\n      static get meta() {\n        return {\n          id: \"bootup-time\",\n          title: \"Shim Audit\",\n          description: \"This audit was filtered out and is not available in this bundle.\",\n          scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE,\n          requiredArtifacts: []\n        };\n      }\n      static audit() {\n        return { score: null, scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE };\n      }\n    };\n    bootup_time_default = ShimAudit3;\n  }\n});\n\n// lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/byte-efficiency/total-byte-weight.js\nvar total_byte_weight_exports = {};\n__export(total_byte_weight_exports, {\n  default: () => total_byte_weight_default\n});\nvar ShimAudit4, total_byte_weight_default;\nvar init_total_byte_weight = __esm({\n  \"lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/byte-efficiency/total-byte-weight.js\"() {\n    init_process_global();\n    init_audit();\n    ShimAudit4 = class extends Audit {\n      static {\n        __name(this, \"ShimAudit\");\n      }\n      static get meta() {\n        return {\n          id: \"total-byte-weight\",\n          title: \"Shim Audit\",\n          description: \"This audit was filtered out and is not available in this bundle.\",\n          scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE,\n          requiredArtifacts: []\n        };\n      }\n      static audit() {\n        return { score: null, scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE };\n      }\n    };\n    total_byte_weight_default = ShimAudit4;\n  }\n});\n\n// lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/byte-efficiency/unminified-css.js\nvar unminified_css_exports = {};\n__export(unminified_css_exports, {\n  default: () => unminified_css_default\n});\nvar ShimAudit5, unminified_css_default;\nvar init_unminified_css = __esm({\n  \"lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/byte-efficiency/unminified-css.js\"() {\n    init_process_global();\n    init_audit();\n    ShimAudit5 = class extends Audit {\n      static {\n        __name(this, \"ShimAudit\");\n      }\n      static get meta() {\n        return {\n          id: \"unminified-css\",\n          title: \"Shim Audit\",\n          description: \"This audit was filtered out and is not available in this bundle.\",\n          scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE,\n          requiredArtifacts: []\n        };\n      }\n      static audit() {\n        return { score: null, scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE };\n      }\n    };\n    unminified_css_default = ShimAudit5;\n  }\n});\n\n// lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/byte-efficiency/unminified-javascript.js\nvar unminified_javascript_exports = {};\n__export(unminified_javascript_exports, {\n  default: () => unminified_javascript_default\n});\nvar ShimAudit6, unminified_javascript_default;\nvar init_unminified_javascript = __esm({\n  \"lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/byte-efficiency/unminified-javascript.js\"() {\n    init_process_global();\n    init_audit();\n    ShimAudit6 = class extends Audit {\n      static {\n        __name(this, \"ShimAudit\");\n      }\n      static get meta() {\n        return {\n          id: \"unminified-javascript\",\n          title: \"Shim Audit\",\n          description: \"This audit was filtered out and is not available in this bundle.\",\n          scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE,\n          requiredArtifacts: []\n        };\n      }\n      static audit() {\n        return { score: null, scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE };\n      }\n    };\n    unminified_javascript_default = ShimAudit6;\n  }\n});\n\n// lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/byte-efficiency/unused-css-rules.js\nvar unused_css_rules_exports = {};\n__export(unused_css_rules_exports, {\n  default: () => unused_css_rules_default\n});\nvar ShimAudit7, unused_css_rules_default;\nvar init_unused_css_rules = __esm({\n  \"lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/byte-efficiency/unused-css-rules.js\"() {\n    init_process_global();\n    init_audit();\n    ShimAudit7 = class extends Audit {\n      static {\n        __name(this, \"ShimAudit\");\n      }\n      static get meta() {\n        return {\n          id: \"unused-css-rules\",\n          title: \"Shim Audit\",\n          description: \"This audit was filtered out and is not available in this bundle.\",\n          scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE,\n          requiredArtifacts: []\n        };\n      }\n      static audit() {\n        return { score: null, scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE };\n      }\n    };\n    unused_css_rules_default = ShimAudit7;\n  }\n});\n\n// lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/byte-efficiency/unused-javascript.js\nvar unused_javascript_exports = {};\n__export(unused_javascript_exports, {\n  default: () => unused_javascript_default\n});\nvar ShimAudit8, unused_javascript_default;\nvar init_unused_javascript = __esm({\n  \"lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/byte-efficiency/unused-javascript.js\"() {\n    init_process_global();\n    init_audit();\n    ShimAudit8 = class extends Audit {\n      static {\n        __name(this, \"ShimAudit\");\n      }\n      static get meta() {\n        return {\n          id: \"unused-javascript\",\n          title: \"Shim Audit\",\n          description: \"This audit was filtered out and is not available in this bundle.\",\n          scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE,\n          requiredArtifacts: []\n        };\n      }\n      static audit() {\n        return { score: null, scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE };\n      }\n    };\n    unused_javascript_default = ShimAudit8;\n  }\n});\n\n// lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/diagnostics.js\nvar diagnostics_exports = {};\n__export(diagnostics_exports, {\n  default: () => diagnostics_default\n});\nvar ShimAudit9, diagnostics_default;\nvar init_diagnostics = __esm({\n  \"lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/diagnostics.js\"() {\n    init_process_global();\n    init_audit();\n    ShimAudit9 = class extends Audit {\n      static {\n        __name(this, \"ShimAudit\");\n      }\n      static get meta() {\n        return {\n          id: \"diagnostics\",\n          title: \"Shim Audit\",\n          description: \"This audit was filtered out and is not available in this bundle.\",\n          scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE,\n          requiredArtifacts: []\n        };\n      }\n      static audit() {\n        return { score: null, scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE };\n      }\n    };\n    diagnostics_default = ShimAudit9;\n  }\n});\n\n// lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/final-screenshot.js\nvar final_screenshot_exports = {};\n__export(final_screenshot_exports, {\n  default: () => final_screenshot_default\n});\nvar ShimAudit10, final_screenshot_default;\nvar init_final_screenshot = __esm({\n  \"lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/final-screenshot.js\"() {\n    init_process_global();\n    init_audit();\n    ShimAudit10 = class extends Audit {\n      static {\n        __name(this, \"ShimAudit\");\n      }\n      static get meta() {\n        return {\n          id: \"final-screenshot\",\n          title: \"Shim Audit\",\n          description: \"This audit was filtered out and is not available in this bundle.\",\n          scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE,\n          requiredArtifacts: []\n        };\n      }\n      static audit() {\n        return { score: null, scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE };\n      }\n    };\n    final_screenshot_default = ShimAudit10;\n  }\n});\n\n// lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/insights/cache-insight.js\nvar cache_insight_exports = {};\n__export(cache_insight_exports, {\n  default: () => cache_insight_default\n});\nvar ShimAudit11, cache_insight_default;\nvar init_cache_insight = __esm({\n  \"lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/insights/cache-insight.js\"() {\n    init_process_global();\n    init_audit();\n    ShimAudit11 = class extends Audit {\n      static {\n        __name(this, \"ShimAudit\");\n      }\n      static get meta() {\n        return {\n          id: \"cache-insight\",\n          title: \"Shim Audit\",\n          description: \"This audit was filtered out and is not available in this bundle.\",\n          scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE,\n          requiredArtifacts: []\n        };\n      }\n      static audit() {\n        return { score: null, scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE };\n      }\n    };\n    cache_insight_default = ShimAudit11;\n  }\n});\n\n// lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/insights/cls-culprits-insight.js\nvar cls_culprits_insight_exports = {};\n__export(cls_culprits_insight_exports, {\n  default: () => cls_culprits_insight_default\n});\nvar ShimAudit12, cls_culprits_insight_default;\nvar init_cls_culprits_insight = __esm({\n  \"lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/insights/cls-culprits-insight.js\"() {\n    init_process_global();\n    init_audit();\n    ShimAudit12 = class extends Audit {\n      static {\n        __name(this, \"ShimAudit\");\n      }\n      static get meta() {\n        return {\n          id: \"cls-culprits-insight\",\n          title: \"Shim Audit\",\n          description: \"This audit was filtered out and is not available in this bundle.\",\n          scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE,\n          requiredArtifacts: []\n        };\n      }\n      static audit() {\n        return { score: null, scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE };\n      }\n    };\n    cls_culprits_insight_default = ShimAudit12;\n  }\n});\n\n// lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/insights/document-latency-insight.js\nvar document_latency_insight_exports = {};\n__export(document_latency_insight_exports, {\n  default: () => document_latency_insight_default\n});\nvar ShimAudit13, document_latency_insight_default;\nvar init_document_latency_insight = __esm({\n  \"lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/insights/document-latency-insight.js\"() {\n    init_process_global();\n    init_audit();\n    ShimAudit13 = class extends Audit {\n      static {\n        __name(this, \"ShimAudit\");\n      }\n      static get meta() {\n        return {\n          id: \"document-latency-insight\",\n          title: \"Shim Audit\",\n          description: \"This audit was filtered out and is not available in this bundle.\",\n          scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE,\n          requiredArtifacts: []\n        };\n      }\n      static audit() {\n        return { score: null, scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE };\n      }\n    };\n    document_latency_insight_default = ShimAudit13;\n  }\n});\n\n// lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/insights/dom-size-insight.js\nvar dom_size_insight_exports = {};\n__export(dom_size_insight_exports, {\n  default: () => dom_size_insight_default\n});\nvar ShimAudit14, dom_size_insight_default;\nvar init_dom_size_insight = __esm({\n  \"lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/insights/dom-size-insight.js\"() {\n    init_process_global();\n    init_audit();\n    ShimAudit14 = class extends Audit {\n      static {\n        __name(this, \"ShimAudit\");\n      }\n      static get meta() {\n        return {\n          id: \"dom-size-insight\",\n          title: \"Shim Audit\",\n          description: \"This audit was filtered out and is not available in this bundle.\",\n          scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE,\n          requiredArtifacts: []\n        };\n      }\n      static audit() {\n        return { score: null, scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE };\n      }\n    };\n    dom_size_insight_default = ShimAudit14;\n  }\n});\n\n// lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/insights/duplicated-javascript-insight.js\nvar duplicated_javascript_insight_exports = {};\n__export(duplicated_javascript_insight_exports, {\n  default: () => duplicated_javascript_insight_default\n});\nvar ShimAudit15, duplicated_javascript_insight_default;\nvar init_duplicated_javascript_insight = __esm({\n  \"lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/insights/duplicated-javascript-insight.js\"() {\n    init_process_global();\n    init_audit();\n    ShimAudit15 = class extends Audit {\n      static {\n        __name(this, \"ShimAudit\");\n      }\n      static get meta() {\n        return {\n          id: \"duplicated-javascript-insight\",\n          title: \"Shim Audit\",\n          description: \"This audit was filtered out and is not available in this bundle.\",\n          scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE,\n          requiredArtifacts: []\n        };\n      }\n      static audit() {\n        return { score: null, scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE };\n      }\n    };\n    duplicated_javascript_insight_default = ShimAudit15;\n  }\n});\n\n// lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/insights/font-display-insight.js\nvar font_display_insight_exports = {};\n__export(font_display_insight_exports, {\n  default: () => font_display_insight_default\n});\nvar ShimAudit16, font_display_insight_default;\nvar init_font_display_insight = __esm({\n  \"lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/insights/font-display-insight.js\"() {\n    init_process_global();\n    init_audit();\n    ShimAudit16 = class extends Audit {\n      static {\n        __name(this, \"ShimAudit\");\n      }\n      static get meta() {\n        return {\n          id: \"font-display-insight\",\n          title: \"Shim Audit\",\n          description: \"This audit was filtered out and is not available in this bundle.\",\n          scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE,\n          requiredArtifacts: []\n        };\n      }\n      static audit() {\n        return { score: null, scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE };\n      }\n    };\n    font_display_insight_default = ShimAudit16;\n  }\n});\n\n// lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/insights/forced-reflow-insight.js\nvar forced_reflow_insight_exports = {};\n__export(forced_reflow_insight_exports, {\n  default: () => forced_reflow_insight_default\n});\nvar ShimAudit17, forced_reflow_insight_default;\nvar init_forced_reflow_insight = __esm({\n  \"lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/insights/forced-reflow-insight.js\"() {\n    init_process_global();\n    init_audit();\n    ShimAudit17 = class extends Audit {\n      static {\n        __name(this, \"ShimAudit\");\n      }\n      static get meta() {\n        return {\n          id: \"forced-reflow-insight\",\n          title: \"Shim Audit\",\n          description: \"This audit was filtered out and is not available in this bundle.\",\n          scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE,\n          requiredArtifacts: []\n        };\n      }\n      static audit() {\n        return { score: null, scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE };\n      }\n    };\n    forced_reflow_insight_default = ShimAudit17;\n  }\n});\n\n// lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/insights/image-delivery-insight.js\nvar image_delivery_insight_exports = {};\n__export(image_delivery_insight_exports, {\n  default: () => image_delivery_insight_default\n});\nvar ShimAudit18, image_delivery_insight_default;\nvar init_image_delivery_insight = __esm({\n  \"lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/insights/image-delivery-insight.js\"() {\n    init_process_global();\n    init_audit();\n    ShimAudit18 = class extends Audit {\n      static {\n        __name(this, \"ShimAudit\");\n      }\n      static get meta() {\n        return {\n          id: \"image-delivery-insight\",\n          title: \"Shim Audit\",\n          description: \"This audit was filtered out and is not available in this bundle.\",\n          scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE,\n          requiredArtifacts: []\n        };\n      }\n      static audit() {\n        return { score: null, scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE };\n      }\n    };\n    image_delivery_insight_default = ShimAudit18;\n  }\n});\n\n// lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/insights/inp-breakdown-insight.js\nvar inp_breakdown_insight_exports = {};\n__export(inp_breakdown_insight_exports, {\n  default: () => inp_breakdown_insight_default\n});\nvar ShimAudit19, inp_breakdown_insight_default;\nvar init_inp_breakdown_insight = __esm({\n  \"lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/insights/inp-breakdown-insight.js\"() {\n    init_process_global();\n    init_audit();\n    ShimAudit19 = class extends Audit {\n      static {\n        __name(this, \"ShimAudit\");\n      }\n      static get meta() {\n        return {\n          id: \"inp-breakdown-insight\",\n          title: \"Shim Audit\",\n          description: \"This audit was filtered out and is not available in this bundle.\",\n          scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE,\n          requiredArtifacts: []\n        };\n      }\n      static audit() {\n        return { score: null, scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE };\n      }\n    };\n    inp_breakdown_insight_default = ShimAudit19;\n  }\n});\n\n// lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/insights/lcp-breakdown-insight.js\nvar lcp_breakdown_insight_exports = {};\n__export(lcp_breakdown_insight_exports, {\n  default: () => lcp_breakdown_insight_default\n});\nvar ShimAudit20, lcp_breakdown_insight_default;\nvar init_lcp_breakdown_insight = __esm({\n  \"lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/insights/lcp-breakdown-insight.js\"() {\n    init_process_global();\n    init_audit();\n    ShimAudit20 = class extends Audit {\n      static {\n        __name(this, \"ShimAudit\");\n      }\n      static get meta() {\n        return {\n          id: \"lcp-breakdown-insight\",\n          title: \"Shim Audit\",\n          description: \"This audit was filtered out and is not available in this bundle.\",\n          scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE,\n          requiredArtifacts: []\n        };\n      }\n      static audit() {\n        return { score: null, scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE };\n      }\n    };\n    lcp_breakdown_insight_default = ShimAudit20;\n  }\n});\n\n// lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/insights/lcp-discovery-insight.js\nvar lcp_discovery_insight_exports = {};\n__export(lcp_discovery_insight_exports, {\n  default: () => lcp_discovery_insight_default\n});\nvar ShimAudit21, lcp_discovery_insight_default;\nvar init_lcp_discovery_insight = __esm({\n  \"lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/insights/lcp-discovery-insight.js\"() {\n    init_process_global();\n    init_audit();\n    ShimAudit21 = class extends Audit {\n      static {\n        __name(this, \"ShimAudit\");\n      }\n      static get meta() {\n        return {\n          id: \"lcp-discovery-insight\",\n          title: \"Shim Audit\",\n          description: \"This audit was filtered out and is not available in this bundle.\",\n          scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE,\n          requiredArtifacts: []\n        };\n      }\n      static audit() {\n        return { score: null, scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE };\n      }\n    };\n    lcp_discovery_insight_default = ShimAudit21;\n  }\n});\n\n// lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/insights/legacy-javascript-insight.js\nvar legacy_javascript_insight_exports = {};\n__export(legacy_javascript_insight_exports, {\n  default: () => legacy_javascript_insight_default\n});\nvar ShimAudit22, legacy_javascript_insight_default;\nvar init_legacy_javascript_insight = __esm({\n  \"lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/insights/legacy-javascript-insight.js\"() {\n    init_process_global();\n    init_audit();\n    ShimAudit22 = class extends Audit {\n      static {\n        __name(this, \"ShimAudit\");\n      }\n      static get meta() {\n        return {\n          id: \"legacy-javascript-insight\",\n          title: \"Shim Audit\",\n          description: \"This audit was filtered out and is not available in this bundle.\",\n          scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE,\n          requiredArtifacts: []\n        };\n      }\n      static audit() {\n        return { score: null, scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE };\n      }\n    };\n    legacy_javascript_insight_default = ShimAudit22;\n  }\n});\n\n// lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/insights/modern-http-insight.js\nvar modern_http_insight_exports = {};\n__export(modern_http_insight_exports, {\n  default: () => modern_http_insight_default\n});\nvar ShimAudit23, modern_http_insight_default;\nvar init_modern_http_insight = __esm({\n  \"lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/insights/modern-http-insight.js\"() {\n    init_process_global();\n    init_audit();\n    ShimAudit23 = class extends Audit {\n      static {\n        __name(this, \"ShimAudit\");\n      }\n      static get meta() {\n        return {\n          id: \"modern-http-insight\",\n          title: \"Shim Audit\",\n          description: \"This audit was filtered out and is not available in this bundle.\",\n          scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE,\n          requiredArtifacts: []\n        };\n      }\n      static audit() {\n        return { score: null, scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE };\n      }\n    };\n    modern_http_insight_default = ShimAudit23;\n  }\n});\n\n// lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/insights/network-dependency-tree-insight.js\nvar network_dependency_tree_insight_exports = {};\n__export(network_dependency_tree_insight_exports, {\n  default: () => network_dependency_tree_insight_default\n});\nvar ShimAudit24, network_dependency_tree_insight_default;\nvar init_network_dependency_tree_insight = __esm({\n  \"lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/insights/network-dependency-tree-insight.js\"() {\n    init_process_global();\n    init_audit();\n    ShimAudit24 = class extends Audit {\n      static {\n        __name(this, \"ShimAudit\");\n      }\n      static get meta() {\n        return {\n          id: \"network-dependency-tree-insight\",\n          title: \"Shim Audit\",\n          description: \"This audit was filtered out and is not available in this bundle.\",\n          scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE,\n          requiredArtifacts: []\n        };\n      }\n      static audit() {\n        return { score: null, scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE };\n      }\n    };\n    network_dependency_tree_insight_default = ShimAudit24;\n  }\n});\n\n// lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/insights/render-blocking-insight.js\nvar render_blocking_insight_exports = {};\n__export(render_blocking_insight_exports, {\n  default: () => render_blocking_insight_default\n});\nvar ShimAudit25, render_blocking_insight_default;\nvar init_render_blocking_insight = __esm({\n  \"lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/insights/render-blocking-insight.js\"() {\n    init_process_global();\n    init_audit();\n    ShimAudit25 = class extends Audit {\n      static {\n        __name(this, \"ShimAudit\");\n      }\n      static get meta() {\n        return {\n          id: \"render-blocking-insight\",\n          title: \"Shim Audit\",\n          description: \"This audit was filtered out and is not available in this bundle.\",\n          scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE,\n          requiredArtifacts: []\n        };\n      }\n      static audit() {\n        return { score: null, scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE };\n      }\n    };\n    render_blocking_insight_default = ShimAudit25;\n  }\n});\n\n// lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/insights/slow-css-selector-insight.js\nvar slow_css_selector_insight_exports = {};\n__export(slow_css_selector_insight_exports, {\n  default: () => slow_css_selector_insight_default\n});\nvar ShimAudit26, slow_css_selector_insight_default;\nvar init_slow_css_selector_insight = __esm({\n  \"lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/insights/slow-css-selector-insight.js\"() {\n    init_process_global();\n    init_audit();\n    ShimAudit26 = class extends Audit {\n      static {\n        __name(this, \"ShimAudit\");\n      }\n      static get meta() {\n        return {\n          id: \"slow-css-selector-insight\",\n          title: \"Shim Audit\",\n          description: \"This audit was filtered out and is not available in this bundle.\",\n          scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE,\n          requiredArtifacts: []\n        };\n      }\n      static audit() {\n        return { score: null, scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE };\n      }\n    };\n    slow_css_selector_insight_default = ShimAudit26;\n  }\n});\n\n// lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/insights/third-parties-insight.js\nvar third_parties_insight_exports = {};\n__export(third_parties_insight_exports, {\n  default: () => third_parties_insight_default\n});\nvar ShimAudit27, third_parties_insight_default;\nvar init_third_parties_insight = __esm({\n  \"lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/insights/third-parties-insight.js\"() {\n    init_process_global();\n    init_audit();\n    ShimAudit27 = class extends Audit {\n      static {\n        __name(this, \"ShimAudit\");\n      }\n      static get meta() {\n        return {\n          id: \"third-parties-insight\",\n          title: \"Shim Audit\",\n          description: \"This audit was filtered out and is not available in this bundle.\",\n          scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE,\n          requiredArtifacts: []\n        };\n      }\n      static audit() {\n        return { score: null, scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE };\n      }\n    };\n    third_parties_insight_default = ShimAudit27;\n  }\n});\n\n// lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/insights/viewport-insight.js\nvar viewport_insight_exports = {};\n__export(viewport_insight_exports, {\n  default: () => viewport_insight_default\n});\nvar ShimAudit28, viewport_insight_default;\nvar init_viewport_insight = __esm({\n  \"lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/insights/viewport-insight.js\"() {\n    init_process_global();\n    init_audit();\n    ShimAudit28 = class extends Audit {\n      static {\n        __name(this, \"ShimAudit\");\n      }\n      static get meta() {\n        return {\n          id: \"viewport-insight\",\n          title: \"Shim Audit\",\n          description: \"This audit was filtered out and is not available in this bundle.\",\n          scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE,\n          requiredArtifacts: []\n        };\n      }\n      static audit() {\n        return { score: null, scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE };\n      }\n    };\n    viewport_insight_default = ShimAudit28;\n  }\n});\n\n// lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/layout-shifts.js\nvar layout_shifts_exports = {};\n__export(layout_shifts_exports, {\n  default: () => layout_shifts_default\n});\nvar ShimAudit29, layout_shifts_default;\nvar init_layout_shifts = __esm({\n  \"lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/layout-shifts.js\"() {\n    init_process_global();\n    init_audit();\n    ShimAudit29 = class extends Audit {\n      static {\n        __name(this, \"ShimAudit\");\n      }\n      static get meta() {\n        return {\n          id: \"layout-shifts\",\n          title: \"Shim Audit\",\n          description: \"This audit was filtered out and is not available in this bundle.\",\n          scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE,\n          requiredArtifacts: []\n        };\n      }\n      static audit() {\n        return { score: null, scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE };\n      }\n    };\n    layout_shifts_default = ShimAudit29;\n  }\n});\n\n// lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/long-tasks.js\nvar long_tasks_exports = {};\n__export(long_tasks_exports, {\n  default: () => long_tasks_default\n});\nvar ShimAudit30, long_tasks_default;\nvar init_long_tasks = __esm({\n  \"lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/long-tasks.js\"() {\n    init_process_global();\n    init_audit();\n    ShimAudit30 = class extends Audit {\n      static {\n        __name(this, \"ShimAudit\");\n      }\n      static get meta() {\n        return {\n          id: \"long-tasks\",\n          title: \"Shim Audit\",\n          description: \"This audit was filtered out and is not available in this bundle.\",\n          scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE,\n          requiredArtifacts: []\n        };\n      }\n      static audit() {\n        return { score: null, scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE };\n      }\n    };\n    long_tasks_default = ShimAudit30;\n  }\n});\n\n// lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/main-thread-tasks.js\nvar main_thread_tasks_exports = {};\n__export(main_thread_tasks_exports, {\n  default: () => main_thread_tasks_default\n});\nvar ShimAudit31, main_thread_tasks_default;\nvar init_main_thread_tasks = __esm({\n  \"lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/main-thread-tasks.js\"() {\n    init_process_global();\n    init_audit();\n    ShimAudit31 = class extends Audit {\n      static {\n        __name(this, \"ShimAudit\");\n      }\n      static get meta() {\n        return {\n          id: \"main-thread-tasks\",\n          title: \"Shim Audit\",\n          description: \"This audit was filtered out and is not available in this bundle.\",\n          scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE,\n          requiredArtifacts: []\n        };\n      }\n      static audit() {\n        return { score: null, scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE };\n      }\n    };\n    main_thread_tasks_default = ShimAudit31;\n  }\n});\n\n// lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/mainthread-work-breakdown.js\nvar mainthread_work_breakdown_exports = {};\n__export(mainthread_work_breakdown_exports, {\n  default: () => mainthread_work_breakdown_default\n});\nvar ShimAudit32, mainthread_work_breakdown_default;\nvar init_mainthread_work_breakdown = __esm({\n  \"lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/mainthread-work-breakdown.js\"() {\n    init_process_global();\n    init_audit();\n    ShimAudit32 = class extends Audit {\n      static {\n        __name(this, \"ShimAudit\");\n      }\n      static get meta() {\n        return {\n          id: \"mainthread-work-breakdown\",\n          title: \"Shim Audit\",\n          description: \"This audit was filtered out and is not available in this bundle.\",\n          scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE,\n          requiredArtifacts: []\n        };\n      }\n      static audit() {\n        return { score: null, scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE };\n      }\n    };\n    mainthread_work_breakdown_default = ShimAudit32;\n  }\n});\n\n// lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/metrics.js\nvar metrics_exports2 = {};\n__export(metrics_exports2, {\n  default: () => metrics_default\n});\nvar ShimAudit33, metrics_default;\nvar init_metrics2 = __esm({\n  \"lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/metrics.js\"() {\n    init_process_global();\n    init_audit();\n    ShimAudit33 = class extends Audit {\n      static {\n        __name(this, \"ShimAudit\");\n      }\n      static get meta() {\n        return {\n          id: \"metrics\",\n          title: \"Shim Audit\",\n          description: \"This audit was filtered out and is not available in this bundle.\",\n          scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE,\n          requiredArtifacts: []\n        };\n      }\n      static audit() {\n        return { score: null, scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE };\n      }\n    };\n    metrics_default = ShimAudit33;\n  }\n});\n\n// lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/metrics/cumulative-layout-shift.js\nvar cumulative_layout_shift_exports = {};\n__export(cumulative_layout_shift_exports, {\n  default: () => cumulative_layout_shift_default\n});\nvar ShimAudit34, cumulative_layout_shift_default;\nvar init_cumulative_layout_shift = __esm({\n  \"lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/metrics/cumulative-layout-shift.js\"() {\n    init_process_global();\n    init_audit();\n    ShimAudit34 = class extends Audit {\n      static {\n        __name(this, \"ShimAudit\");\n      }\n      static get meta() {\n        return {\n          id: \"cumulative-layout-shift\",\n          title: \"Shim Audit\",\n          description: \"This audit was filtered out and is not available in this bundle.\",\n          scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE,\n          requiredArtifacts: []\n        };\n      }\n      static audit() {\n        return { score: null, scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE };\n      }\n    };\n    cumulative_layout_shift_default = ShimAudit34;\n  }\n});\n\n// lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/metrics/first-contentful-paint.js\nvar first_contentful_paint_exports = {};\n__export(first_contentful_paint_exports, {\n  default: () => first_contentful_paint_default\n});\nvar ShimAudit35, first_contentful_paint_default;\nvar init_first_contentful_paint = __esm({\n  \"lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/metrics/first-contentful-paint.js\"() {\n    init_process_global();\n    init_audit();\n    ShimAudit35 = class extends Audit {\n      static {\n        __name(this, \"ShimAudit\");\n      }\n      static get meta() {\n        return {\n          id: \"first-contentful-paint\",\n          title: \"Shim Audit\",\n          description: \"This audit was filtered out and is not available in this bundle.\",\n          scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE,\n          requiredArtifacts: []\n        };\n      }\n      static audit() {\n        return { score: null, scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE };\n      }\n    };\n    first_contentful_paint_default = ShimAudit35;\n  }\n});\n\n// lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/metrics/interaction-to-next-paint.js\nvar interaction_to_next_paint_exports = {};\n__export(interaction_to_next_paint_exports, {\n  default: () => interaction_to_next_paint_default\n});\nvar ShimAudit36, interaction_to_next_paint_default;\nvar init_interaction_to_next_paint = __esm({\n  \"lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/metrics/interaction-to-next-paint.js\"() {\n    init_process_global();\n    init_audit();\n    ShimAudit36 = class extends Audit {\n      static {\n        __name(this, \"ShimAudit\");\n      }\n      static get meta() {\n        return {\n          id: \"interaction-to-next-paint\",\n          title: \"Shim Audit\",\n          description: \"This audit was filtered out and is not available in this bundle.\",\n          scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE,\n          requiredArtifacts: []\n        };\n      }\n      static audit() {\n        return { score: null, scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE };\n      }\n    };\n    interaction_to_next_paint_default = ShimAudit36;\n  }\n});\n\n// lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/metrics/interactive.js\nvar interactive_exports = {};\n__export(interactive_exports, {\n  default: () => interactive_default\n});\nvar ShimAudit37, interactive_default;\nvar init_interactive = __esm({\n  \"lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/metrics/interactive.js\"() {\n    init_process_global();\n    init_audit();\n    ShimAudit37 = class extends Audit {\n      static {\n        __name(this, \"ShimAudit\");\n      }\n      static get meta() {\n        return {\n          id: \"interactive\",\n          title: \"Shim Audit\",\n          description: \"This audit was filtered out and is not available in this bundle.\",\n          scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE,\n          requiredArtifacts: []\n        };\n      }\n      static audit() {\n        return { score: null, scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE };\n      }\n    };\n    interactive_default = ShimAudit37;\n  }\n});\n\n// lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/metrics/largest-contentful-paint.js\nvar largest_contentful_paint_exports = {};\n__export(largest_contentful_paint_exports, {\n  default: () => largest_contentful_paint_default\n});\nvar ShimAudit38, largest_contentful_paint_default;\nvar init_largest_contentful_paint = __esm({\n  \"lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/metrics/largest-contentful-paint.js\"() {\n    init_process_global();\n    init_audit();\n    ShimAudit38 = class extends Audit {\n      static {\n        __name(this, \"ShimAudit\");\n      }\n      static get meta() {\n        return {\n          id: \"largest-contentful-paint\",\n          title: \"Shim Audit\",\n          description: \"This audit was filtered out and is not available in this bundle.\",\n          scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE,\n          requiredArtifacts: []\n        };\n      }\n      static audit() {\n        return { score: null, scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE };\n      }\n    };\n    largest_contentful_paint_default = ShimAudit38;\n  }\n});\n\n// lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/metrics/max-potential-fid.js\nvar max_potential_fid_exports = {};\n__export(max_potential_fid_exports, {\n  default: () => max_potential_fid_default\n});\nvar ShimAudit39, max_potential_fid_default;\nvar init_max_potential_fid = __esm({\n  \"lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/metrics/max-potential-fid.js\"() {\n    init_process_global();\n    init_audit();\n    ShimAudit39 = class extends Audit {\n      static {\n        __name(this, \"ShimAudit\");\n      }\n      static get meta() {\n        return {\n          id: \"max-potential-fid\",\n          title: \"Shim Audit\",\n          description: \"This audit was filtered out and is not available in this bundle.\",\n          scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE,\n          requiredArtifacts: []\n        };\n      }\n      static audit() {\n        return { score: null, scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE };\n      }\n    };\n    max_potential_fid_default = ShimAudit39;\n  }\n});\n\n// lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/metrics/speed-index.js\nvar speed_index_exports = {};\n__export(speed_index_exports, {\n  default: () => speed_index_default\n});\nvar ShimAudit40, speed_index_default;\nvar init_speed_index = __esm({\n  \"lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/metrics/speed-index.js\"() {\n    init_process_global();\n    init_audit();\n    ShimAudit40 = class extends Audit {\n      static {\n        __name(this, \"ShimAudit\");\n      }\n      static get meta() {\n        return {\n          id: \"speed-index\",\n          title: \"Shim Audit\",\n          description: \"This audit was filtered out and is not available in this bundle.\",\n          scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE,\n          requiredArtifacts: []\n        };\n      }\n      static audit() {\n        return { score: null, scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE };\n      }\n    };\n    speed_index_default = ShimAudit40;\n  }\n});\n\n// lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/metrics/total-blocking-time.js\nvar total_blocking_time_exports = {};\n__export(total_blocking_time_exports, {\n  default: () => total_blocking_time_default\n});\nvar ShimAudit41, total_blocking_time_default;\nvar init_total_blocking_time = __esm({\n  \"lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/metrics/total-blocking-time.js\"() {\n    init_process_global();\n    init_audit();\n    ShimAudit41 = class extends Audit {\n      static {\n        __name(this, \"ShimAudit\");\n      }\n      static get meta() {\n        return {\n          id: \"total-blocking-time\",\n          title: \"Shim Audit\",\n          description: \"This audit was filtered out and is not available in this bundle.\",\n          scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE,\n          requiredArtifacts: []\n        };\n      }\n      static audit() {\n        return { score: null, scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE };\n      }\n    };\n    total_blocking_time_default = ShimAudit41;\n  }\n});\n\n// lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/network-requests.js\nvar network_requests_exports = {};\n__export(network_requests_exports, {\n  default: () => network_requests_default\n});\nvar ShimAudit42, network_requests_default;\nvar init_network_requests = __esm({\n  \"lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/network-requests.js\"() {\n    init_process_global();\n    init_audit();\n    ShimAudit42 = class extends Audit {\n      static {\n        __name(this, \"ShimAudit\");\n      }\n      static get meta() {\n        return {\n          id: \"network-requests\",\n          title: \"Shim Audit\",\n          description: \"This audit was filtered out and is not available in this bundle.\",\n          scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE,\n          requiredArtifacts: []\n        };\n      }\n      static audit() {\n        return { score: null, scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE };\n      }\n    };\n    network_requests_default = ShimAudit42;\n  }\n});\n\n// lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/network-rtt.js\nvar network_rtt_exports = {};\n__export(network_rtt_exports, {\n  default: () => network_rtt_default\n});\nvar ShimAudit43, network_rtt_default;\nvar init_network_rtt = __esm({\n  \"lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/network-rtt.js\"() {\n    init_process_global();\n    init_audit();\n    ShimAudit43 = class extends Audit {\n      static {\n        __name(this, \"ShimAudit\");\n      }\n      static get meta() {\n        return {\n          id: \"network-rtt\",\n          title: \"Shim Audit\",\n          description: \"This audit was filtered out and is not available in this bundle.\",\n          scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE,\n          requiredArtifacts: []\n        };\n      }\n      static audit() {\n        return { score: null, scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE };\n      }\n    };\n    network_rtt_default = ShimAudit43;\n  }\n});\n\n// lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/network-server-latency.js\nvar network_server_latency_exports = {};\n__export(network_server_latency_exports, {\n  default: () => network_server_latency_default\n});\nvar ShimAudit44, network_server_latency_default;\nvar init_network_server_latency = __esm({\n  \"lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/network-server-latency.js\"() {\n    init_process_global();\n    init_audit();\n    ShimAudit44 = class extends Audit {\n      static {\n        __name(this, \"ShimAudit\");\n      }\n      static get meta() {\n        return {\n          id: \"network-server-latency\",\n          title: \"Shim Audit\",\n          description: \"This audit was filtered out and is not available in this bundle.\",\n          scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE,\n          requiredArtifacts: []\n        };\n      }\n      static audit() {\n        return { score: null, scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE };\n      }\n    };\n    network_server_latency_default = ShimAudit44;\n  }\n});\n\n// lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/non-composited-animations.js\nvar non_composited_animations_exports = {};\n__export(non_composited_animations_exports, {\n  default: () => non_composited_animations_default\n});\nvar ShimAudit45, non_composited_animations_default;\nvar init_non_composited_animations = __esm({\n  \"lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/non-composited-animations.js\"() {\n    init_process_global();\n    init_audit();\n    ShimAudit45 = class extends Audit {\n      static {\n        __name(this, \"ShimAudit\");\n      }\n      static get meta() {\n        return {\n          id: \"non-composited-animations\",\n          title: \"Shim Audit\",\n          description: \"This audit was filtered out and is not available in this bundle.\",\n          scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE,\n          requiredArtifacts: []\n        };\n      }\n      static audit() {\n        return { score: null, scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE };\n      }\n    };\n    non_composited_animations_default = ShimAudit45;\n  }\n});\n\n// lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/oopif-iframe-test-audit.js\nvar oopif_iframe_test_audit_exports = {};\n__export(oopif_iframe_test_audit_exports, {\n  default: () => oopif_iframe_test_audit_default\n});\nvar ShimAudit46, oopif_iframe_test_audit_default;\nvar init_oopif_iframe_test_audit = __esm({\n  \"lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/oopif-iframe-test-audit.js\"() {\n    init_process_global();\n    init_audit();\n    ShimAudit46 = class extends Audit {\n      static {\n        __name(this, \"ShimAudit\");\n      }\n      static get meta() {\n        return {\n          id: \"oopif-iframe-test-audit\",\n          title: \"Shim Audit\",\n          description: \"This audit was filtered out and is not available in this bundle.\",\n          scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE,\n          requiredArtifacts: []\n        };\n      }\n      static audit() {\n        return { score: null, scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE };\n      }\n    };\n    oopif_iframe_test_audit_default = ShimAudit46;\n  }\n});\n\n// lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/predictive-perf.js\nvar predictive_perf_exports = {};\n__export(predictive_perf_exports, {\n  default: () => predictive_perf_default\n});\nvar ShimAudit47, predictive_perf_default;\nvar init_predictive_perf = __esm({\n  \"lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/predictive-perf.js\"() {\n    init_process_global();\n    init_audit();\n    ShimAudit47 = class extends Audit {\n      static {\n        __name(this, \"ShimAudit\");\n      }\n      static get meta() {\n        return {\n          id: \"predictive-perf\",\n          title: \"Shim Audit\",\n          description: \"This audit was filtered out and is not available in this bundle.\",\n          scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE,\n          requiredArtifacts: []\n        };\n      }\n      static audit() {\n        return { score: null, scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE };\n      }\n    };\n    predictive_perf_default = ShimAudit47;\n  }\n});\n\n// lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/redirects.js\nvar redirects_exports = {};\n__export(redirects_exports, {\n  default: () => redirects_default\n});\nvar ShimAudit48, redirects_default;\nvar init_redirects = __esm({\n  \"lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/redirects.js\"() {\n    init_process_global();\n    init_audit();\n    ShimAudit48 = class extends Audit {\n      static {\n        __name(this, \"ShimAudit\");\n      }\n      static get meta() {\n        return {\n          id: \"redirects\",\n          title: \"Shim Audit\",\n          description: \"This audit was filtered out and is not available in this bundle.\",\n          scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE,\n          requiredArtifacts: []\n        };\n      }\n      static audit() {\n        return { score: null, scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE };\n      }\n    };\n    redirects_default = ShimAudit48;\n  }\n});\n\n// lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/resource-summary.js\nvar resource_summary_exports = {};\n__export(resource_summary_exports, {\n  default: () => resource_summary_default\n});\nvar ShimAudit49, resource_summary_default;\nvar init_resource_summary = __esm({\n  \"lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/resource-summary.js\"() {\n    init_process_global();\n    init_audit();\n    ShimAudit49 = class extends Audit {\n      static {\n        __name(this, \"ShimAudit\");\n      }\n      static get meta() {\n        return {\n          id: \"resource-summary\",\n          title: \"Shim Audit\",\n          description: \"This audit was filtered out and is not available in this bundle.\",\n          scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE,\n          requiredArtifacts: []\n        };\n      }\n      static audit() {\n        return { score: null, scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE };\n      }\n    };\n    resource_summary_default = ShimAudit49;\n  }\n});\n\n// lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/screenshot-thumbnails.js\nvar screenshot_thumbnails_exports = {};\n__export(screenshot_thumbnails_exports, {\n  default: () => screenshot_thumbnails_default\n});\nvar ShimAudit50, screenshot_thumbnails_default;\nvar init_screenshot_thumbnails = __esm({\n  \"lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/screenshot-thumbnails.js\"() {\n    init_process_global();\n    init_audit();\n    ShimAudit50 = class extends Audit {\n      static {\n        __name(this, \"ShimAudit\");\n      }\n      static get meta() {\n        return {\n          id: \"screenshot-thumbnails\",\n          title: \"Shim Audit\",\n          description: \"This audit was filtered out and is not available in this bundle.\",\n          scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE,\n          requiredArtifacts: []\n        };\n      }\n      static audit() {\n        return { score: null, scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE };\n      }\n    };\n    screenshot_thumbnails_default = ShimAudit50;\n  }\n});\n\n// lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/script-treemap-data.js\nvar script_treemap_data_exports = {};\n__export(script_treemap_data_exports, {\n  default: () => script_treemap_data_default\n});\nvar ShimAudit51, script_treemap_data_default;\nvar init_script_treemap_data = __esm({\n  \"lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/script-treemap-data.js\"() {\n    init_process_global();\n    init_audit();\n    ShimAudit51 = class extends Audit {\n      static {\n        __name(this, \"ShimAudit\");\n      }\n      static get meta() {\n        return {\n          id: \"script-treemap-data\",\n          title: \"Shim Audit\",\n          description: \"This audit was filtered out and is not available in this bundle.\",\n          scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE,\n          requiredArtifacts: []\n        };\n      }\n      static audit() {\n        return { score: null, scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE };\n      }\n    };\n    script_treemap_data_default = ShimAudit51;\n  }\n});\n\n// lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/server-response-time.js\nvar server_response_time_exports = {};\n__export(server_response_time_exports, {\n  default: () => server_response_time_default\n});\nvar ShimAudit52, server_response_time_default;\nvar init_server_response_time = __esm({\n  \"lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/server-response-time.js\"() {\n    init_process_global();\n    init_audit();\n    ShimAudit52 = class extends Audit {\n      static {\n        __name(this, \"ShimAudit\");\n      }\n      static get meta() {\n        return {\n          id: \"server-response-time\",\n          title: \"Shim Audit\",\n          description: \"This audit was filtered out and is not available in this bundle.\",\n          scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE,\n          requiredArtifacts: []\n        };\n      }\n      static audit() {\n        return { score: null, scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE };\n      }\n    };\n    server_response_time_default = ShimAudit52;\n  }\n});\n\n// lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/unsized-images.js\nvar unsized_images_exports = {};\n__export(unsized_images_exports, {\n  default: () => unsized_images_default\n});\nvar ShimAudit53, unsized_images_default;\nvar init_unsized_images = __esm({\n  \"lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/unsized-images.js\"() {\n    init_process_global();\n    init_audit();\n    ShimAudit53 = class extends Audit {\n      static {\n        __name(this, \"ShimAudit\");\n      }\n      static get meta() {\n        return {\n          id: \"unsized-images\",\n          title: \"Shim Audit\",\n          description: \"This audit was filtered out and is not available in this bundle.\",\n          scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE,\n          requiredArtifacts: []\n        };\n      }\n      static audit() {\n        return { score: null, scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE };\n      }\n    };\n    unsized_images_default = ShimAudit53;\n  }\n});\n\n// lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/user-timings.js\nvar user_timings_exports = {};\n__export(user_timings_exports, {\n  default: () => user_timings_default\n});\nvar ShimAudit54, user_timings_default;\nvar init_user_timings = __esm({\n  \"lh-audit-shim:/Users/alexrudenko/src/lighthouse/core/audits/user-timings.js\"() {\n    init_process_global();\n    init_audit();\n    ShimAudit54 = class extends Audit {\n      static {\n        __name(this, \"ShimAudit\");\n      }\n      static get meta() {\n        return {\n          id: \"user-timings\",\n          title: \"Shim Audit\",\n          description: \"This audit was filtered out and is not available in this bundle.\",\n          scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE,\n          requiredArtifacts: []\n        };\n      }\n      static audit() {\n        return { score: null, scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE };\n      }\n    };\n    user_timings_default = ShimAudit54;\n  }\n});\n\n// replace-modules:/Users/alexrudenko/src/lighthouse/node_modules/@sentry/node/build/cjs/index.js\nvar cjs_exports = {};\n__export(cjs_exports, {\n  default: () => cjs_default\n});\nvar cjs_default;\nvar init_cjs = __esm({\n  \"replace-modules:/Users/alexrudenko/src/lighthouse/node_modules/@sentry/node/build/cjs/index.js\"() {\n    init_process_global();\n    cjs_default = {};\n  }\n});\n\n// clients/devtools-mcp/devtools-mcp-entry.js\ninit_process_global();\n\n// core/index.js\ninit_process_global();\ninit_trace();\n\n// core/runner.js\ninit_process_global();\ninit_lighthouse_logger();\ninit_lodash();\nimport path6 from \"path\";\n\n// core/scoring.js\ninit_process_global();\ninit_audit();\n/**\n * @license\n * Copyright 2018 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\nvar clampTo2Decimals2 = /* @__PURE__ */ __name((val) => Math.round(val * 100) / 100, \"clampTo2Decimals\");\nvar ReportScoring = class _ReportScoring {\n  static {\n    __name(this, \"ReportScoring\");\n  }\n  /**\n   * Computes the weighted-average of the score of the list of items.\n   * @param {Array<{score: number|null, weight: number}>} items\n   * @return {number|null}\n   */\n  static arithmeticMean(items) {\n    items = items.filter((item) => item.weight > 0);\n    if (items.some((item) => item.score === null)) return null;\n    const results = items.reduce(\n      (result, item) => {\n        const score = item.score;\n        const weight = item.weight;\n        return {\n          weight: result.weight + weight,\n          sum: result.sum + /** @type {number} */\n          score * weight\n        };\n      },\n      { weight: 0, sum: 0 }\n    );\n    return clampTo2Decimals2(results.sum / results.weight || 0);\n  }\n  /**\n   * Returns the report JSON object with computed scores.\n   * @param {Object<string, LH.Config.Category>} configCategories\n   * @param {Object<string, LH.RawIcu<LH.Audit.Result>>} resultsByAuditId\n   * @return {Object<string, LH.RawIcu<LH.Result.Category>>}\n   */\n  static scoreAllCategories(configCategories, resultsByAuditId) {\n    const scoredCategories = {};\n    for (const [categoryId, configCategory] of Object.entries(configCategories)) {\n      const auditRefs = configCategory.auditRefs.map((configMember) => {\n        const member = { ...configMember };\n        const result = resultsByAuditId[member.id];\n        if (result.scoreDisplayMode === Audit.SCORING_MODES.NOT_APPLICABLE || result.scoreDisplayMode === Audit.SCORING_MODES.INFORMATIVE || result.scoreDisplayMode === Audit.SCORING_MODES.MANUAL) {\n          member.weight = 0;\n        }\n        return member;\n      });\n      const scores = auditRefs.map((auditRef) => ({\n        score: resultsByAuditId[auditRef.id].score,\n        weight: auditRef.weight\n      }));\n      const score = _ReportScoring.arithmeticMean(scores);\n      scoredCategories[categoryId] = {\n        ...configCategory,\n        auditRefs,\n        id: categoryId,\n        score\n      };\n    }\n    return scoredCategories;\n  }\n};\n\n// core/runner.js\ninit_audit();\ninit_format();\n\n// core/lib/stack-packs.js\ninit_process_global();\ninit_lighthouse_logger();\nvar import_lighthouse_stack_packs = __toESM(require_lighthouse_stack_packs(), 1);\ninit_i18n();\n/**\n * @license\n * Copyright 2019 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\nvar stackPacksToInclude = [\n  {\n    packId: \"gatsby\",\n    requiredStacks: [\"js:gatsby\"]\n  },\n  {\n    packId: \"wordpress\",\n    requiredStacks: [\"js:wordpress\"]\n  },\n  {\n    packId: \"wix\",\n    requiredStacks: [\"js:wix\"]\n  },\n  {\n    packId: \"wp-rocket\",\n    requiredStacks: [\"js:wp-rocket\"]\n  },\n  {\n    packId: \"ezoic\",\n    requiredStacks: [\"js:ezoic\"]\n  },\n  {\n    packId: \"drupal\",\n    requiredStacks: [\"js:drupal\"]\n  },\n  {\n    packId: \"nitropack\",\n    requiredStacks: [\"js:nitropack\"]\n  },\n  {\n    packId: \"amp\",\n    requiredStacks: [\"js:amp\"]\n  },\n  {\n    packId: \"magento\",\n    requiredStacks: [\"js:magento\"]\n  },\n  {\n    packId: \"octobercms\",\n    requiredStacks: [\"js:octobercms\"]\n  },\n  {\n    packId: \"joomla\",\n    requiredStacks: [\"js:joomla\"]\n  },\n  {\n    packId: \"next.js\",\n    requiredStacks: [\"js:next\"]\n  },\n  {\n    packId: \"nuxt\",\n    requiredStacks: [\"js:nuxt\"]\n  },\n  {\n    packId: \"angular\",\n    requiredStacks: [\"js:angular\"]\n  },\n  {\n    packId: \"react\",\n    requiredStacks: [\"js:react\"]\n  }\n];\nfunction getStackPacks(pageStacks) {\n  if (!pageStacks) return [];\n  const packs = [];\n  for (const pageStack of pageStacks) {\n    const stackPackToIncl = stackPacksToInclude.find((stackPackToIncl2) => stackPackToIncl2.requiredStacks.includes(`${pageStack.detector}:${pageStack.id}`));\n    if (!stackPackToIncl) {\n      continue;\n    }\n    const matchedPack = import_lighthouse_stack_packs.default.find((pack) => pack.id === stackPackToIncl.packId);\n    if (!matchedPack) {\n      lighthouse_logger_default.warn(\n        \"StackPacks\",\n        `'${stackPackToIncl.packId}' stack pack was matched but is not found in stack-packs lib`\n      );\n      continue;\n    }\n    const str_105 = createIcuMessageFn(\n      `node_modules/lighthouse-stack-packs/packs/${matchedPack.id}.js`,\n      matchedPack.UIStrings\n    );\n    const descriptions = {};\n    const UIStrings125 = matchedPack.UIStrings;\n    for (const key in UIStrings125) {\n      if (UIStrings125[key]) {\n        descriptions[key] = str_105(UIStrings125[key]);\n      }\n    }\n    packs.push({\n      id: matchedPack.id,\n      title: matchedPack.title,\n      iconDataURL: matchedPack.icon,\n      descriptions\n    });\n  }\n  return packs.sort((a, b) => {\n    const aVal = stackPacksToInclude.findIndex((p) => p.packId === a.id);\n    const bVal = stackPacksToInclude.findIndex((p) => p.packId === b.id);\n    return aVal - bVal;\n  });\n}\n__name(getStackPacks, \"getStackPacks\");\n\n// core/lib/asset-saver.js\ninit_process_global();\ninit_url();\ninit_lighthouse_logger();\ninit_lantern2();\nimport fs from \"fs\";\nimport path3 from \"path\";\nimport stream from \"stream\";\nimport { createGzip, gunzipSync } from \"zlib\";\n\n// core/lib/lantern-trace-saver.js\ninit_process_global();\n/**\n * @license\n * Copyright 2018 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\n// core/lib/traces/metric-trace-events.js\ninit_process_global();\ninit_lighthouse_logger();\ninit_trace_processor();\n/**\n * @license\n * Copyright 2017 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\n// core/computed/network-analysis.js\ninit_process_global();\ninit_lighthouse_logger();\ninit_lantern2();\ninit_computed_artifact();\ninit_network_records();\n/**\n * @license\n * Copyright 2017 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\nvar NetworkAnalysis = class {\n  static {\n    __name(this, \"NetworkAnalysis\");\n  }\n  /**\n   * @param {LH.DevtoolsLog} devtoolsLog\n   * @param {LH.Artifacts.ComputedContext} context\n   * @return {Promise<LH.Artifacts.NetworkAnalysis>}\n   */\n  static async compute_(devtoolsLog, context) {\n    const records = await NetworkRecordsComputed.request(devtoolsLog, context);\n    const analysis = core_exports.NetworkAnalyzer.analyze(records);\n    if (!analysis) {\n      lighthouse_logger_default.error(\"NetworkAnalysis\", \"Network analysis failed due to lack of transfer data\");\n      return {\n        throughput: 0,\n        rtt: Number.POSITIVE_INFINITY,\n        additionalRttByOrigin: /* @__PURE__ */ new Map(),\n        serverResponseTimeByOrigin: /* @__PURE__ */ new Map()\n      };\n    }\n    return analysis;\n  }\n};\nvar NetworkAnalysisComputed = makeComputedArtifact(NetworkAnalysis, null);\n\n// core/computed/load-simulator.js\ninit_process_global();\ninit_computed_artifact();\ninit_lantern2();\n/**\n * @license\n * Copyright 2018 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\nvar LoadSimulator = class {\n  static {\n    __name(this, \"LoadSimulator\");\n  }\n  /**\n   * @param {{devtoolsLog: LH.DevtoolsLog, settings: LH.Audit.Context['settings']}} data\n   * @param {LH.Artifacts.ComputedContext} context\n   * @return {Promise<LH.Gatherer.Simulation.Simulator>}\n   */\n  static async compute_(data31, context) {\n    const networkAnalysis = await NetworkAnalysisComputed.request(data31.devtoolsLog, context);\n    return simulation_exports.Simulator.createSimulator({ ...data31.settings, networkAnalysis });\n  }\n  /**\n   * @param {LH.Artifacts.NetworkAnalysis} networkAnalysis\n   * @return {LH.PrecomputedLanternData}\n   */\n  static convertAnalysisToSaveableLanternData(networkAnalysis) {\n    const lanternData = { additionalRttByOrigin: {}, serverResponseTimeByOrigin: {} };\n    for (const [origin, value] of networkAnalysis.additionalRttByOrigin.entries()) {\n      if (origin.startsWith(\"http\")) lanternData.additionalRttByOrigin[origin] = value;\n    }\n    for (const [origin, value] of networkAnalysis.serverResponseTimeByOrigin.entries()) {\n      if (origin.startsWith(\"http\")) lanternData.serverResponseTimeByOrigin[origin] = value;\n    }\n    return lanternData;\n  }\n};\nvar LoadSimulatorComputed = makeComputedArtifact(LoadSimulator, [\"devtoolsLog\", \"settings\"]);\n\n// core/lib/asset-saver.js\ninit_lh_error();\ninit_root2();\n/**\n * @license\n * Copyright 2016 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\nvar artifactsFilename = \"artifacts.json\";\nvar traceFilename = \"trace.json\";\nvar devtoolsFilename = \"devtoolslog.json\";\nvar errorPrefix = \"pageLoadError.\";\nasync function writeJson(contents, path7, gzip) {\n  const writeStream = fs.createWriteStream(gzip ? path7 + \".gz\" : path7);\n  if (gzip) {\n    await stream.promises.pipeline(contents, createGzip(), writeStream);\n  } else {\n    await stream.promises.pipeline(contents, writeStream);\n  }\n}\n__name(writeJson, \"writeJson\");\nfunction readJson(filename, reviver) {\n  if (fs.existsSync(filename + \".gz\")) {\n    filename = filename + \".gz\";\n  }\n  if (!filename.endsWith(\".json.gz\")) {\n    return JSON.parse(fs.readFileSync(filename, \"utf8\"), reviver);\n  }\n  const buffer = gunzipSync(fs.readFileSync(filename));\n  return JSON.parse(buffer.toString(\"utf8\"), reviver);\n}\n__name(readJson, \"readJson\");\nfunction endsWithSuffix(filename, suffix) {\n  return filename.endsWith(suffix) || filename.endsWith(suffix + \".gz\");\n}\n__name(endsWithSuffix, \"endsWithSuffix\");\nfunction loadArtifacts(basePath) {\n  lighthouse_logger_default.log(\"Reading artifacts from disk:\", basePath);\n  if (!fs.existsSync(basePath)) {\n    throw new Error(\"No saved artifacts found at \" + basePath);\n  }\n  const artifacts = readJson(path3.join(basePath, artifactsFilename), LighthouseError.parseReviver);\n  const filenames = fs.readdirSync(basePath);\n  filenames.filter((f) => endsWithSuffix(f, devtoolsFilename)).forEach((filename) => {\n    const devtoolsLog = readJson(path3.join(basePath, filename));\n    if (filename.startsWith(devtoolsFilename)) {\n      artifacts.DevtoolsLog = devtoolsLog;\n    } else if (filename.startsWith(errorPrefix)) {\n      artifacts.DevtoolsLogError = devtoolsLog;\n    }\n  });\n  filenames.filter((f) => endsWithSuffix(f, traceFilename)).forEach((filename) => {\n    let trace = readJson(path3.join(basePath, filename));\n    if (Array.isArray(trace)) {\n      trace = { traceEvents: trace };\n    }\n    if (filename.startsWith(traceFilename)) {\n      artifacts.Trace = trace;\n    } else if (filename.startsWith(errorPrefix)) {\n      artifacts.TraceError = trace;\n    }\n  });\n  if (Array.isArray(artifacts.Timing)) {\n    artifacts.Timing.forEach((entry) => entry.gather = true);\n  }\n  return artifacts;\n}\n__name(loadArtifacts, \"loadArtifacts\");\nfunction stringifyReplacer(key, value) {\n  if (value instanceof Error) {\n    return LighthouseError.stringifyReplacer(value);\n  }\n  return value;\n}\n__name(stringifyReplacer, \"stringifyReplacer\");\nasync function saveArtifacts(artifacts, basePath, options = {}) {\n  const status = { msg: \"Saving artifacts\", id: \"lh:assetSaver:saveArtifacts\" };\n  lighthouse_logger_default.time(status);\n  fs.mkdirSync(basePath, { recursive: true });\n  const filenames = fs.readdirSync(basePath);\n  for (const filename of filenames) {\n    const isPreviousFile = filename.endsWith(traceFilename) || filename.endsWith(devtoolsFilename) || filename.endsWith(traceFilename + \".gz\") || filename.endsWith(devtoolsFilename + \".gz\") || filename === artifactsFilename || filename === artifactsFilename + \".gz\";\n    if (isPreviousFile) {\n      fs.unlinkSync(`${basePath}/${filename}`);\n    }\n  }\n  const {\n    DevtoolsLog: DevtoolsLog2,\n    Trace,\n    DevtoolsLogError,\n    TraceError,\n    ...restArtifacts\n  } = artifacts;\n  if (Trace) {\n    await saveTrace(Trace, `${basePath}/${traceFilename}`, options);\n  }\n  if (TraceError) {\n    await saveTrace(TraceError, `${basePath}/${errorPrefix}${traceFilename}`, options);\n  }\n  if (DevtoolsLog2) {\n    await saveDevtoolsLog(\n      DevtoolsLog2,\n      `${basePath}/${devtoolsFilename}`,\n      options\n    );\n  }\n  if (DevtoolsLogError) {\n    await saveDevtoolsLog(\n      DevtoolsLogError,\n      `${basePath}/${errorPrefix}${devtoolsFilename}`,\n      options\n    );\n  }\n  const restArtifactsString = JSON.stringify(restArtifacts, stringifyReplacer, 2);\n  await writeJson(function* () {\n    yield restArtifactsString;\n    yield \"\\n\";\n  }, `${basePath}/${artifactsFilename}`, !!options.gzip);\n  lighthouse_logger_default.log(\"Artifacts saved to disk in folder:\", basePath);\n  lighthouse_logger_default.timeEnd(status);\n}\n__name(saveArtifacts, \"saveArtifacts\");\nfunction saveLhr(lhr, basePath) {\n  fs.writeFileSync(`${basePath}/lhr.report.json`, JSON.stringify(lhr, null, 2));\n}\n__name(saveLhr, \"saveLhr\");\nfunction* arrayOfObjectsJsonGenerator(arrayOfObjects) {\n  const ITEMS_PER_ITERATION = 500;\n  yield \"[\\n\";\n  if (arrayOfObjects.length > 0) {\n    const itemsIterator = arrayOfObjects[Symbol.iterator]();\n    const firstItem = itemsIterator.next().value;\n    yield `  ${JSON.stringify(firstItem)}`;\n    let itemsRemaining = ITEMS_PER_ITERATION;\n    let itemsJSON = \"\";\n    for (const item of itemsIterator) {\n      itemsJSON += `,\n  ${JSON.stringify(item)}`;\n      itemsRemaining--;\n      if (itemsRemaining === 0) {\n        yield itemsJSON;\n        itemsRemaining = ITEMS_PER_ITERATION;\n        itemsJSON = \"\";\n      }\n    }\n    yield itemsJSON;\n  }\n  yield \"\\n]\";\n}\n__name(arrayOfObjectsJsonGenerator, \"arrayOfObjectsJsonGenerator\");\nfunction* traceJsonGenerator(traceData) {\n  const { traceEvents, ...rest } = traceData;\n  yield \"{\\n\";\n  yield '\"traceEvents\": ';\n  yield* arrayOfObjectsJsonGenerator(traceEvents);\n  for (const [key, value] of Object.entries(rest)) {\n    yield `,\n\"${key}\": ${JSON.stringify(value, null, 2)}`;\n  }\n  yield \"}\\n\";\n}\n__name(traceJsonGenerator, \"traceJsonGenerator\");\nfunction saveTrace(traceData, traceFilename2, options = {}) {\n  const traceIter = traceJsonGenerator(traceData);\n  return writeJson(traceIter, traceFilename2, !!options.gzip);\n}\n__name(saveTrace, \"saveTrace\");\nfunction saveDevtoolsLog(devtoolsLog, devtoolLogFilename, options = {}) {\n  return writeJson(function* () {\n    yield* arrayOfObjectsJsonGenerator(devtoolsLog);\n    yield \"\\n\";\n  }, devtoolLogFilename, !!options.gzip);\n}\n__name(saveDevtoolsLog, \"saveDevtoolsLog\");\n\n// core/lib/sentry.js\ninit_process_global();\ninit_lighthouse_logger();\n\n// core/config/config.js\ninit_process_global();\ninit_lighthouse_logger();\nimport path5 from \"path\";\n\n// core/config/default-config.js\ninit_process_global();\ninit_lh();\n\n// core/config/constants.js\nvar constants_exports = {};\n__export(constants_exports, {\n  defaultSettings: () => defaultSettings,\n  nonSimulatedSettingsOverrides: () => nonSimulatedSettingsOverrides,\n  screenEmulationMetrics: () => screenEmulationMetrics,\n  throttling: () => throttling2,\n  userAgents: () => userAgents\n});\ninit_process_global();\ninit_lantern2();\n/**\n * @license\n * Copyright 2018 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\nvar throttling2 = simulation_exports.Constants.throttling;\nvar MOTOGPOWER_EMULATION_METRICS = {\n  mobile: true,\n  width: 412,\n  height: 823,\n  // This value has some interesting ramifications for image-size-responsive, see:\n  // https://github.com/GoogleChrome/lighthouse/issues/10741#issuecomment-626903508\n  deviceScaleFactor: 1.75,\n  disabled: false\n};\nvar DESKTOP_EMULATION_METRICS = {\n  mobile: false,\n  width: 1350,\n  height: 940,\n  deviceScaleFactor: 1,\n  disabled: false\n};\nvar screenEmulationMetrics = {\n  mobile: MOTOGPOWER_EMULATION_METRICS,\n  desktop: DESKTOP_EMULATION_METRICS\n};\nvar MOTOG4_USERAGENT = \"Mozilla/5.0 (Linux; Android 11; moto g power (2022)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Mobile Safari/537.36\";\nvar DESKTOP_USERAGENT = \"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36\";\nvar userAgents = {\n  mobile: MOTOG4_USERAGENT,\n  desktop: DESKTOP_USERAGENT\n};\nvar defaultSettings = {\n  output: \"json\",\n  maxWaitForFcp: 30 * 1e3,\n  maxWaitForLoad: 45 * 1e3,\n  pauseAfterFcpMs: 1e3,\n  pauseAfterLoadMs: 1e3,\n  networkQuietThresholdMs: 1e3,\n  cpuQuietThresholdMs: 1e3,\n  formFactor: \"mobile\",\n  throttling: throttling2.mobileSlow4G,\n  throttlingMethod: \"simulate\",\n  screenEmulation: screenEmulationMetrics.mobile,\n  emulatedUserAgent: userAgents.mobile,\n  auditMode: false,\n  gatherMode: false,\n  clearStorageTypes: [\"file_systems\", \"shader_cache\", \"service_workers\", \"cache_storage\"],\n  disableStorageReset: false,\n  debugNavigation: false,\n  channel: \"node\",\n  usePassiveGathering: false,\n  disableFullPageScreenshot: false,\n  skipAboutBlank: false,\n  blankPage: \"about:blank\",\n  ignoreStatusCode: false,\n  // the following settings have no defaults but we still want ensure that `key in settings`\n  // in config will work in a typechecked way\n  locale: \"en-US\",\n  // actual default determined by Config using lib/i18n\n  blockedUrlPatterns: null,\n  additionalTraceCategories: null,\n  extraHeaders: null,\n  precomputedLanternData: null,\n  onlyAudits: null,\n  onlyCategories: null,\n  skipAudits: null\n};\nvar nonSimulatedSettingsOverrides = {\n  pauseAfterFcpMs: 5250,\n  pauseAfterLoadMs: 5250,\n  networkQuietThresholdMs: 5250,\n  cpuQuietThresholdMs: 5250\n};\n\n// core/config/default-config.js\ninit_i18n();\n/**\n * @license\n * Copyright 2018 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\nvar UIStrings21 = {\n  /** Title of the Performance category of audits. Equivalent to 'Web performance', this term is inclusive of all web page speed and loading optimization topics. Also used as a label of a score gauge; try to limit to 20 characters. */\n  performanceCategoryTitle: \"Performance\",\n  /** Title of the speed metrics section of the Performance category. Within this section are various speed metrics which quantify the pageload performance into values presented in seconds and milliseconds. */\n  metricGroupTitle: \"Metrics\",\n  /** Title of the insights section of the Performance category. Within this section are various insights to give developers tips on how to improve the performance of their page. */\n  insightsGroupTitle: \"Insights\",\n  /** Description of the insights section of the Performance category. Within this section are various insights to give developers tips on how to improve the performance of their page. */\n  insightsGroupDescription: \"These insights are also available in the Chrome DevTools Performance Panel - [record a trace](https://developer.chrome.com/docs/devtools/performance/reference) to view more detailed information.\",\n  /** Title of an opportunity sub-section of the Performance category. Within this section are audits with imperative titles that suggest actions the user can take to improve the time of the first initial render of the webpage. */\n  firstPaintImprovementsGroupTitle: \"First Paint Improvements\",\n  /** Description of an opportunity sub-section of the Performance category. Within this section are audits with imperative titles that suggest actions the user can take to improve the time of the first initial render of the webpage. */\n  firstPaintImprovementsGroupDescription: \"The most critical aspect of performance is how quickly pixels are rendered onscreen. Key metrics: First Contentful Paint, First Meaningful Paint\",\n  /** Title of an opportunity sub-section of the Performance category. Within this section are audits with imperative titles that suggest actions the user can take to improve the overall loading performance of their web page. */\n  overallImprovementsGroupTitle: \"Overall Improvements\",\n  /** Description of an opportunity sub-section of the Performance category. Within this section are audits with imperative titles that suggest actions the user can take to improve the overall loading performance of their web page. */\n  overallImprovementsGroupDescription: \"Enhance the overall loading experience, so the page is responsive and ready to use as soon as possible. Key metrics: Time to Interactive, Speed Index\",\n  /** Title of the diagnostics section of the Performance category. Within this section are audits with non-imperative titles that provide more detail on the page's page load performance characteristics. Whereas the 'Opportunities' suggest an action along with expected time savings, diagnostics do not. Within this section, the user may read the details and deduce additional actions they could take. */\n  diagnosticsGroupTitle: \"Diagnostics\",\n  /** Description of the diagnostics section of the Performance category. Within this section are audits with non-imperative titles that provide more detail on a web page's load performance characteristics. Within this section, the user may read the details and deduce additional actions they could take to improve performance. */\n  diagnosticsGroupDescription: \"More information about the performance of your application. These numbers don't [directly affect](https://developer.chrome.com/docs/lighthouse/performance/performance-scoring/) the Performance score.\",\n  /** Title of the Accessibility category of audits. This section contains audits focused on making web content accessible to all users. Also used as a label of a score gauge; try to limit to 20 characters. */\n  a11yCategoryTitle: \"Accessibility\",\n  /** Description of the Accessibility category. This is displayed at the top of a list of audits focused on making web content accessible to all users. No character length limits. 'improve the accessibility of your web app' and 'manual testing' become link texts to additional documentation. */\n  a11yCategoryDescription: \"These checks highlight opportunities to [improve the accessibility of your web app](https://developer.chrome.com/docs/lighthouse/accessibility/). Automatic detection can only detect a subset of issues and does not guarantee the accessibility of your web app, so [manual testing](https://web.dev/articles/how-to-review) is also encouraged.\",\n  /** Description of the Accessibility manual checks category. This description is displayed above a list of accessibility audits that currently have no automated test and so must be verified manually by the user. No character length limits. 'conducting an accessibility review' becomes link text to additional documentation. */\n  a11yCategoryManualDescription: \"These items address areas which an automated testing tool cannot cover. Learn more in our guide on [conducting an accessibility review](https://web.dev/articles/how-to-review).\",\n  /** Title of the best practices section of the Accessibility category. Within this section are audits with descriptive titles that highlight common accessibility best practices. */\n  a11yBestPracticesGroupTitle: \"Best practices\",\n  /** Description of the best practices section within the Accessibility category. Within this section are audits with descriptive titles that highlight common accessibility best practices. */\n  a11yBestPracticesGroupDescription: \"These items highlight common accessibility best practices.\",\n  /** Title of the color contrast section within the Accessibility category. Within this section are audits with descriptive titles that highlight the color and vision aspects of the page's accessibility that are passing or failing. */\n  a11yColorContrastGroupTitle: \"Contrast\",\n  /** Description of the color contrast section within the Accessibility category. Within this section are audits with descriptive titles that highlight the color and vision aspects of the page's accessibility that are passing or failing. */\n  a11yColorContrastGroupDescription: \"These are opportunities to improve the legibility of your content.\",\n  /** Title of the HTML element naming section within the Accessibility category. Within this section are audits with descriptive titles that highlight if the non-textual HTML elements on the page have names discernible by a screen reader. */\n  a11yNamesLabelsGroupTitle: \"Names and labels\",\n  /** Description of the HTML element naming section within the Accessibility category. Within this section are audits with descriptive titles that highlight if the non-textual HTML elements on the page have names discernible by a screen reader. */\n  a11yNamesLabelsGroupDescription: \"These are opportunities to improve the semantics of the controls in your application. This may enhance the experience for users of assistive technology, like a screen reader.\",\n  /** Title of the navigation section within the Accessibility category. Within this section are audits with descriptive titles that highlight opportunities to improve keyboard navigation. */\n  a11yNavigationGroupTitle: \"Navigation\",\n  /** Description of the navigation section within the Accessibility category. Within this section are audits with descriptive titles that highlight opportunities to improve keyboard navigation. */\n  a11yNavigationGroupDescription: \"These are opportunities to improve keyboard navigation in your application.\",\n  /** Title of the ARIA validity section within the Accessibility category. Within this section are audits with descriptive titles that highlight if whether all the aria-* HTML attributes have been used properly. */\n  a11yAriaGroupTitle: \"ARIA\",\n  /** Description of the ARIA validity section within the Accessibility category. Within this section are audits with descriptive titles that highlight if whether all the aria-* HTML attributes have been used properly. */\n  a11yAriaGroupDescription: \"These are opportunities to improve the usage of ARIA in your application which may enhance the experience for users of assistive technology, like a screen reader.\",\n  /** Title of the language section within the Accessibility category. Within this section are audits with descriptive titles that highlight if the language has been annotated in the correct HTML attributes on the page. */\n  a11yLanguageGroupTitle: \"Internationalization and localization\",\n  /** Description of the language section within the Accessibility category. Within this section are audits with descriptive titles that highlight if the language has been annotated in the correct HTML attributes on the page. */\n  a11yLanguageGroupDescription: \"These are opportunities to improve the interpretation of your content by users in different locales.\",\n  /** Title of the navigation section within the Accessibility category. Within this section are audits with descriptive titles that highlight opportunities to provide alternative content for audio and video. */\n  a11yAudioVideoGroupTitle: \"Audio and video\",\n  /** Description of the navigation section within the Accessibility category. Within this section are audits with descriptive titles that highlight opportunities to provide alternative content for audio and video. */\n  a11yAudioVideoGroupDescription: \"These are opportunities to provide alternative content for audio and video. This may improve the experience for users with hearing or vision impairments.\",\n  /** Title of the navigation section within the Accessibility category. Within this section are audits with descriptive titles that highlight opportunities to improve the experience of reading tabular or list data using assistive technology. */\n  a11yTablesListsVideoGroupTitle: \"Tables and lists\",\n  /** Description of the navigation section within the Accessibility category. Within this section are audits with descriptive titles that highlight opportunities to improve the experience of reading tabular or list data using assistive technology. */\n  a11yTablesListsVideoGroupDescription: \"These are opportunities to improve the experience of reading tabular or list data using assistive technology, like a screen reader.\",\n  /** Title of the Search Engine Optimization (SEO) category of audits. This is displayed at the top of a list of audits focused on topics related to optimizing a website for indexing by search engines. Also used as a label of a score gauge; try to limit to 20 characters. */\n  seoCategoryTitle: \"SEO\",\n  /** Description of the Search Engine Optimization (SEO) category. This is displayed at the top of a list of audits focused on optimizing a website for indexing by search engines. No character length limits. The last sentence starting with 'Learn' becomes link text to additional documentation. */\n  seoCategoryDescription: \"These checks ensure that your page is following basic search engine optimization advice. There are many additional factors Lighthouse does not score here that may affect your search ranking, including performance on [Core Web Vitals](https://web.dev/explore/vitals). [Learn more about Google Search Essentials](https://support.google.com/webmasters/answer/35769).\",\n  /** Description of the Search Engine Optimization (SEO) manual checks category, the additional validators must be run by hand in order to check all SEO best practices. This is displayed at the top of a list of manually run audits focused on optimizing a website for indexing by search engines. No character length limits. */\n  seoCategoryManualDescription: \"Run these additional validators on your site to check additional SEO best practices.\",\n  /** Title of the navigation section within the Search Engine Optimization (SEO) category. Within this section are audits with descriptive titles that highlight opportunities to make a page more usable on mobile devices. */\n  seoMobileGroupTitle: \"Mobile Friendly\",\n  /** Description of the navigation section within the Search Engine Optimization (SEO) category. Within this section are audits with descriptive titles that highlight opportunities to make a page more usable on mobile devices. */\n  seoMobileGroupDescription: \"Make sure your pages are mobile friendly so users don’t have to pinch or zoom in order to read the content pages. [Learn how to make pages mobile-friendly](https://developers.google.com/search/mobile-sites/).\",\n  /** Title of the navigation section within the Search Engine Optimization (SEO) category. Within this section are audits with descriptive titles that highlight ways to make a website content more easily understood by search engine crawler bots. */\n  seoContentGroupTitle: \"Content Best Practices\",\n  /** Description of the navigation section within the Search Engine Optimization (SEO) category. Within this section are audits with descriptive titles that highlight ways to make a website content more easily understood by search engine crawler bots. */\n  seoContentGroupDescription: \"Format your HTML in a way that enables crawlers to better understand your app’s content.\",\n  /** Title of the navigation section within the Search Engine Optimization (SEO) category. Within this section are audits with descriptive titles that highlight ways to make a website accessible to search engine crawlers. */\n  seoCrawlingGroupTitle: \"Crawling and Indexing\",\n  /** Description of the navigation section within the Search Engine Optimization (SEO) category. Within this section are audits with descriptive titles that highlight ways to make a website accessible to search engine crawlers. */\n  seoCrawlingGroupDescription: \"To appear in search results, crawlers need access to your app.\",\n  /** Title of the Best Practices category of audits. This is displayed at the top of a list of audits focused on topics related to following web development best practices and accepted guidelines. Also used as a label of a score gauge; try to limit to 20 characters. */\n  bestPracticesCategoryTitle: \"Best Practices\",\n  /** Title of the Trust & Safety group of audits. This is displayed at the top of a list of audits focused on maintaining user trust and protecting security in web development. */\n  bestPracticesTrustSafetyGroupTitle: \"Trust and Safety\",\n  /** Title of the User Experience group of the Best Practices category. Within this section are the audits related to the end user's experience of the webpage. */\n  bestPracticesUXGroupTitle: \"User Experience\",\n  /** Title of the Browser Compatibility group of the Best Practices category. Within this section are the audits related to whether the page is interpreted consistently by browsers. */\n  bestPracticesBrowserCompatGroupTitle: \"Browser Compatibility\",\n  /** Title of the General group of the Best Practices category. Within this section are the audits that don't belong to a specific group but are of general interest. */\n  bestPracticesGeneralGroupTitle: \"General\"\n};\nvar str_2 = createIcuMessageFn({ url: \"core/config/default-config.js\" }.url, UIStrings21);\nvar defaultConfig = {\n  settings: defaultSettings,\n  artifacts: [\n    // Artifacts which can be depended on come first.\n    { id: \"DevtoolsLog\", gatherer: \"devtools-log\" },\n    { id: \"Trace\", gatherer: \"trace\" },\n    { id: \"Accessibility\", gatherer: \"accessibility\" },\n    { id: \"AnchorElements\", gatherer: \"anchor-elements\" },\n    { id: \"ConsoleMessages\", gatherer: \"console-messages\" },\n    { id: \"CSSUsage\", gatherer: \"css-usage\" },\n    { id: \"Doctype\", gatherer: \"dobetterweb/doctype\" },\n    { id: \"Inputs\", gatherer: \"inputs\" },\n    { id: \"IFrameElements\", gatherer: \"iframe-elements\" },\n    { id: \"ImageElements\", gatherer: \"image-elements\" },\n    { id: \"InspectorIssues\", gatherer: \"inspector-issues\" },\n    { id: \"JsUsage\", gatherer: \"js-usage\" },\n    { id: \"LinkElements\", gatherer: \"link-elements\" },\n    { id: \"MainDocumentContent\", gatherer: \"main-document-content\" },\n    { id: \"MetaElements\", gatherer: \"meta-elements\" },\n    { id: \"NetworkUserAgent\", gatherer: \"network-user-agent\" },\n    { id: \"RobotsTxt\", gatherer: \"seo/robots-txt\" },\n    { id: \"Scripts\", gatherer: \"scripts\" },\n    { id: \"SourceMaps\", gatherer: \"source-maps\" },\n    { id: \"Stacks\", gatherer: \"stacks\" },\n    { id: \"Stylesheets\", gatherer: \"stylesheets\" },\n    { id: \"TraceElements\", gatherer: \"trace-elements\" },\n    { id: \"ViewportDimensions\", gatherer: \"viewport-dimensions\" },\n    // FullPageScreenshot comes at the end so all other node analysis is captured.\n    { id: \"FullPageScreenshot\", gatherer: \"full-page-screenshot\" },\n    // BFCacheFailures comes at the very end because it can perform a page navigation.\n    { id: \"BFCacheFailures\", gatherer: \"bf-cache-failures\" }\n  ],\n  audits: [\n    \"is-on-https\",\n    \"redirects-http\",\n    \"metrics/first-contentful-paint\",\n    \"metrics/largest-contentful-paint\",\n    \"metrics/speed-index\",\n    \"screenshot-thumbnails\",\n    \"final-screenshot\",\n    \"metrics/total-blocking-time\",\n    \"metrics/max-potential-fid\",\n    \"metrics/cumulative-layout-shift\",\n    \"metrics/interaction-to-next-paint\",\n    \"errors-in-console\",\n    \"server-response-time\",\n    \"metrics/interactive\",\n    \"user-timings\",\n    \"redirects\",\n    \"image-aspect-ratio\",\n    \"image-size-responsive\",\n    \"deprecations\",\n    \"third-party-cookies\",\n    \"mainthread-work-breakdown\",\n    \"bootup-time\",\n    \"diagnostics\",\n    \"network-requests\",\n    \"network-rtt\",\n    \"network-server-latency\",\n    \"main-thread-tasks\",\n    \"metrics\",\n    \"resource-summary\",\n    \"layout-shifts\",\n    \"long-tasks\",\n    \"non-composited-animations\",\n    \"unsized-images\",\n    \"valid-source-maps\",\n    \"csp-xss\",\n    \"has-hsts\",\n    \"origin-isolation\",\n    \"clickjacking-mitigation\",\n    \"trusted-types-xss\",\n    \"script-treemap-data\",\n    \"accessibility/accesskeys\",\n    \"accessibility/aria-allowed-attr\",\n    \"accessibility/aria-allowed-role\",\n    \"accessibility/aria-command-name\",\n    \"accessibility/aria-conditional-attr\",\n    \"accessibility/aria-deprecated-role\",\n    \"accessibility/aria-dialog-name\",\n    \"accessibility/aria-hidden-body\",\n    \"accessibility/aria-hidden-focus\",\n    \"accessibility/aria-input-field-name\",\n    \"accessibility/aria-meter-name\",\n    \"accessibility/aria-progressbar-name\",\n    \"accessibility/aria-prohibited-attr\",\n    \"accessibility/aria-required-attr\",\n    \"accessibility/aria-required-children\",\n    \"accessibility/aria-required-parent\",\n    \"accessibility/aria-roles\",\n    \"accessibility/aria-text\",\n    \"accessibility/aria-toggle-field-name\",\n    \"accessibility/aria-tooltip-name\",\n    \"accessibility/aria-treeitem-name\",\n    \"accessibility/aria-valid-attr-value\",\n    \"accessibility/aria-valid-attr\",\n    \"accessibility/button-name\",\n    \"accessibility/bypass\",\n    \"accessibility/color-contrast\",\n    \"accessibility/definition-list\",\n    \"accessibility/dlitem\",\n    \"accessibility/document-title\",\n    \"accessibility/duplicate-id-aria\",\n    \"accessibility/empty-heading\",\n    \"accessibility/form-field-multiple-labels\",\n    \"accessibility/frame-title\",\n    \"accessibility/heading-order\",\n    \"accessibility/html-has-lang\",\n    \"accessibility/html-lang-valid\",\n    \"accessibility/html-xml-lang-mismatch\",\n    \"accessibility/identical-links-same-purpose\",\n    \"accessibility/image-alt\",\n    \"accessibility/image-redundant-alt\",\n    \"accessibility/input-button-name\",\n    \"accessibility/input-image-alt\",\n    \"accessibility/label-content-name-mismatch\",\n    \"accessibility/label\",\n    \"accessibility/landmark-one-main\",\n    \"accessibility/link-name\",\n    \"accessibility/link-in-text-block\",\n    \"accessibility/list\",\n    \"accessibility/listitem\",\n    \"accessibility/meta-refresh\",\n    \"accessibility/meta-viewport\",\n    \"accessibility/object-alt\",\n    \"accessibility/select-name\",\n    \"accessibility/skip-link\",\n    \"accessibility/tabindex\",\n    \"accessibility/table-duplicate-name\",\n    \"accessibility/table-fake-caption\",\n    \"accessibility/target-size\",\n    \"accessibility/td-has-header\",\n    \"accessibility/td-headers-attr\",\n    \"accessibility/th-has-data-cells\",\n    \"accessibility/valid-lang\",\n    \"accessibility/video-caption\",\n    \"accessibility/manual/custom-controls-labels\",\n    \"accessibility/manual/custom-controls-roles\",\n    \"accessibility/manual/focus-traps\",\n    \"accessibility/manual/focusable-controls\",\n    \"accessibility/manual/interactive-element-affordance\",\n    \"accessibility/manual/logical-tab-order\",\n    \"accessibility/manual/managed-focus\",\n    \"accessibility/manual/offscreen-content-hidden\",\n    \"accessibility/manual/use-landmarks\",\n    \"accessibility/manual/visual-order-follows-dom\",\n    \"byte-efficiency/total-byte-weight\",\n    \"byte-efficiency/unminified-css\",\n    \"byte-efficiency/unminified-javascript\",\n    \"byte-efficiency/unused-css-rules\",\n    \"byte-efficiency/unused-javascript\",\n    \"dobetterweb/doctype\",\n    \"dobetterweb/charset\",\n    \"dobetterweb/geolocation-on-start\",\n    \"dobetterweb/inspector-issues\",\n    \"dobetterweb/js-libraries\",\n    \"dobetterweb/notification-on-start\",\n    \"dobetterweb/paste-preventing-inputs\",\n    \"seo/meta-description\",\n    \"seo/http-status-code\",\n    \"seo/link-text\",\n    \"seo/crawlable-anchors\",\n    \"seo/is-crawlable\",\n    \"seo/robots-txt\",\n    \"seo/hreflang\",\n    \"seo/canonical\",\n    \"seo/manual/structured-data\",\n    \"bf-cache\",\n    \"insights/cache-insight\",\n    \"insights/cls-culprits-insight\",\n    \"insights/document-latency-insight\",\n    \"insights/dom-size-insight\",\n    \"insights/duplicated-javascript-insight\",\n    \"insights/font-display-insight\",\n    \"insights/forced-reflow-insight\",\n    \"insights/image-delivery-insight\",\n    \"insights/inp-breakdown-insight\",\n    \"insights/lcp-breakdown-insight\",\n    \"insights/lcp-discovery-insight\",\n    \"insights/legacy-javascript-insight\",\n    \"insights/modern-http-insight\",\n    \"insights/network-dependency-tree-insight\",\n    \"insights/render-blocking-insight\",\n    \"insights/third-parties-insight\",\n    \"insights/viewport-insight\"\n  ],\n  groups: {\n    \"metrics\": {\n      title: str_2(UIStrings21.metricGroupTitle)\n    },\n    \"insights\": {\n      title: str_2(UIStrings21.insightsGroupTitle),\n      description: str_2(UIStrings21.insightsGroupDescription)\n    },\n    \"diagnostics\": {\n      title: str_2(UIStrings21.diagnosticsGroupTitle),\n      description: str_2(UIStrings21.diagnosticsGroupDescription)\n    },\n    \"a11y-best-practices\": {\n      title: str_2(UIStrings21.a11yBestPracticesGroupTitle),\n      description: str_2(UIStrings21.a11yBestPracticesGroupDescription)\n    },\n    \"a11y-color-contrast\": {\n      title: str_2(UIStrings21.a11yColorContrastGroupTitle),\n      description: str_2(UIStrings21.a11yColorContrastGroupDescription)\n    },\n    \"a11y-names-labels\": {\n      title: str_2(UIStrings21.a11yNamesLabelsGroupTitle),\n      description: str_2(UIStrings21.a11yNamesLabelsGroupDescription)\n    },\n    \"a11y-navigation\": {\n      title: str_2(UIStrings21.a11yNavigationGroupTitle),\n      description: str_2(UIStrings21.a11yNavigationGroupDescription)\n    },\n    \"a11y-aria\": {\n      title: str_2(UIStrings21.a11yAriaGroupTitle),\n      description: str_2(UIStrings21.a11yAriaGroupDescription)\n    },\n    \"a11y-language\": {\n      title: str_2(UIStrings21.a11yLanguageGroupTitle),\n      description: str_2(UIStrings21.a11yLanguageGroupDescription)\n    },\n    \"a11y-audio-video\": {\n      title: str_2(UIStrings21.a11yAudioVideoGroupTitle),\n      description: str_2(UIStrings21.a11yAudioVideoGroupDescription)\n    },\n    \"a11y-tables-lists\": {\n      title: str_2(UIStrings21.a11yTablesListsVideoGroupTitle),\n      description: str_2(UIStrings21.a11yTablesListsVideoGroupDescription)\n    },\n    \"seo-mobile\": {\n      title: str_2(UIStrings21.seoMobileGroupTitle),\n      description: str_2(UIStrings21.seoMobileGroupDescription)\n    },\n    \"seo-content\": {\n      title: str_2(UIStrings21.seoContentGroupTitle),\n      description: str_2(UIStrings21.seoContentGroupDescription)\n    },\n    \"seo-crawl\": {\n      title: str_2(UIStrings21.seoCrawlingGroupTitle),\n      description: str_2(UIStrings21.seoCrawlingGroupDescription)\n    },\n    \"best-practices-trust-safety\": {\n      title: str_2(UIStrings21.bestPracticesTrustSafetyGroupTitle)\n    },\n    \"best-practices-ux\": {\n      title: str_2(UIStrings21.bestPracticesUXGroupTitle)\n    },\n    \"best-practices-browser-compat\": {\n      title: str_2(UIStrings21.bestPracticesBrowserCompatGroupTitle)\n    },\n    \"best-practices-general\": {\n      title: str_2(UIStrings21.bestPracticesGeneralGroupTitle)\n    },\n    // Group for audits that should not be displayed.\n    \"hidden\": { title: \"\" }\n  },\n  categories: {\n    \"performance\": {\n      title: str_2(UIStrings21.performanceCategoryTitle),\n      supportedModes: [\"navigation\", \"timespan\", \"snapshot\"],\n      auditRefs: [\n        { id: \"first-contentful-paint\", weight: 10, group: \"metrics\", acronym: \"FCP\" },\n        { id: \"largest-contentful-paint\", weight: 25, group: \"metrics\", acronym: \"LCP\" },\n        { id: \"total-blocking-time\", weight: 30, group: \"metrics\", acronym: \"TBT\" },\n        { id: \"cumulative-layout-shift\", weight: 25, group: \"metrics\", acronym: \"CLS\" },\n        { id: \"speed-index\", weight: 10, group: \"metrics\", acronym: \"SI\" },\n        { id: \"interaction-to-next-paint\", weight: 0, group: \"metrics\", acronym: \"INP\" },\n        // Insight audits.\n        { id: \"cache-insight\", weight: 0, group: \"insights\" },\n        { id: \"cls-culprits-insight\", weight: 0, group: \"insights\" },\n        { id: \"document-latency-insight\", weight: 0, group: \"insights\" },\n        { id: \"dom-size-insight\", weight: 0, group: \"insights\" },\n        { id: \"duplicated-javascript-insight\", weight: 0, group: \"insights\" },\n        { id: \"font-display-insight\", weight: 0, group: \"insights\" },\n        { id: \"forced-reflow-insight\", weight: 0, group: \"insights\" },\n        { id: \"image-delivery-insight\", weight: 0, group: \"insights\" },\n        { id: \"inp-breakdown-insight\", weight: 0, group: \"insights\" },\n        { id: \"lcp-breakdown-insight\", weight: 0, group: \"insights\" },\n        { id: \"lcp-discovery-insight\", weight: 0, group: \"insights\" },\n        { id: \"legacy-javascript-insight\", weight: 0, group: \"insights\" },\n        { id: \"modern-http-insight\", weight: 0, group: \"insights\" },\n        { id: \"network-dependency-tree-insight\", weight: 0, group: \"insights\" },\n        { id: \"render-blocking-insight\", weight: 0, group: \"insights\" },\n        { id: \"third-parties-insight\", weight: 0, group: \"insights\" },\n        { id: \"viewport-insight\", weight: 0, group: \"insights\" },\n        // These are our \"invisible\" metrics. Not displayed, but still in the LHR.\n        { id: \"interactive\", weight: 0, group: \"hidden\", acronym: \"TTI\" },\n        { id: \"max-potential-fid\", weight: 0, group: \"hidden\" },\n        { id: \"unminified-css\", weight: 0, group: \"diagnostics\" },\n        { id: \"unminified-javascript\", weight: 0, group: \"diagnostics\" },\n        { id: \"unused-css-rules\", weight: 0, group: \"diagnostics\" },\n        { id: \"unused-javascript\", weight: 0, group: \"diagnostics\" },\n        { id: \"total-byte-weight\", weight: 0, group: \"diagnostics\" },\n        { id: \"user-timings\", weight: 0, group: \"diagnostics\" },\n        { id: \"bootup-time\", weight: 0, group: \"diagnostics\" },\n        { id: \"mainthread-work-breakdown\", weight: 0, group: \"diagnostics\" },\n        { id: \"long-tasks\", weight: 0, group: \"diagnostics\" },\n        { id: \"non-composited-animations\", weight: 0, group: \"diagnostics\" },\n        { id: \"unsized-images\", weight: 0, group: \"diagnostics\" },\n        { id: \"bf-cache\", weight: 0, group: \"diagnostics\" },\n        // Audits past this point contain useful data but are not displayed with other audits.\n        { id: \"network-requests\", weight: 0, group: \"hidden\" },\n        { id: \"network-rtt\", weight: 0, group: \"hidden\" },\n        { id: \"network-server-latency\", weight: 0, group: \"hidden\" },\n        { id: \"main-thread-tasks\", weight: 0, group: \"hidden\" },\n        { id: \"diagnostics\", weight: 0, group: \"hidden\" },\n        { id: \"metrics\", weight: 0, group: \"hidden\" },\n        { id: \"screenshot-thumbnails\", weight: 0, group: \"hidden\" },\n        { id: \"final-screenshot\", weight: 0, group: \"hidden\" },\n        { id: \"script-treemap-data\", weight: 0, group: \"hidden\" },\n        { id: \"resource-summary\", weight: 0, group: \"hidden\" },\n        { id: \"redirects\", weight: 0, group: \"hidden\" },\n        { id: \"server-response-time\", weight: 0, group: \"hidden\" },\n        { id: \"layout-shifts\", weight: 0, group: \"hidden\" }\n      ]\n    },\n    \"accessibility\": {\n      title: str_2(UIStrings21.a11yCategoryTitle),\n      description: str_2(UIStrings21.a11yCategoryDescription),\n      manualDescription: str_2(UIStrings21.a11yCategoryManualDescription),\n      supportedModes: [\"navigation\", \"snapshot\"],\n      // Audit weights weights are derived from the axe-core \"Impact\",\n      // with adjustments based on axe-core \"Tags\":\n      //\n      // ┌────────────┬───────────────────────────────────────────────┐\n      // │ Impact     │ Weight Based on Tags                          │\n      // │            ├──────────────┬─────────────────┬──────────────┤\n      // │            │  wcag A+AA   │  best-practice  │ experimental │\n      // │            │ (ex: wcag2aa)│ (w/o wcag tag)  │              │\n      // ├────────────┼──────────────┼─────────────────┼──────────────┤\n      // │ Minor      │       1      │        0        │      0       │\n      // │ Moderate   │       3      │        3        │      0       │\n      // │ Serious    │       7      │        7        │      0       │\n      // │ Critical   │      10      │       10        │      0       │\n      // └────────────┴──────────────┴─────────────────┴──────────────┘\n      //\n      // Notes:\n      //  • Experimental rules always have weight 0\n      //  • Best practice rules only affect scores when tagged with wcagA+AA\n      //    and are moderate, serious, or critical.\n      //\n      // To find the latest axe-core Impact and Tag values:\n      //   1. Browse to https://dequeuniversity.com/rules/axe/html.\n      //   2. Click on the latest rule set (ex: https://dequeuniversity.com/rules/axe/html/4.10)\n      //   3. Review the tables\n      auditRefs: [\n        { id: \"accesskeys\", weight: 7, group: \"a11y-navigation\" },\n        // Serious, best-practice\n        { id: \"aria-allowed-attr\", weight: 10, group: \"a11y-aria\" },\n        // Critical, wcag2a\n        { id: \"aria-command-name\", weight: 7, group: \"a11y-aria\" },\n        // Serious, wcag2a\n        { id: \"aria-conditional-attr\", weight: 7, group: \"a11y-aria\" },\n        // Serious, wcag2a\n        { id: \"aria-deprecated-role\", weight: 1, group: \"a11y-aria\" },\n        // Minor, wcag2a\n        { id: \"aria-dialog-name\", weight: 7, group: \"a11y-aria\" },\n        // Serious, best-practice\n        { id: \"aria-hidden-body\", weight: 10, group: \"a11y-aria\" },\n        // Critical, wcag2a\n        { id: \"aria-hidden-focus\", weight: 7, group: \"a11y-aria\" },\n        // Serious, wcag2a\n        { id: \"aria-input-field-name\", weight: 7, group: \"a11y-aria\" },\n        // Serious, wcag2a\n        { id: \"aria-meter-name\", weight: 7, group: \"a11y-aria\" },\n        // Serious, wcag2a\n        { id: \"aria-progressbar-name\", weight: 7, group: \"a11y-aria\" },\n        // Serious, wcag2a\n        { id: \"aria-prohibited-attr\", weight: 7, group: \"a11y-aria\" },\n        // Serious, wcag2a\n        { id: \"aria-required-attr\", weight: 10, group: \"a11y-aria\" },\n        // Critical, wcag2a\n        { id: \"aria-required-children\", weight: 10, group: \"a11y-aria\" },\n        // Critical, wcag2a\n        { id: \"aria-required-parent\", weight: 10, group: \"a11y-aria\" },\n        // Critical, wcag2a\n        { id: \"aria-roles\", weight: 10, group: \"a11y-aria\" },\n        // Critical, wcag2a\n        { id: \"aria-text\", weight: 7, group: \"a11y-aria\" },\n        // Serious, best-practice\n        { id: \"aria-toggle-field-name\", weight: 7, group: \"a11y-aria\" },\n        // Serious, wcag2a\n        { id: \"aria-tooltip-name\", weight: 7, group: \"a11y-aria\" },\n        // Serious, wcag2a\n        { id: \"aria-treeitem-name\", weight: 7, group: \"a11y-aria\" },\n        // Serious, best-practice\n        { id: \"aria-valid-attr-value\", weight: 10, group: \"a11y-aria\" },\n        // Critical, wcag2a\n        { id: \"aria-valid-attr\", weight: 10, group: \"a11y-aria\" },\n        // Critical, wcag2a\n        { id: \"button-name\", weight: 10, group: \"a11y-names-labels\" },\n        // Critical, wcag2a\n        { id: \"bypass\", weight: 7, group: \"a11y-navigation\" },\n        // Serious, wcag2a\n        { id: \"color-contrast\", weight: 7, group: \"a11y-color-contrast\" },\n        // Serious, wcag2aa\n        { id: \"definition-list\", weight: 7, group: \"a11y-tables-lists\" },\n        // Serious, wcag2a\n        { id: \"dlitem\", weight: 7, group: \"a11y-tables-lists\" },\n        // Serious, wcag2a\n        { id: \"document-title\", weight: 7, group: \"a11y-names-labels\" },\n        // Serious, wcag2a\n        { id: \"duplicate-id-aria\", weight: 10, group: \"a11y-aria\" },\n        // Critical, wcag2a\n        { id: \"form-field-multiple-labels\", weight: 3, group: \"a11y-names-labels\" },\n        // Moderate, wcag2a\n        { id: \"frame-title\", weight: 7, group: \"a11y-names-labels\" },\n        // Serious, wcag2a\n        { id: \"heading-order\", weight: 3, group: \"a11y-navigation\" },\n        // Moderate, best-practice\n        { id: \"html-has-lang\", weight: 7, group: \"a11y-language\" },\n        // Serious, wcag2a\n        { id: \"html-lang-valid\", weight: 7, group: \"a11y-language\" },\n        // Serious, wcag2a\n        { id: \"html-xml-lang-mismatch\", weight: 3, group: \"a11y-language\" },\n        // Moderate, wcag2a\n        { id: \"image-alt\", weight: 10, group: \"a11y-names-labels\" },\n        // Critical, wcag2a\n        { id: \"input-button-name\", weight: 10, group: \"a11y-names-labels\" },\n        // Critical, wcag2a\n        { id: \"input-image-alt\", weight: 10, group: \"a11y-names-labels\" },\n        // Critical, wcag2a\n        { id: \"label\", weight: 10, group: \"a11y-names-labels\" },\n        // Critical, wcag2a\n        { id: \"link-in-text-block\", weight: 7, group: \"a11y-color-contrast\" },\n        // Serious, wcag2a\n        { id: \"link-name\", weight: 7, group: \"a11y-names-labels\" },\n        // Serious, wcag2a\n        { id: \"list\", weight: 7, group: \"a11y-tables-lists\" },\n        // Serious, wcag2a\n        { id: \"listitem\", weight: 7, group: \"a11y-tables-lists\" },\n        // Serious, wcag2a\n        { id: \"meta-refresh\", weight: 10, group: \"a11y-best-practices\" },\n        // Critical, wcag2a\n        { id: \"meta-viewport\", weight: 10, group: \"a11y-best-practices\" },\n        // Critical, wcag2aa\n        { id: \"object-alt\", weight: 7, group: \"a11y-names-labels\" },\n        // Serious, wcag2a\n        { id: \"select-name\", weight: 10, group: \"a11y-names-labels\" },\n        // Critical, wcag2a\n        { id: \"skip-link\", weight: 3, group: \"a11y-names-labels\" },\n        // Moderate, best-practice\n        { id: \"tabindex\", weight: 7, group: \"a11y-navigation\" },\n        // Serious, best-practice\n        { id: \"target-size\", weight: 7, group: \"a11y-best-practices\" },\n        // Serious, wcag22aa\n        { id: \"td-headers-attr\", weight: 7, group: \"a11y-tables-lists\" },\n        // Serious, wcag2a\n        { id: \"th-has-data-cells\", weight: 7, group: \"a11y-tables-lists\" },\n        // Serious, wcag2a\n        { id: \"valid-lang\", weight: 7, group: \"a11y-language\" },\n        // Serious, wcag2aa\n        { id: \"video-caption\", weight: 10, group: \"a11y-audio-video\" },\n        // Critical, wcag2a\n        { id: \"landmark-one-main\", weight: 3, group: \"a11y-best-practices\" },\n        // Moderate, best-practice\n        // Manual audits\n        { id: \"focusable-controls\", weight: 0 },\n        { id: \"interactive-element-affordance\", weight: 0 },\n        { id: \"logical-tab-order\", weight: 0 },\n        { id: \"visual-order-follows-dom\", weight: 0 },\n        { id: \"focus-traps\", weight: 0 },\n        { id: \"managed-focus\", weight: 0 },\n        { id: \"use-landmarks\", weight: 0 },\n        { id: \"offscreen-content-hidden\", weight: 0 },\n        { id: \"custom-controls-labels\", weight: 0 },\n        { id: \"custom-controls-roles\", weight: 0 },\n        // Low-impact best-practices\n        { id: \"table-duplicate-name\", weight: 0, group: \"a11y-best-practices\" },\n        // Minor, best-practice\n        { id: \"empty-heading\", weight: 0, group: \"a11y-best-practices\" },\n        // Minor, best-practice\n        { id: \"aria-allowed-role\", weight: 0, group: \"a11y-best-practices\" },\n        // Minor, best-practice\n        { id: \"image-redundant-alt\", weight: 0, group: \"a11y-names-labels\" },\n        // Minor, best-practice\n        // WCAG AAA\n        { id: \"identical-links-same-purpose\", weight: 0, group: \"a11y-best-practices\" },\n        // Minor, wcag2aaa\n        // Hidden audits (ie. experimental)\n        { id: \"label-content-name-mismatch\", weight: 0, group: \"hidden\" },\n        // Serious, experimental\n        { id: \"table-fake-caption\", weight: 0, group: \"hidden\" },\n        // Serious, experimental\n        { id: \"td-has-header\", weight: 0, group: \"hidden\" }\n        // Critical, experimental\n      ]\n    },\n    \"best-practices\": {\n      title: str_2(UIStrings21.bestPracticesCategoryTitle),\n      supportedModes: [\"navigation\", \"timespan\", \"snapshot\"],\n      auditRefs: [\n        // Trust & Safety\n        { id: \"is-on-https\", weight: 5, group: \"best-practices-trust-safety\" },\n        { id: \"redirects-http\", weight: 1, group: \"best-practices-trust-safety\" },\n        { id: \"geolocation-on-start\", weight: 1, group: \"best-practices-trust-safety\" },\n        { id: \"notification-on-start\", weight: 1, group: \"best-practices-trust-safety\" },\n        { id: \"csp-xss\", weight: 0, group: \"best-practices-trust-safety\" },\n        { id: \"has-hsts\", weight: 0, group: \"best-practices-trust-safety\" },\n        { id: \"origin-isolation\", weight: 0, group: \"best-practices-trust-safety\" },\n        { id: \"clickjacking-mitigation\", weight: 0, group: \"best-practices-trust-safety\" },\n        { id: \"trusted-types-xss\", weight: 0, group: \"best-practices-trust-safety\" },\n        // User Experience\n        { id: \"paste-preventing-inputs\", weight: 3, group: \"best-practices-ux\" },\n        { id: \"image-aspect-ratio\", weight: 1, group: \"best-practices-ux\" },\n        { id: \"image-size-responsive\", weight: 1, group: \"best-practices-ux\" },\n        // Browser Compatibility\n        { id: \"doctype\", weight: 1, group: \"best-practices-browser-compat\" },\n        { id: \"charset\", weight: 1, group: \"best-practices-browser-compat\" },\n        // General Group\n        { id: \"js-libraries\", weight: 0, group: \"best-practices-general\" },\n        { id: \"deprecations\", weight: 5, group: \"best-practices-general\" },\n        { id: \"third-party-cookies\", weight: 5, group: \"best-practices-general\" },\n        { id: \"errors-in-console\", weight: 1, group: \"best-practices-general\" },\n        { id: \"valid-source-maps\", weight: 0, group: \"best-practices-general\" },\n        { id: \"inspector-issues\", weight: 1, group: \"best-practices-general\" }\n      ]\n    },\n    \"seo\": {\n      title: str_2(UIStrings21.seoCategoryTitle),\n      description: str_2(UIStrings21.seoCategoryDescription),\n      manualDescription: str_2(UIStrings21.seoCategoryManualDescription),\n      supportedModes: [\"navigation\", \"snapshot\"],\n      auditRefs: [\n        // Should be at least 31% of the score, such that this audit failing\n        // results in the SEO category failing.\n        // Solve for w:\n        //    w / (w + T) >= 0.31\n        // where T is the sum of all the other weights.\n        { id: \"is-crawlable\", weight: 93 / 23, group: \"seo-crawl\" },\n        { id: \"document-title\", weight: 1, group: \"seo-content\" },\n        { id: \"meta-description\", weight: 1, group: \"seo-content\" },\n        { id: \"http-status-code\", weight: 1, group: \"seo-crawl\" },\n        { id: \"link-text\", weight: 1, group: \"seo-content\" },\n        { id: \"crawlable-anchors\", weight: 1, group: \"seo-crawl\" },\n        { id: \"robots-txt\", weight: 1, group: \"seo-crawl\" },\n        { id: \"image-alt\", weight: 1, group: \"seo-content\" },\n        { id: \"hreflang\", weight: 1, group: \"seo-content\" },\n        { id: \"canonical\", weight: 1, group: \"seo-content\" },\n        // Manual audits\n        { id: \"structured-data\", weight: 0 }\n      ]\n    }\n  }\n};\nObject.defineProperty(defaultConfig, \"UIStrings\", {\n  enumerable: false,\n  get: /* @__PURE__ */ __name(() => UIStrings21, \"get\")\n});\nvar default_config_default = defaultConfig;\n\n// core/config/validation.js\ninit_process_global();\ninit_audit();\ninit_base_gatherer();\ninit_i18n();\n/**\n * @license\n * Copyright 2021 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\nfunction isValidArtifactDependency(dependent, dependency) {\n  const levels = { timespan: 0, snapshot: 1, navigation: 2 };\n  const dependentLevel = Math.min(...dependent.instance.meta.supportedModes.map((l) => levels[l]));\n  const dependencyLevel = Math.min(...dependency.instance.meta.supportedModes.map((l) => levels[l]));\n  if (dependentLevel === levels.timespan) return dependencyLevel === levels.timespan;\n  if (dependentLevel === levels.snapshot) return dependencyLevel === levels.snapshot;\n  return true;\n}\n__name(isValidArtifactDependency, \"isValidArtifactDependency\");\nfunction assertValidPluginName(config3, pluginName) {\n  const parts = pluginName.split(\"/\");\n  if (parts.length === 2) {\n    pluginName = parts[1];\n  }\n  if (!pluginName.startsWith(\"lighthouse-plugin-\")) {\n    throw new Error(`plugin name '${pluginName}' does not start with 'lighthouse-plugin-'`);\n  }\n  if (config3.categories?.[pluginName]) {\n    throw new Error(`plugin name '${pluginName}' not allowed because it is the id of a category already found in config`);\n  }\n}\n__name(assertValidPluginName, \"assertValidPluginName\");\nfunction assertValidArtifact(artifactDefn) {\n  const gatherer = artifactDefn.gatherer.instance;\n  if (typeof gatherer.meta !== \"object\") {\n    throw new Error(`Gatherer for ${artifactDefn.id} did not provide a meta object.`);\n  }\n  if (gatherer.meta.supportedModes.length === 0) {\n    throw new Error(`Gatherer for ${artifactDefn.id} did not support any gather modes.`);\n  }\n  if (typeof gatherer.getArtifact !== \"function\" || gatherer.getArtifact === base_gatherer_default.prototype.getArtifact) {\n    throw new Error(`Gatherer for ${artifactDefn.id} did not define a \"getArtifact\" method.`);\n  }\n}\n__name(assertValidArtifact, \"assertValidArtifact\");\nfunction assertValidAudit(auditDefinition) {\n  const { implementation, path: auditPath } = auditDefinition;\n  const auditName = auditPath || implementation?.meta?.id || \"Unknown audit\";\n  if (typeof implementation.audit !== \"function\" || implementation.audit === Audit.audit) {\n    throw new Error(`${auditName} has no audit() method.`);\n  }\n  if (typeof implementation.meta.id !== \"string\") {\n    throw new Error(`${auditName} has no meta.id property, or the property is not a string.`);\n  }\n  if (!isStringOrIcuMessage(implementation.meta.title)) {\n    throw new Error(`${auditName} has no meta.title property, or the property is not a string.`);\n  }\n  const scoreDisplayMode = implementation.meta.scoreDisplayMode || Audit.SCORING_MODES.BINARY;\n  if (!isStringOrIcuMessage(implementation.meta.failureTitle) && scoreDisplayMode === Audit.SCORING_MODES.BINARY) {\n    throw new Error(`${auditName} has no meta.failureTitle and should.`);\n  }\n  if (!isStringOrIcuMessage(implementation.meta.description)) {\n    throw new Error(\n      `${auditName} has no meta.description property, or the property is not a string.`\n    );\n  } else if (implementation.meta.description === \"\") {\n    throw new Error(\n      `${auditName} has an empty meta.description string. Please add a description for the UI.`\n    );\n  }\n  if (!Array.isArray(implementation.meta.requiredArtifacts)) {\n    throw new Error(\n      `${auditName} has no meta.requiredArtifacts property, or the property is not an array.`\n    );\n  }\n}\n__name(assertValidAudit, \"assertValidAudit\");\nfunction assertValidCategories(categories, audits, groups) {\n  if (!categories) {\n    return;\n  }\n  const auditsKeyedById = new Map((audits || []).map((audit) => {\n    return [audit.implementation.meta.id, audit];\n  }));\n  Object.keys(categories).forEach((categoryId) => {\n    categories[categoryId].auditRefs.forEach((auditRef, index) => {\n      if (!auditRef.id) {\n        throw new Error(`missing an audit id at ${categoryId}[${index}]`);\n      }\n      const audit = auditsKeyedById.get(auditRef.id);\n      if (!audit) {\n        throw new Error(`could not find ${auditRef.id} audit for category ${categoryId}`);\n      }\n      const auditImpl = audit.implementation;\n      const isManual = auditImpl.meta.scoreDisplayMode === \"manual\";\n      if (categoryId === \"accessibility\" && !auditRef.group && !isManual) {\n        throw new Error(`${auditRef.id} accessibility audit does not have a group`);\n      }\n      if (auditRef.weight > 0 && isManual) {\n        throw new Error(`${auditRef.id} is manual but has a positive weight`);\n      }\n      if (auditRef.group && (!groups || !groups[auditRef.group])) {\n        throw new Error(`${auditRef.id} references unknown group ${auditRef.group}`);\n      }\n    });\n  });\n}\n__name(assertValidCategories, \"assertValidCategories\");\nfunction assertValidSettings(settings) {\n  if (!settings.formFactor) {\n    throw new Error(`\\`settings.formFactor\\` must be defined as 'mobile' or 'desktop'. See https://github.com/GoogleChrome/lighthouse/blob/main/docs/emulation.md`);\n  }\n  if (!settings.screenEmulation.disabled) {\n    if (settings.screenEmulation.mobile !== (settings.formFactor === \"mobile\")) {\n      throw new Error(`Screen emulation mobile setting (${settings.screenEmulation.mobile}) does not match formFactor setting (${settings.formFactor}). See https://github.com/GoogleChrome/lighthouse/blob/main/docs/emulation.md`);\n    }\n  }\n  const skippedAndOnlyAuditId = settings.skipAudits?.find((auditId) => settings.onlyAudits?.includes(auditId));\n  if (skippedAndOnlyAuditId) {\n    throw new Error(`${skippedAndOnlyAuditId} appears in both skipAudits and onlyAudits`);\n  }\n}\n__name(assertValidSettings, \"assertValidSettings\");\nfunction assertValidArtifacts(artifactDefns) {\n  const availableArtifacts = /* @__PURE__ */ new Set();\n  for (const artifact of artifactDefns) {\n    assertValidArtifact(artifact);\n    if (availableArtifacts.has(artifact.id)) {\n      throw new Error(`Config defined multiple artifacts with id '${artifact.id}'`);\n    }\n    availableArtifacts.add(artifact.id);\n    if (!artifact.dependencies) continue;\n    for (const [dependencyKey, { id: dependencyId }] of Object.entries(artifact.dependencies)) {\n      if (availableArtifacts.has(dependencyId)) continue;\n      throwInvalidDependencyOrder(artifact.id, dependencyKey);\n    }\n  }\n}\n__name(assertValidArtifacts, \"assertValidArtifacts\");\nfunction assertValidConfig(resolvedConfig) {\n  assertValidArtifacts(resolvedConfig.artifacts || []);\n  for (const auditDefn of resolvedConfig.audits || []) {\n    assertValidAudit(auditDefn);\n  }\n  assertValidCategories(resolvedConfig.categories, resolvedConfig.audits, resolvedConfig.groups);\n  assertValidSettings(resolvedConfig.settings);\n}\n__name(assertValidConfig, \"assertValidConfig\");\nfunction throwInvalidDependencyOrder(artifactId, dependencyKey) {\n  throw new Error(\n    [\n      `Failed to find dependency \"${dependencyKey}\" for \"${artifactId}\" artifact`,\n      `Check that...`,\n      `  1. A gatherer exposes a matching Symbol that satisfies \"${dependencyKey}\".`,\n      `  2. \"${dependencyKey}\" is configured to run before \"${artifactId}\"`\n    ].join(\"\\n\")\n  );\n}\n__name(throwInvalidDependencyOrder, \"throwInvalidDependencyOrder\");\nfunction throwInvalidArtifactDependency(artifactId, dependencyKey) {\n  throw new Error(\n    [\n      `Dependency \"${dependencyKey}\" for \"${artifactId}\" artifact is invalid.`,\n      `The dependency must be collected before the dependent.`\n    ].join(\"\\n\")\n  );\n}\n__name(throwInvalidArtifactDependency, \"throwInvalidArtifactDependency\");\n\n// core/config/filters.js\ninit_process_global();\ninit_audit();\n/**\n * @license\n * Copyright 2021 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\nvar baseArtifactKeySource = {\n  fetchTime: \"\",\n  LighthouseRunWarnings: \"\",\n  BenchmarkIndex: \"\",\n  HostDPR: \"\",\n  settings: \"\",\n  Timing: \"\",\n  URL: \"\",\n  PageLoadError: \"\",\n  HostFormFactor: \"\",\n  HostUserAgent: \"\",\n  HostProduct: \"\",\n  GatherContext: \"\"\n};\nvar baseArtifactKeys = Object.keys(baseArtifactKeySource);\nvar filterResistantAuditIds = [];\nvar filterResistantArtifactIds = [\"Stacks\", \"NetworkUserAgent\", \"FullPageScreenshot\"];\nfunction getAuditIdsInCategories(allCategories, onlyCategories) {\n  if (!allCategories) return /* @__PURE__ */ new Set();\n  onlyCategories = onlyCategories || Object.keys(allCategories);\n  const categories = onlyCategories.map((categoryId) => allCategories[categoryId]);\n  const auditRefs = categories.flatMap((category) => category?.auditRefs || []);\n  return new Set(auditRefs.map((auditRef) => auditRef.id));\n}\n__name(getAuditIdsInCategories, \"getAuditIdsInCategories\");\nfunction filterArtifactsByAvailableAudits(artifacts, audits) {\n  if (!artifacts) return null;\n  if (!audits) return artifacts;\n  const artifactsById = new Map(artifacts.map((artifact) => [artifact.id, artifact]));\n  const artifactIdsToKeep = /* @__PURE__ */ new Set([\n    ...filterResistantArtifactIds,\n    ...audits.flatMap((audit) => audit.implementation.meta.requiredArtifacts)\n  ]);\n  let previousSize = 0;\n  while (previousSize !== artifactIdsToKeep.size) {\n    previousSize = artifactIdsToKeep.size;\n    for (const artifactId of artifactIdsToKeep) {\n      const artifact = artifactsById.get(artifactId);\n      if (!artifact) continue;\n      if (!artifact.dependencies) continue;\n      for (const dep of Object.values(artifact.dependencies)) {\n        artifactIdsToKeep.add(dep.id);\n      }\n    }\n  }\n  return artifacts.filter((artifact) => artifactIdsToKeep.has(artifact.id));\n}\n__name(filterArtifactsByAvailableAudits, \"filterArtifactsByAvailableAudits\");\nfunction filterArtifactsByGatherMode(artifacts, mode) {\n  if (!artifacts) return null;\n  return artifacts.filter((artifact) => {\n    return artifact.gatherer.instance.meta.supportedModes.includes(mode);\n  });\n}\n__name(filterArtifactsByGatherMode, \"filterArtifactsByGatherMode\");\nfunction filterAuditsByAvailableArtifacts(audits, availableArtifacts) {\n  if (!audits) return null;\n  const availableArtifactIds = new Set(\n    availableArtifacts.map((artifact) => artifact.id).concat(baseArtifactKeys)\n  );\n  return audits.filter((audit) => {\n    const meta = audit.implementation.meta;\n    return meta.requiredArtifacts.every((id) => availableArtifactIds.has(id));\n  });\n}\n__name(filterAuditsByAvailableArtifacts, \"filterAuditsByAvailableArtifacts\");\nfunction filterAuditsByGatherMode(audits, mode) {\n  if (!audits) return null;\n  return audits.filter((audit) => {\n    const meta = audit.implementation.meta;\n    return !meta.supportedModes || meta.supportedModes.includes(mode);\n  });\n}\n__name(filterAuditsByGatherMode, \"filterAuditsByGatherMode\");\nfunction filterCategoriesByGatherMode(categories, mode) {\n  if (!categories) return null;\n  const categoriesToKeep = Object.entries(categories).filter(([_, category]) => {\n    return !category.supportedModes || category.supportedModes.includes(mode);\n  });\n  return Object.fromEntries(categoriesToKeep);\n}\n__name(filterCategoriesByGatherMode, \"filterCategoriesByGatherMode\");\nfunction filterCategoriesByExplicitFilters(categories, onlyCategories) {\n  if (!categories || !onlyCategories) return categories;\n  const categoriesToKeep = Object.entries(categories).filter(([categoryId]) => onlyCategories.includes(categoryId));\n  return Object.fromEntries(categoriesToKeep);\n}\n__name(filterCategoriesByExplicitFilters, \"filterCategoriesByExplicitFilters\");\nfunction errorOnUnknownOnlyCategories(allCategories, onlyCategories) {\n  if (!onlyCategories) return;\n  const unknown = onlyCategories.filter((c) => !allCategories?.[c]);\n  if (unknown.length) {\n    throw new Error(`unrecognized category in 'onlyCategories': ${unknown.join(\", \")}`);\n  }\n}\n__name(errorOnUnknownOnlyCategories, \"errorOnUnknownOnlyCategories\");\nfunction filterCategoriesByAvailableAudits(categories, availableAudits) {\n  if (!categories) return categories;\n  const availableAuditIdToMeta = new Map(\n    availableAudits.map((audit) => [audit.implementation.meta.id, audit.implementation.meta])\n  );\n  const categoryEntries = Object.entries(categories).map(([categoryId, category]) => {\n    const filteredCategory = {\n      ...category,\n      auditRefs: category.auditRefs.filter((ref) => availableAuditIdToMeta.has(ref.id))\n    };\n    const didFilter = filteredCategory.auditRefs.length < category.auditRefs.length;\n    const hasOnlyManualAudits = filteredCategory.auditRefs.every((ref) => {\n      const meta = availableAuditIdToMeta.get(ref.id);\n      if (!meta) return false;\n      return meta.scoreDisplayMode === Audit.SCORING_MODES.MANUAL;\n    });\n    if (didFilter && hasOnlyManualAudits) filteredCategory.auditRefs = [];\n    return [categoryId, filteredCategory];\n  }).filter((entry) => typeof entry[1] === \"object\" && entry[1].auditRefs.length);\n  return Object.fromEntries(categoryEntries);\n}\n__name(filterCategoriesByAvailableAudits, \"filterCategoriesByAvailableAudits\");\nfunction filterConfigByGatherMode(resolvedConfig, mode) {\n  const artifacts = filterArtifactsByGatherMode(resolvedConfig.artifacts, mode);\n  const supportedAudits = filterAuditsByGatherMode(resolvedConfig.audits, mode);\n  const audits = filterAuditsByAvailableArtifacts(supportedAudits, artifacts || []);\n  const supportedCategories = filterCategoriesByGatherMode(resolvedConfig.categories, mode);\n  const categories = filterCategoriesByAvailableAudits(supportedCategories, audits || []);\n  return {\n    ...resolvedConfig,\n    artifacts,\n    audits,\n    categories\n  };\n}\n__name(filterConfigByGatherMode, \"filterConfigByGatherMode\");\nfunction filterConfigByExplicitFilters(resolvedConfig, filters) {\n  const { onlyAudits, onlyCategories, skipAudits } = filters;\n  if (onlyAudits && !onlyAudits.length) {\n    throw new Error(`onlyAudits cannot be an empty array.`);\n  }\n  if (onlyCategories && !onlyCategories.length) {\n    throw new Error(`onlyCategories cannot be an empty array.`);\n  }\n  errorOnUnknownOnlyCategories(resolvedConfig.categories, onlyCategories);\n  let baseAuditIds = getAuditIdsInCategories(resolvedConfig.categories, void 0);\n  if (onlyCategories) {\n    baseAuditIds = getAuditIdsInCategories(resolvedConfig.categories, onlyCategories);\n  } else if (onlyAudits) {\n    baseAuditIds = /* @__PURE__ */ new Set();\n  } else if (!resolvedConfig.categories || !Object.keys(resolvedConfig.categories).length) {\n    baseAuditIds = new Set(resolvedConfig.audits?.map((audit) => audit.implementation.meta.id));\n  }\n  const auditIdsToKeep = new Set(\n    [\n      ...baseAuditIds,\n      // Start with our base audits.\n      ...onlyAudits || [],\n      // Additionally include the opt-in audits from `onlyAudits`.\n      ...filterResistantAuditIds\n      // Always include any filter-resistant audits.\n    ].filter((auditId) => !skipAudits || !skipAudits.includes(auditId))\n  );\n  const audits = auditIdsToKeep.size && resolvedConfig.audits ? resolvedConfig.audits.filter((audit) => auditIdsToKeep.has(audit.implementation.meta.id)) : resolvedConfig.audits;\n  const availableCategories = filterCategoriesByAvailableAudits(resolvedConfig.categories, audits || []);\n  const categories = filterCategoriesByExplicitFilters(availableCategories, onlyCategories);\n  let artifacts = filterArtifactsByAvailableAudits(resolvedConfig.artifacts, audits);\n  if (artifacts && resolvedConfig.settings.disableFullPageScreenshot) {\n    artifacts = artifacts.filter(({ id }) => id !== \"FullPageScreenshot\");\n  }\n  return {\n    ...resolvedConfig,\n    artifacts,\n    audits,\n    categories\n  };\n}\n__name(filterConfigByExplicitFilters, \"filterConfigByExplicitFilters\");\n\n// core/config/config-helpers.js\ninit_process_global();\ninit_module();\ninit_url();\ninit_lodash();\nimport path4 from \"path\";\n\n// core/config/config-plugin.js\ninit_process_global();\ninit_i18n();\n/**\n * @license\n * Copyright 2019 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\nfunction isArrayOfUnknownObjects(arr) {\n  return Array.isArray(arr) && arr.every(isObjectOfUnknownProperties);\n}\n__name(isArrayOfUnknownObjects, \"isArrayOfUnknownObjects\");\nfunction isObjectOfUnknownProperties(val) {\n  return typeof val === \"object\" && val !== null && !Array.isArray(val);\n}\n__name(isObjectOfUnknownProperties, \"isObjectOfUnknownProperties\");\nfunction objectIsGatherMode(str) {\n  if (typeof str !== \"string\") return false;\n  return str === \"navigation\" || str === \"timespan\" || str === \"snapshot\";\n}\n__name(objectIsGatherMode, \"objectIsGatherMode\");\nfunction isArrayOfGatherModes(arr) {\n  if (!Array.isArray(arr)) return false;\n  return arr.every(objectIsGatherMode);\n}\n__name(isArrayOfGatherModes, \"isArrayOfGatherModes\");\nfunction assertNoExcessProperties(obj, pluginName, objectName = \"\") {\n  if (objectName) {\n    objectName += \" \";\n  }\n  const invalidKeys = Object.keys(obj);\n  if (invalidKeys.length > 0) {\n    const keys2 = invalidKeys.join(\", \");\n    throw new Error(`${pluginName} has unrecognized ${objectName}properties: [${keys2}]`);\n  }\n}\n__name(assertNoExcessProperties, \"assertNoExcessProperties\");\nvar ConfigPlugin = class _ConfigPlugin {\n  static {\n    __name(this, \"ConfigPlugin\");\n  }\n  /**\n   * Extract and validate the list of AuditDefns added by the plugin (or undefined\n   * if no additional audits are being added by the plugin).\n   * @param {unknown} auditsJson\n   * @param {string} pluginName\n   * @return {Array<{path: string}>|undefined}\n   */\n  static _parseAuditsList(auditsJson, pluginName) {\n    if (auditsJson === void 0) {\n      return void 0;\n    } else if (!isArrayOfUnknownObjects(auditsJson)) {\n      throw new Error(`${pluginName} has an invalid audits array.`);\n    }\n    return auditsJson.map((auditDefnJson) => {\n      const { path: path7, ...invalidRest } = auditDefnJson;\n      assertNoExcessProperties(invalidRest, pluginName, \"audit\");\n      if (typeof path7 !== \"string\") {\n        throw new Error(`${pluginName} has a missing audit path.`);\n      }\n      return {\n        path: path7\n      };\n    });\n  }\n  /**\n   * Extract and validate the list of category AuditRefs added by the plugin.\n   * @param {unknown} auditRefsJson\n   * @param {string} pluginName\n   * @return {Array<LH.Config.AuditRefJson>}\n   */\n  static _parseAuditRefsList(auditRefsJson, pluginName) {\n    if (!isArrayOfUnknownObjects(auditRefsJson)) {\n      throw new Error(`${pluginName} has no valid auditsRefs.`);\n    }\n    return auditRefsJson.map((auditRefJson) => {\n      const { id, weight, group, ...invalidRest } = auditRefJson;\n      assertNoExcessProperties(invalidRest, pluginName, \"auditRef\");\n      if (typeof id !== \"string\") {\n        throw new Error(`${pluginName} has an invalid auditRef id.`);\n      }\n      if (typeof weight !== \"number\") {\n        throw new Error(`${pluginName} has an invalid auditRef weight.`);\n      }\n      if (typeof group !== \"string\" && typeof group !== \"undefined\") {\n        throw new Error(`${pluginName} has an invalid auditRef group.`);\n      }\n      const prependedGroup = group ? `${pluginName}-${group}` : group;\n      return {\n        id,\n        weight,\n        group: prependedGroup\n      };\n    });\n  }\n  /**\n   * Extract and validate the category added by the plugin.\n   * @param {unknown} categoryJson\n   * @param {string} pluginName\n   * @return {LH.Config.CategoryJson}\n   */\n  static _parseCategory(categoryJson, pluginName) {\n    if (!isObjectOfUnknownProperties(categoryJson)) {\n      throw new Error(`${pluginName} has no valid category.`);\n    }\n    const {\n      title,\n      description,\n      manualDescription,\n      auditRefs: auditRefsJson,\n      supportedModes,\n      ...invalidRest\n    } = categoryJson;\n    assertNoExcessProperties(invalidRest, pluginName, \"category\");\n    if (!isStringOrIcuMessage(title)) {\n      throw new Error(`${pluginName} has an invalid category tile.`);\n    }\n    if (!isStringOrIcuMessage(description) && description !== void 0) {\n      throw new Error(`${pluginName} has an invalid category description.`);\n    }\n    if (!isStringOrIcuMessage(manualDescription) && manualDescription !== void 0) {\n      throw new Error(`${pluginName} has an invalid category manualDescription.`);\n    }\n    if (!isArrayOfGatherModes(supportedModes) && supportedModes !== void 0) {\n      throw new Error(\n        `${pluginName} supportedModes must be an array, valid array values are \"navigation\", \"timespan\", and \"snapshot\".`\n      );\n    }\n    const auditRefs = _ConfigPlugin._parseAuditRefsList(auditRefsJson, pluginName);\n    return {\n      title,\n      auditRefs,\n      description,\n      manualDescription,\n      supportedModes\n    };\n  }\n  /**\n   * Extract and validate groups JSON added by the plugin.\n   * @param {unknown} groupsJson\n   * @param {string} pluginName\n   * @return {Record<string, LH.Config.GroupJson>|undefined}\n   */\n  static _parseGroups(groupsJson, pluginName) {\n    if (groupsJson === void 0) {\n      return void 0;\n    }\n    if (!isObjectOfUnknownProperties(groupsJson)) {\n      throw new Error(`${pluginName} groups json is not defined as an object.`);\n    }\n    const groups = Object.entries(groupsJson);\n    const parsedGroupsJson = {};\n    groups.forEach(([groupId, groupJson]) => {\n      if (!isObjectOfUnknownProperties(groupJson)) {\n        throw new Error(`${pluginName} has a group not defined as an object.`);\n      }\n      const { title, description, ...invalidRest } = groupJson;\n      assertNoExcessProperties(invalidRest, pluginName, \"group\");\n      if (!isStringOrIcuMessage(title)) {\n        throw new Error(`${pluginName} has an invalid group title.`);\n      }\n      if (!isStringOrIcuMessage(description) && description !== void 0) {\n        throw new Error(`${pluginName} has an invalid group description.`);\n      }\n      parsedGroupsJson[`${pluginName}-${groupId}`] = {\n        title,\n        description\n      };\n    });\n    return parsedGroupsJson;\n  }\n  /**\n   * Extracts and validates a config from the provided plugin input, throwing\n   * if it deviates from the expected object shape.\n   * @param {unknown} pluginJson\n   * @param {string} pluginName\n   * @return {LH.Config}\n   */\n  static parsePlugin(pluginJson, pluginName) {\n    pluginJson = JSON.parse(JSON.stringify(pluginJson));\n    if (!isObjectOfUnknownProperties(pluginJson)) {\n      throw new Error(`${pluginName} is not defined as an object.`);\n    }\n    const {\n      audits: pluginAuditsJson,\n      category: pluginCategoryJson,\n      groups: pluginGroupsJson,\n      ...invalidRest\n    } = pluginJson;\n    assertNoExcessProperties(invalidRest, pluginName);\n    return {\n      audits: _ConfigPlugin._parseAuditsList(pluginAuditsJson, pluginName),\n      categories: {\n        [pluginName]: _ConfigPlugin._parseCategory(pluginCategoryJson, pluginName)\n      },\n      groups: _ConfigPlugin._parseGroups(pluginGroupsJson, pluginName)\n    };\n  }\n};\nvar config_plugin_default = ConfigPlugin;\n\n// core/config/config-helpers.js\ninit_i18n();\ninit_esm_utils();\n/**\n * @license\n * Copyright 2019 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\nvar require4 = createRequire({ url: \"core/config/config-helpers.js\" }.url);\nfunction isBundledEnvironment2() {\n  if (global.isDevtools || global.isLightrider) return true;\n  try {\n    require4.resolve(\"lighthouse-logger\");\n    return false;\n  } catch (err) {\n    return true;\n  }\n}\n__name(isBundledEnvironment2, \"isBundledEnvironment\");\nvar mergeOptionsOfItems = /* @__PURE__ */ __name(function(items) {\n  const mergedItems = [];\n  for (const item of items) {\n    const existingItem = item.path && mergedItems.find((candidate) => candidate.path === item.path);\n    if (!existingItem) {\n      mergedItems.push(item);\n      continue;\n    }\n    existingItem.options = Object.assign({}, existingItem.options, item.options);\n  }\n  return mergedItems;\n}, \"mergeOptionsOfItems\");\nfunction _mergeConfigFragment(base, extension, overwriteArrays = false) {\n  if (typeof base === \"undefined\" || base === null) {\n    return extension;\n  } else if (typeof extension === \"undefined\") {\n    return base;\n  } else if (Array.isArray(extension)) {\n    if (overwriteArrays) return extension;\n    if (!Array.isArray(base)) throw new TypeError(`Expected array but got ${typeof base}`);\n    const merged = base.slice();\n    extension.forEach((item) => {\n      if (!merged.some((candidate) => isEqual_default(candidate, item))) merged.push(item);\n    });\n    return merged;\n  } else if (typeof extension === \"object\") {\n    if (typeof base !== \"object\") throw new TypeError(`Expected object but got ${typeof base}`);\n    if (Array.isArray(base)) throw new TypeError(\"Expected object but got Array\");\n    Object.keys(extension).forEach((key) => {\n      const localOverwriteArrays = overwriteArrays || key === \"settings\" && typeof base[key] === \"object\";\n      base[key] = _mergeConfigFragment(base[key], extension[key], localOverwriteArrays);\n    });\n    return base;\n  }\n  return extension;\n}\n__name(_mergeConfigFragment, \"_mergeConfigFragment\");\nvar mergeConfigFragment = _mergeConfigFragment;\nfunction mergeConfigFragmentArrayByKey(baseArray, extensionArray, keyFn) {\n  const itemsByKey = /* @__PURE__ */ new Map();\n  const mergedArray = baseArray || [];\n  for (let i = 0; i < mergedArray.length; i++) {\n    const item = mergedArray[i];\n    itemsByKey.set(keyFn(item), { index: i, item });\n  }\n  for (const item of extensionArray || []) {\n    const baseItemEntry = itemsByKey.get(keyFn(item));\n    if (baseItemEntry) {\n      const baseItem = baseItemEntry.item;\n      const merged = typeof item === \"object\" && typeof baseItem === \"object\" ? mergeConfigFragment(baseItem, item, true) : item;\n      mergedArray[baseItemEntry.index] = merged;\n    } else {\n      mergedArray.push(item);\n    }\n  }\n  return mergedArray;\n}\n__name(mergeConfigFragmentArrayByKey, \"mergeConfigFragmentArrayByKey\");\nfunction expandGathererShorthand(gatherer) {\n  if (typeof gatherer === \"string\") {\n    return { path: gatherer };\n  } else if (\"implementation\" in gatherer || \"instance\" in gatherer) {\n    return gatherer;\n  } else if (\"path\" in gatherer) {\n    if (typeof gatherer.path !== \"string\") {\n      throw new Error(\"Invalid Gatherer type \" + JSON.stringify(gatherer));\n    }\n    return gatherer;\n  } else if (typeof gatherer === \"function\") {\n    return { implementation: gatherer };\n  } else if (gatherer && typeof gatherer.getArtifact === \"function\") {\n    return { instance: gatherer };\n  } else {\n    throw new Error(\"Invalid Gatherer type \" + JSON.stringify(gatherer));\n  }\n}\n__name(expandGathererShorthand, \"expandGathererShorthand\");\nfunction expandAuditShorthand(audit) {\n  if (typeof audit === \"string\") {\n    return { path: audit, options: {} };\n  } else if (\"implementation\" in audit && typeof audit.implementation.audit === \"function\") {\n    return audit;\n  } else if (\"path\" in audit && typeof audit.path === \"string\") {\n    return audit;\n  } else if (\"audit\" in audit && typeof audit.audit === \"function\") {\n    return { implementation: audit, options: {} };\n  } else {\n    throw new Error(\"Invalid Audit type \" + JSON.stringify(audit));\n  }\n}\n__name(expandAuditShorthand, \"expandAuditShorthand\");\nvar bundledModules = /* @__PURE__ */ new Map([\n  [\"../gather/gatherers/accessibility\", Promise.resolve().then(() => (init_accessibility(), accessibility_exports))],\n  [\"../gather/gatherers/anchor-elements\", Promise.resolve().then(() => (init_anchor_elements(), anchor_elements_exports))],\n  [\"../gather/gatherers/console-messages\", Promise.resolve().then(() => (init_console_messages(), console_messages_exports))],\n  [\"../gather/gatherers/devtools-log\", Promise.resolve().then(() => (init_devtools_log(), devtools_log_exports))],\n  [\"../gather/gatherers/dobetterweb/doctype\", Promise.resolve().then(() => (init_doctype(), doctype_exports))],\n  [\"../gather/gatherers/image-elements\", Promise.resolve().then(() => (init_image_elements(), image_elements_exports))],\n  [\"../gather/gatherers/inputs\", Promise.resolve().then(() => (init_inputs(), inputs_exports))],\n  [\"../gather/gatherers/inspector-issues\", Promise.resolve().then(() => (init_inspector_issues(), inspector_issues_exports))],\n  [\"../gather/gatherers/link-elements\", Promise.resolve().then(() => (init_link_elements(), link_elements_exports))],\n  [\"../gather/gatherers/main-document-content\", Promise.resolve().then(() => (init_main_document_content(), main_document_content_exports))],\n  [\"../gather/gatherers/meta-elements\", Promise.resolve().then(() => (init_meta_elements(), meta_elements_exports))],\n  [\"../gather/gatherers/scripts\", Promise.resolve().then(() => (init_scripts(), scripts_exports))],\n  [\"../gather/gatherers/seo/robots-txt\", Promise.resolve().then(() => (init_robots_txt(), robots_txt_exports))],\n  [\"../gather/gatherers/source-maps\", Promise.resolve().then(() => (init_source_maps(), source_maps_exports))],\n  [\"../gather/gatherers/stacks\", Promise.resolve().then(() => (init_stacks(), stacks_exports))],\n  [\"../gather/gatherers/viewport-dimensions\", Promise.resolve().then(() => (init_viewport_dimensions(), viewport_dimensions_exports))],\n  [\"../audits/accessibility/accesskeys\", Promise.resolve().then(() => (init_accesskeys(), accesskeys_exports))],\n  [\"../audits/accessibility/aria-allowed-attr\", Promise.resolve().then(() => (init_aria_allowed_attr(), aria_allowed_attr_exports))],\n  [\"../audits/accessibility/aria-allowed-role\", Promise.resolve().then(() => (init_aria_allowed_role(), aria_allowed_role_exports))],\n  [\"../audits/accessibility/aria-command-name\", Promise.resolve().then(() => (init_aria_command_name(), aria_command_name_exports))],\n  [\"../audits/accessibility/aria-conditional-attr\", Promise.resolve().then(() => (init_aria_conditional_attr(), aria_conditional_attr_exports))],\n  [\"../audits/accessibility/aria-deprecated-role\", Promise.resolve().then(() => (init_aria_deprecated_role(), aria_deprecated_role_exports))],\n  [\"../audits/accessibility/aria-dialog-name\", Promise.resolve().then(() => (init_aria_dialog_name(), aria_dialog_name_exports))],\n  [\"../audits/accessibility/aria-hidden-body\", Promise.resolve().then(() => (init_aria_hidden_body(), aria_hidden_body_exports))],\n  [\"../audits/accessibility/aria-hidden-focus\", Promise.resolve().then(() => (init_aria_hidden_focus(), aria_hidden_focus_exports))],\n  [\"../audits/accessibility/aria-input-field-name\", Promise.resolve().then(() => (init_aria_input_field_name(), aria_input_field_name_exports))],\n  [\"../audits/accessibility/aria-meter-name\", Promise.resolve().then(() => (init_aria_meter_name(), aria_meter_name_exports))],\n  [\"../audits/accessibility/aria-progressbar-name\", Promise.resolve().then(() => (init_aria_progressbar_name(), aria_progressbar_name_exports))],\n  [\"../audits/accessibility/aria-prohibited-attr\", Promise.resolve().then(() => (init_aria_prohibited_attr(), aria_prohibited_attr_exports))],\n  [\"../audits/accessibility/aria-required-attr\", Promise.resolve().then(() => (init_aria_required_attr(), aria_required_attr_exports))],\n  [\"../audits/accessibility/aria-required-children\", Promise.resolve().then(() => (init_aria_required_children(), aria_required_children_exports))],\n  [\"../audits/accessibility/aria-required-parent\", Promise.resolve().then(() => (init_aria_required_parent(), aria_required_parent_exports))],\n  [\"../audits/accessibility/aria-roles\", Promise.resolve().then(() => (init_aria_roles(), aria_roles_exports))],\n  [\"../audits/accessibility/aria-text\", Promise.resolve().then(() => (init_aria_text(), aria_text_exports))],\n  [\"../audits/accessibility/aria-toggle-field-name\", Promise.resolve().then(() => (init_aria_toggle_field_name(), aria_toggle_field_name_exports))],\n  [\"../audits/accessibility/aria-tooltip-name\", Promise.resolve().then(() => (init_aria_tooltip_name(), aria_tooltip_name_exports))],\n  [\"../audits/accessibility/aria-treeitem-name\", Promise.resolve().then(() => (init_aria_treeitem_name(), aria_treeitem_name_exports))],\n  [\"../audits/accessibility/aria-valid-attr-value\", Promise.resolve().then(() => (init_aria_valid_attr_value(), aria_valid_attr_value_exports))],\n  [\"../audits/accessibility/aria-valid-attr\", Promise.resolve().then(() => (init_aria_valid_attr(), aria_valid_attr_exports))],\n  [\"../audits/accessibility/button-name\", Promise.resolve().then(() => (init_button_name(), button_name_exports))],\n  [\"../audits/accessibility/bypass\", Promise.resolve().then(() => (init_bypass(), bypass_exports))],\n  [\"../audits/accessibility/color-contrast\", Promise.resolve().then(() => (init_color_contrast(), color_contrast_exports))],\n  [\"../audits/accessibility/definition-list\", Promise.resolve().then(() => (init_definition_list(), definition_list_exports))],\n  [\"../audits/accessibility/dlitem\", Promise.resolve().then(() => (init_dlitem(), dlitem_exports))],\n  [\"../audits/accessibility/document-title\", Promise.resolve().then(() => (init_document_title(), document_title_exports))],\n  [\"../audits/accessibility/duplicate-id-aria\", Promise.resolve().then(() => (init_duplicate_id_aria(), duplicate_id_aria_exports))],\n  [\"../audits/accessibility/empty-heading\", Promise.resolve().then(() => (init_empty_heading(), empty_heading_exports))],\n  [\"../audits/accessibility/form-field-multiple-labels\", Promise.resolve().then(() => (init_form_field_multiple_labels(), form_field_multiple_labels_exports))],\n  [\"../audits/accessibility/frame-title\", Promise.resolve().then(() => (init_frame_title(), frame_title_exports))],\n  [\"../audits/accessibility/heading-order\", Promise.resolve().then(() => (init_heading_order(), heading_order_exports))],\n  [\"../audits/accessibility/html-has-lang\", Promise.resolve().then(() => (init_html_has_lang(), html_has_lang_exports))],\n  [\"../audits/accessibility/html-lang-valid\", Promise.resolve().then(() => (init_html_lang_valid(), html_lang_valid_exports))],\n  [\"../audits/accessibility/html-xml-lang-mismatch\", Promise.resolve().then(() => (init_html_xml_lang_mismatch(), html_xml_lang_mismatch_exports))],\n  [\"../audits/accessibility/identical-links-same-purpose\", Promise.resolve().then(() => (init_identical_links_same_purpose(), identical_links_same_purpose_exports))],\n  [\"../audits/accessibility/image-alt\", Promise.resolve().then(() => (init_image_alt(), image_alt_exports))],\n  [\"../audits/accessibility/image-redundant-alt\", Promise.resolve().then(() => (init_image_redundant_alt(), image_redundant_alt_exports))],\n  [\"../audits/accessibility/input-button-name\", Promise.resolve().then(() => (init_input_button_name(), input_button_name_exports))],\n  [\"../audits/accessibility/input-image-alt\", Promise.resolve().then(() => (init_input_image_alt(), input_image_alt_exports))],\n  [\"../audits/accessibility/label-content-name-mismatch\", Promise.resolve().then(() => (init_label_content_name_mismatch(), label_content_name_mismatch_exports))],\n  [\"../audits/accessibility/label\", Promise.resolve().then(() => (init_label(), label_exports))],\n  [\"../audits/accessibility/landmark-one-main\", Promise.resolve().then(() => (init_landmark_one_main(), landmark_one_main_exports))],\n  [\"../audits/accessibility/link-in-text-block\", Promise.resolve().then(() => (init_link_in_text_block(), link_in_text_block_exports))],\n  [\"../audits/accessibility/link-name\", Promise.resolve().then(() => (init_link_name(), link_name_exports))],\n  [\"../audits/accessibility/list\", Promise.resolve().then(() => (init_list(), list_exports))],\n  [\"../audits/accessibility/listitem\", Promise.resolve().then(() => (init_listitem(), listitem_exports))],\n  [\"../audits/accessibility/manual/custom-controls-labels\", Promise.resolve().then(() => (init_custom_controls_labels(), custom_controls_labels_exports))],\n  [\"../audits/accessibility/manual/custom-controls-roles\", Promise.resolve().then(() => (init_custom_controls_roles(), custom_controls_roles_exports))],\n  [\"../audits/accessibility/manual/focus-traps\", Promise.resolve().then(() => (init_focus_traps(), focus_traps_exports))],\n  [\"../audits/accessibility/manual/focusable-controls\", Promise.resolve().then(() => (init_focusable_controls(), focusable_controls_exports))],\n  [\"../audits/accessibility/manual/interactive-element-affordance\", Promise.resolve().then(() => (init_interactive_element_affordance(), interactive_element_affordance_exports))],\n  [\"../audits/accessibility/manual/logical-tab-order\", Promise.resolve().then(() => (init_logical_tab_order(), logical_tab_order_exports))],\n  [\"../audits/accessibility/manual/managed-focus\", Promise.resolve().then(() => (init_managed_focus(), managed_focus_exports))],\n  [\"../audits/accessibility/manual/offscreen-content-hidden\", Promise.resolve().then(() => (init_offscreen_content_hidden(), offscreen_content_hidden_exports))],\n  [\"../audits/accessibility/manual/use-landmarks\", Promise.resolve().then(() => (init_use_landmarks(), use_landmarks_exports))],\n  [\"../audits/accessibility/manual/visual-order-follows-dom\", Promise.resolve().then(() => (init_visual_order_follows_dom(), visual_order_follows_dom_exports))],\n  [\"../audits/accessibility/meta-refresh\", Promise.resolve().then(() => (init_meta_refresh(), meta_refresh_exports))],\n  [\"../audits/accessibility/meta-viewport\", Promise.resolve().then(() => (init_meta_viewport(), meta_viewport_exports))],\n  [\"../audits/accessibility/object-alt\", Promise.resolve().then(() => (init_object_alt(), object_alt_exports))],\n  [\"../audits/accessibility/select-name\", Promise.resolve().then(() => (init_select_name(), select_name_exports))],\n  [\"../audits/accessibility/skip-link\", Promise.resolve().then(() => (init_skip_link(), skip_link_exports))],\n  [\"../audits/accessibility/tabindex\", Promise.resolve().then(() => (init_tabindex(), tabindex_exports))],\n  [\"../audits/accessibility/table-duplicate-name\", Promise.resolve().then(() => (init_table_duplicate_name(), table_duplicate_name_exports))],\n  [\"../audits/accessibility/table-fake-caption\", Promise.resolve().then(() => (init_table_fake_caption(), table_fake_caption_exports))],\n  [\"../audits/accessibility/target-size\", Promise.resolve().then(() => (init_target_size(), target_size_exports))],\n  [\"../audits/accessibility/td-has-header\", Promise.resolve().then(() => (init_td_has_header(), td_has_header_exports))],\n  [\"../audits/accessibility/td-headers-attr\", Promise.resolve().then(() => (init_td_headers_attr(), td_headers_attr_exports))],\n  [\"../audits/accessibility/th-has-data-cells\", Promise.resolve().then(() => (init_th_has_data_cells(), th_has_data_cells_exports))],\n  [\"../audits/accessibility/valid-lang\", Promise.resolve().then(() => (init_valid_lang(), valid_lang_exports))],\n  [\"../audits/accessibility/video-caption\", Promise.resolve().then(() => (init_video_caption(), video_caption_exports))],\n  [\"../audits/clickjacking-mitigation\", Promise.resolve().then(() => (init_clickjacking_mitigation(), clickjacking_mitigation_exports))],\n  [\"../audits/csp-xss\", Promise.resolve().then(() => (init_csp_xss(), csp_xss_exports))],\n  [\"../audits/deprecations\", Promise.resolve().then(() => (init_deprecations(), deprecations_exports))],\n  [\"../audits/dobetterweb/charset\", Promise.resolve().then(() => (init_charset(), charset_exports))],\n  [\"../audits/dobetterweb/doctype\", Promise.resolve().then(() => (init_doctype2(), doctype_exports2))],\n  [\"../audits/dobetterweb/geolocation-on-start\", Promise.resolve().then(() => (init_geolocation_on_start(), geolocation_on_start_exports))],\n  [\"../audits/dobetterweb/inspector-issues\", Promise.resolve().then(() => (init_inspector_issues2(), inspector_issues_exports2))],\n  [\"../audits/dobetterweb/js-libraries\", Promise.resolve().then(() => (init_js_libraries(), js_libraries_exports))],\n  [\"../audits/dobetterweb/notification-on-start\", Promise.resolve().then(() => (init_notification_on_start(), notification_on_start_exports))],\n  [\"../audits/dobetterweb/paste-preventing-inputs\", Promise.resolve().then(() => (init_paste_preventing_inputs(), paste_preventing_inputs_exports))],\n  [\"../audits/errors-in-console\", Promise.resolve().then(() => (init_errors_in_console(), errors_in_console_exports))],\n  [\"../audits/has-hsts\", Promise.resolve().then(() => (init_has_hsts(), has_hsts_exports))],\n  [\"../audits/image-aspect-ratio\", Promise.resolve().then(() => (init_image_aspect_ratio(), image_aspect_ratio_exports))],\n  [\"../audits/image-size-responsive\", Promise.resolve().then(() => (init_image_size_responsive(), image_size_responsive_exports))],\n  [\"../audits/is-on-https\", Promise.resolve().then(() => (init_is_on_https(), is_on_https_exports))],\n  [\"../audits/origin-isolation\", Promise.resolve().then(() => (init_origin_isolation(), origin_isolation_exports))],\n  [\"../audits/redirects-http\", Promise.resolve().then(() => (init_redirects_http(), redirects_http_exports))],\n  [\"../audits/seo/canonical\", Promise.resolve().then(() => (init_canonical(), canonical_exports))],\n  [\"../audits/seo/crawlable-anchors\", Promise.resolve().then(() => (init_crawlable_anchors(), crawlable_anchors_exports))],\n  [\"../audits/seo/hreflang\", Promise.resolve().then(() => (init_hreflang(), hreflang_exports))],\n  [\"../audits/seo/http-status-code\", Promise.resolve().then(() => (init_http_status_code(), http_status_code_exports))],\n  [\"../audits/seo/is-crawlable\", Promise.resolve().then(() => (init_is_crawlable(), is_crawlable_exports))],\n  [\"../audits/seo/link-text\", Promise.resolve().then(() => (init_link_text(), link_text_exports))],\n  [\"../audits/seo/manual/structured-data\", Promise.resolve().then(() => (init_structured_data(), structured_data_exports))],\n  [\"../audits/seo/meta-description\", Promise.resolve().then(() => (init_meta_description(), meta_description_exports))],\n  [\"../audits/seo/robots-txt\", Promise.resolve().then(() => (init_robots_txt2(), robots_txt_exports2))],\n  [\"../audits/third-party-cookies\", Promise.resolve().then(() => (init_third_party_cookies(), third_party_cookies_exports))],\n  [\"../audits/trusted-types-xss\", Promise.resolve().then(() => (init_trusted_types_xss(), trusted_types_xss_exports))],\n  [\"../audits/valid-source-maps\", Promise.resolve().then(() => (init_valid_source_maps(), valid_source_maps_exports))],\n  [\"../computed/speedline\", Promise.resolve().then(() => (init_speedline(), speedline_exports))],\n  [\"../computed/metrics/timing-summary\", Promise.resolve().then(() => (init_timing_summary(), timing_summary_exports))],\n  [\"../computed/entity-classification\", Promise.resolve().then(() => (init_entity_classification(), entity_classification_exports))],\n  [\"../computed/trace-engine-result\", Promise.resolve().then(() => (init_trace_engine_result(), trace_engine_result_exports))],\n  [\"../gather/gatherers/bf-cache-failures\", Promise.resolve().then(() => (init_bf_cache_failures(), bf_cache_failures_exports))],\n  [\"../gather/gatherers/css-usage\", Promise.resolve().then(() => (init_css_usage(), css_usage_exports))],\n  [\"../gather/gatherers/full-page-screenshot\", Promise.resolve().then(() => (init_full_page_screenshot(), full_page_screenshot_exports))],\n  [\"../gather/gatherers/iframe-elements\", Promise.resolve().then(() => (init_iframe_elements(), iframe_elements_exports))],\n  [\"../gather/gatherers/js-usage\", Promise.resolve().then(() => (init_js_usage(), js_usage_exports))],\n  [\"../gather/gatherers/network-user-agent\", Promise.resolve().then(() => (init_network_user_agent(), network_user_agent_exports))],\n  [\"../gather/gatherers/stylesheets\", Promise.resolve().then(() => (init_stylesheets(), stylesheets_exports))],\n  [\"../gather/gatherers/trace-elements\", Promise.resolve().then(() => (init_trace_elements(), trace_elements_exports))],\n  [\"../gather/gatherers/trace\", Promise.resolve().then(() => (init_trace(), trace_exports))],\n  [\"../audits/autocomplete\", Promise.resolve().then(() => (init_autocomplete(), autocomplete_exports))],\n  [\"../audits/bf-cache\", Promise.resolve().then(() => (init_bf_cache(), bf_cache_exports))],\n  [\"../audits/bootup-time\", Promise.resolve().then(() => (init_bootup_time(), bootup_time_exports))],\n  [\"../audits/byte-efficiency/total-byte-weight\", Promise.resolve().then(() => (init_total_byte_weight(), total_byte_weight_exports))],\n  [\"../audits/byte-efficiency/unminified-css\", Promise.resolve().then(() => (init_unminified_css(), unminified_css_exports))],\n  [\"../audits/byte-efficiency/unminified-javascript\", Promise.resolve().then(() => (init_unminified_javascript(), unminified_javascript_exports))],\n  [\"../audits/byte-efficiency/unused-css-rules\", Promise.resolve().then(() => (init_unused_css_rules(), unused_css_rules_exports))],\n  [\"../audits/byte-efficiency/unused-javascript\", Promise.resolve().then(() => (init_unused_javascript(), unused_javascript_exports))],\n  [\"../audits/diagnostics\", Promise.resolve().then(() => (init_diagnostics(), diagnostics_exports))],\n  [\"../audits/final-screenshot\", Promise.resolve().then(() => (init_final_screenshot(), final_screenshot_exports))],\n  [\"../audits/insights/cache-insight\", Promise.resolve().then(() => (init_cache_insight(), cache_insight_exports))],\n  [\"../audits/insights/cls-culprits-insight\", Promise.resolve().then(() => (init_cls_culprits_insight(), cls_culprits_insight_exports))],\n  [\"../audits/insights/document-latency-insight\", Promise.resolve().then(() => (init_document_latency_insight(), document_latency_insight_exports))],\n  [\"../audits/insights/dom-size-insight\", Promise.resolve().then(() => (init_dom_size_insight(), dom_size_insight_exports))],\n  [\"../audits/insights/duplicated-javascript-insight\", Promise.resolve().then(() => (init_duplicated_javascript_insight(), duplicated_javascript_insight_exports))],\n  [\"../audits/insights/font-display-insight\", Promise.resolve().then(() => (init_font_display_insight(), font_display_insight_exports))],\n  [\"../audits/insights/forced-reflow-insight\", Promise.resolve().then(() => (init_forced_reflow_insight(), forced_reflow_insight_exports))],\n  [\"../audits/insights/image-delivery-insight\", Promise.resolve().then(() => (init_image_delivery_insight(), image_delivery_insight_exports))],\n  [\"../audits/insights/inp-breakdown-insight\", Promise.resolve().then(() => (init_inp_breakdown_insight(), inp_breakdown_insight_exports))],\n  [\"../audits/insights/lcp-breakdown-insight\", Promise.resolve().then(() => (init_lcp_breakdown_insight(), lcp_breakdown_insight_exports))],\n  [\"../audits/insights/lcp-discovery-insight\", Promise.resolve().then(() => (init_lcp_discovery_insight(), lcp_discovery_insight_exports))],\n  [\"../audits/insights/legacy-javascript-insight\", Promise.resolve().then(() => (init_legacy_javascript_insight(), legacy_javascript_insight_exports))],\n  [\"../audits/insights/modern-http-insight\", Promise.resolve().then(() => (init_modern_http_insight(), modern_http_insight_exports))],\n  [\"../audits/insights/network-dependency-tree-insight\", Promise.resolve().then(() => (init_network_dependency_tree_insight(), network_dependency_tree_insight_exports))],\n  [\"../audits/insights/render-blocking-insight\", Promise.resolve().then(() => (init_render_blocking_insight(), render_blocking_insight_exports))],\n  [\"../audits/insights/slow-css-selector-insight\", Promise.resolve().then(() => (init_slow_css_selector_insight(), slow_css_selector_insight_exports))],\n  [\"../audits/insights/third-parties-insight\", Promise.resolve().then(() => (init_third_parties_insight(), third_parties_insight_exports))],\n  [\"../audits/insights/viewport-insight\", Promise.resolve().then(() => (init_viewport_insight(), viewport_insight_exports))],\n  [\"../audits/layout-shifts\", Promise.resolve().then(() => (init_layout_shifts(), layout_shifts_exports))],\n  [\"../audits/long-tasks\", Promise.resolve().then(() => (init_long_tasks(), long_tasks_exports))],\n  [\"../audits/main-thread-tasks\", Promise.resolve().then(() => (init_main_thread_tasks(), main_thread_tasks_exports))],\n  [\"../audits/mainthread-work-breakdown\", Promise.resolve().then(() => (init_mainthread_work_breakdown(), mainthread_work_breakdown_exports))],\n  [\"../audits/metrics\", Promise.resolve().then(() => (init_metrics2(), metrics_exports2))],\n  [\"../audits/metrics/cumulative-layout-shift\", Promise.resolve().then(() => (init_cumulative_layout_shift(), cumulative_layout_shift_exports))],\n  [\"../audits/metrics/first-contentful-paint\", Promise.resolve().then(() => (init_first_contentful_paint(), first_contentful_paint_exports))],\n  [\"../audits/metrics/interaction-to-next-paint\", Promise.resolve().then(() => (init_interaction_to_next_paint(), interaction_to_next_paint_exports))],\n  [\"../audits/metrics/interactive\", Promise.resolve().then(() => (init_interactive(), interactive_exports))],\n  [\"../audits/metrics/largest-contentful-paint\", Promise.resolve().then(() => (init_largest_contentful_paint(), largest_contentful_paint_exports))],\n  [\"../audits/metrics/max-potential-fid\", Promise.resolve().then(() => (init_max_potential_fid(), max_potential_fid_exports))],\n  [\"../audits/metrics/speed-index\", Promise.resolve().then(() => (init_speed_index(), speed_index_exports))],\n  [\"../audits/metrics/total-blocking-time\", Promise.resolve().then(() => (init_total_blocking_time(), total_blocking_time_exports))],\n  [\"../audits/network-requests\", Promise.resolve().then(() => (init_network_requests(), network_requests_exports))],\n  [\"../audits/network-rtt\", Promise.resolve().then(() => (init_network_rtt(), network_rtt_exports))],\n  [\"../audits/network-server-latency\", Promise.resolve().then(() => (init_network_server_latency(), network_server_latency_exports))],\n  [\"../audits/non-composited-animations\", Promise.resolve().then(() => (init_non_composited_animations(), non_composited_animations_exports))],\n  [\"../audits/oopif-iframe-test-audit\", Promise.resolve().then(() => (init_oopif_iframe_test_audit(), oopif_iframe_test_audit_exports))],\n  [\"../audits/predictive-perf\", Promise.resolve().then(() => (init_predictive_perf(), predictive_perf_exports))],\n  [\"../audits/redirects\", Promise.resolve().then(() => (init_redirects(), redirects_exports))],\n  [\"../audits/resource-summary\", Promise.resolve().then(() => (init_resource_summary(), resource_summary_exports))],\n  [\"../audits/screenshot-thumbnails\", Promise.resolve().then(() => (init_screenshot_thumbnails(), screenshot_thumbnails_exports))],\n  [\"../audits/script-treemap-data\", Promise.resolve().then(() => (init_script_treemap_data(), script_treemap_data_exports))],\n  [\"../audits/server-response-time\", Promise.resolve().then(() => (init_server_response_time(), server_response_time_exports))],\n  [\"../audits/unsized-images\", Promise.resolve().then(() => (init_unsized_images(), unsized_images_exports))],\n  [\"../audits/user-timings\", Promise.resolve().then(() => (init_user_timings(), user_timings_exports))]\n]);\nasync function requireWrapper(requirePath) {\n  if (path4.isAbsolute(requirePath)) {\n    requirePath = url_default.pathToFileURL(requirePath).href;\n  }\n  let module2;\n  if (bundledModules.has(requirePath)) {\n    module2 = await bundledModules.get(requirePath);\n  } else if (requirePath.match(/\\.(js|mjs|cjs)$/)) {\n    module2 = await import(requirePath);\n  } else {\n    requirePath += \".js\";\n    module2 = await import(requirePath);\n  }\n  if (module2.default) return module2.default;\n  const methods = /* @__PURE__ */ new Set([\"meta\"]);\n  const possibleNamedExports = Object.keys(module2).filter((key) => {\n    if (!(module2[key] && module2[key] instanceof Object)) return false;\n    return Object.getOwnPropertyNames(module2[key]).some((method) => methods.has(method));\n  });\n  if (possibleNamedExports.length === 1) return possibleNamedExports[0];\n  if (possibleNamedExports.length > 1) {\n    throw new Error(`module '${requirePath}' has too many possible exports`);\n  }\n  throw new Error(`module '${requirePath}' missing default export`);\n}\n__name(requireWrapper, \"requireWrapper\");\nasync function requireGatherer(gathererPath, coreGathererList, configDir) {\n  const coreGatherer = coreGathererList.find((a) => a === `${gathererPath}.js`);\n  let requirePath = `../gather/gatherers/${gathererPath}`;\n  if (!coreGatherer) {\n    requirePath = resolveModulePath(gathererPath, configDir, \"gatherer\");\n  }\n  const GathererClass = (\n    /** @type {GathererConstructor} */\n    await requireWrapper(requirePath)\n  );\n  return {\n    instance: new GathererClass(),\n    implementation: GathererClass,\n    path: gathererPath\n  };\n}\n__name(requireGatherer, \"requireGatherer\");\nfunction requireAudit(auditPath, coreAuditList, configDir) {\n  const auditPathJs = `${auditPath}.js`;\n  const coreAudit = coreAuditList.find((a) => a === auditPathJs);\n  let requirePath = `../audits/${auditPath}`;\n  if (!coreAudit) {\n    if (isBundledEnvironment2()) {\n      requirePath = auditPath;\n    } else {\n      const absolutePath = resolveModulePath(auditPath, configDir, \"audit\");\n      if (isBundledEnvironment2()) {\n        requirePath = path4.relative(\"\", absolutePath);\n      } else {\n        requirePath = absolutePath;\n      }\n    }\n  }\n  return requireWrapper(requirePath);\n}\n__name(requireAudit, \"requireAudit\");\nfunction cleanFlagsForSettings(flags = {}) {\n  const settings = {};\n  for (const key of Object.keys(flags)) {\n    if (key in defaultSettings) {\n      settings[key] = flags[key];\n    }\n  }\n  return settings;\n}\n__name(cleanFlagsForSettings, \"cleanFlagsForSettings\");\nfunction resolveSettings(settingsJson = {}, overrides = void 0) {\n  const locale = lookupLocale(overrides?.locale || settingsJson.locale);\n  const { defaultSettings: defaultSettings2 } = constants_exports;\n  const settingWithDefaults = mergeConfigFragment(deepClone(defaultSettings2), settingsJson, true);\n  const settingsWithFlags = mergeConfigFragment(\n    settingWithDefaults,\n    cleanFlagsForSettings(overrides),\n    true\n  );\n  settingsWithFlags.locale = locale;\n  if (settingsWithFlags.emulatedUserAgent === true) {\n    settingsWithFlags.emulatedUserAgent = userAgents[settingsWithFlags.formFactor];\n  }\n  assertValidSettings(settingsWithFlags);\n  return settingsWithFlags;\n}\n__name(resolveSettings, \"resolveSettings\");\nasync function mergePlugins(config3, configDir, flags) {\n  const configPlugins = config3.plugins || [];\n  const flagPlugins = flags?.plugins || [];\n  const pluginNames = /* @__PURE__ */ new Set([...configPlugins, ...flagPlugins]);\n  for (const pluginName of pluginNames) {\n    assertValidPluginName(config3, pluginName);\n    const pluginPath = isBundledEnvironment2() ? pluginName : resolveModulePath(pluginName, configDir, \"plugin\");\n    const rawPluginJson = await requireWrapper(pluginPath);\n    const pluginJson = config_plugin_default.parsePlugin(rawPluginJson, pluginName);\n    config3 = mergeConfigFragment(config3, pluginJson);\n  }\n  return config3;\n}\n__name(mergePlugins, \"mergePlugins\");\nasync function resolveGathererToDefn(gathererJson, coreGathererList, configDir) {\n  const gathererDefn = expandGathererShorthand(gathererJson);\n  if (gathererDefn.instance) {\n    return {\n      instance: gathererDefn.instance,\n      implementation: gathererDefn.implementation,\n      path: gathererDefn.path\n    };\n  } else if (gathererDefn.implementation) {\n    const GathererClass = gathererDefn.implementation;\n    return {\n      instance: new GathererClass(),\n      implementation: gathererDefn.implementation,\n      path: gathererDefn.path\n    };\n  } else if (gathererDefn.path) {\n    const path7 = gathererDefn.path;\n    return requireGatherer(path7, coreGathererList, configDir);\n  } else {\n    throw new Error(\"Invalid expanded Gatherer: \" + JSON.stringify(gathererDefn));\n  }\n}\n__name(resolveGathererToDefn, \"resolveGathererToDefn\");\nasync function resolveAuditsToDefns(audits, configDir) {\n  if (!audits) {\n    return null;\n  }\n  const coreList = Runner.getAuditList();\n  const auditDefnsPromises = audits.map(async (auditJson) => {\n    const auditDefn = expandAuditShorthand(auditJson);\n    let implementation;\n    if (\"implementation\" in auditDefn) {\n      implementation = auditDefn.implementation;\n    } else {\n      implementation = await requireAudit(auditDefn.path, coreList, configDir);\n    }\n    return {\n      implementation,\n      path: auditDefn.path,\n      options: auditDefn.options || {}\n    };\n  });\n  const auditDefns = await Promise.all(auditDefnsPromises);\n  const mergedAuditDefns = mergeOptionsOfItems(auditDefns);\n  mergedAuditDefns.forEach((audit) => assertValidAudit(audit));\n  return mergedAuditDefns;\n}\n__name(resolveAuditsToDefns, \"resolveAuditsToDefns\");\nfunction resolveModulePath(moduleIdentifier, configDir, category) {\n  try {\n    return require4.resolve(moduleIdentifier);\n  } catch (e) {\n  }\n  try {\n    return require4.resolve(moduleIdentifier, { paths: [process.cwd()] });\n  } catch (e) {\n  }\n  const cwdPath = path4.resolve(process.cwd(), moduleIdentifier);\n  try {\n    return require4.resolve(cwdPath);\n  } catch (e) {\n  }\n  const errorString = \"Unable to locate \" + (category ? `${category}: ` : \"\") + `\\`${moduleIdentifier}\\`.\n     Tried to resolve the module from these locations:\n       ${\"\"}\n       ${cwdPath}`;\n  if (!configDir) {\n    throw new Error(errorString);\n  }\n  const relativePath = path4.resolve(configDir, moduleIdentifier);\n  try {\n    return require4.resolve(relativePath);\n  } catch (requireError) {\n  }\n  try {\n    return require4.resolve(moduleIdentifier, { paths: [configDir] });\n  } catch (requireError) {\n  }\n  throw new Error(errorString + `\n       ${relativePath}`);\n}\n__name(resolveModulePath, \"resolveModulePath\");\nfunction shallowClone(item) {\n  if (typeof item === \"object\") {\n    return Object.assign(\n      Object.create(\n        Object.getPrototypeOf(item)\n      ),\n      item\n    );\n  }\n  return item;\n}\n__name(shallowClone, \"shallowClone\");\nfunction deepClone(json) {\n  return JSON.parse(JSON.stringify(json));\n}\n__name(deepClone, \"deepClone\");\nfunction deepCloneConfigJson(json) {\n  const cloned = deepClone(json);\n  if (Array.isArray(json.audits)) {\n    cloned.audits = json.audits.map((audit) => shallowClone(audit));\n  }\n  if (Array.isArray(json.artifacts)) {\n    cloned.artifacts = json.artifacts.map((artifact) => ({\n      ...artifact,\n      gatherer: shallowClone(artifact.gatherer)\n    }));\n  }\n  return cloned;\n}\n__name(deepCloneConfigJson, \"deepCloneConfigJson\");\n\n// core/config/config.js\ninit_esm_utils();\ninit_format();\n/**\n * @license\n * Copyright 2020 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\nvar defaultConfigPath = path5.join(\n  \"\",\n  \"../../config/default-config.js\"\n);\nvar internalArtifactPriorities = {\n  FullPageScreenshot: 1,\n  BFCacheFailures: 1\n};\nfunction resolveWorkingCopy(config3, context) {\n  let { configPath } = context;\n  if (configPath && !path5.isAbsolute(configPath)) {\n    throw new Error(\"configPath must be an absolute path\");\n  }\n  if (!config3) {\n    config3 = default_config_default;\n    configPath = defaultConfigPath;\n  }\n  const configDir = configPath ? path5.dirname(configPath) : void 0;\n  return {\n    configWorkingCopy: deepCloneConfigJson(config3),\n    configPath,\n    configDir\n  };\n}\n__name(resolveWorkingCopy, \"resolveWorkingCopy\");\nfunction resolveExtensions(config3) {\n  if (!config3.extends) return config3;\n  if (config3.extends !== \"lighthouse:default\") {\n    throw new Error(\"`lighthouse:default` is the only valid extension method.\");\n  }\n  const { artifacts, ...extensionJSON } = config3;\n  const defaultClone = deepCloneConfigJson(default_config_default);\n  const mergedConfig = mergeConfigFragment(defaultClone, extensionJSON);\n  mergedConfig.artifacts = mergeConfigFragmentArrayByKey(\n    defaultClone.artifacts,\n    artifacts,\n    (artifact) => artifact.id\n  );\n  return mergedConfig;\n}\n__name(resolveExtensions, \"resolveExtensions\");\nfunction resolveArtifactDependencies(artifact, gatherer, artifactDefnsBySymbol) {\n  if (!(\"dependencies\" in gatherer.instance.meta)) return void 0;\n  const dependencies = Object.entries(gatherer.instance.meta.dependencies).map(\n    ([dependencyName, artifactSymbol]) => {\n      const dependency = artifactDefnsBySymbol.get(artifactSymbol);\n      if (!dependency) throwInvalidDependencyOrder(artifact.id, dependencyName);\n      const validDependency = isValidArtifactDependency(gatherer, dependency.gatherer);\n      if (!validDependency) throwInvalidArtifactDependency(artifact.id, dependencyName);\n      return [dependencyName, { id: dependency.id }];\n    }\n  );\n  return Object.fromEntries(dependencies);\n}\n__name(resolveArtifactDependencies, \"resolveArtifactDependencies\");\nasync function resolveArtifactsToDefns(artifacts, configDir) {\n  if (!artifacts) return null;\n  const status = { msg: \"Resolve artifact definitions\", id: \"lh:config:resolveArtifactsToDefns\" };\n  lighthouse_logger_default.time(status, \"verbose\");\n  const sortedArtifacts = [...artifacts];\n  sortedArtifacts.sort((a, b) => {\n    const aPriority = internalArtifactPriorities[a.id] || 0;\n    const bPriority = internalArtifactPriorities[b.id] || 0;\n    return aPriority - bPriority;\n  });\n  const artifactDefnsBySymbol = /* @__PURE__ */ new Map();\n  const coreGathererList = Runner.getGathererList();\n  const artifactDefns = [];\n  for (const artifactJson of sortedArtifacts) {\n    const gathererJson = artifactJson.gatherer;\n    const gatherer = await resolveGathererToDefn(gathererJson, coreGathererList, configDir);\n    const artifact = {\n      id: artifactJson.id,\n      gatherer,\n      dependencies: resolveArtifactDependencies(artifactJson, gatherer, artifactDefnsBySymbol)\n    };\n    const symbol = artifact.gatherer.instance.meta.symbol;\n    if (symbol) artifactDefnsBySymbol.set(symbol, artifact);\n    artifactDefns.push(artifact);\n  }\n  lighthouse_logger_default.timeEnd(status);\n  return artifactDefns;\n}\n__name(resolveArtifactsToDefns, \"resolveArtifactsToDefns\");\nfunction overrideSettingsForGatherMode(settings, gatherMode) {\n  if (gatherMode === \"timespan\") {\n    if (settings.throttlingMethod === \"simulate\") {\n      settings.throttlingMethod = \"devtools\";\n    }\n  }\n}\n__name(overrideSettingsForGatherMode, \"overrideSettingsForGatherMode\");\nfunction overrideThrottlingWindows(settings) {\n  if (settings.throttlingMethod === \"simulate\") return;\n  settings.cpuQuietThresholdMs = Math.max(\n    settings.cpuQuietThresholdMs || 0,\n    nonSimulatedSettingsOverrides.cpuQuietThresholdMs\n  );\n  settings.networkQuietThresholdMs = Math.max(\n    settings.networkQuietThresholdMs || 0,\n    nonSimulatedSettingsOverrides.networkQuietThresholdMs\n  );\n  settings.pauseAfterFcpMs = Math.max(\n    settings.pauseAfterFcpMs || 0,\n    nonSimulatedSettingsOverrides.pauseAfterFcpMs\n  );\n  settings.pauseAfterLoadMs = Math.max(\n    settings.pauseAfterLoadMs || 0,\n    nonSimulatedSettingsOverrides.pauseAfterLoadMs\n  );\n}\n__name(overrideThrottlingWindows, \"overrideThrottlingWindows\");\nasync function initializeConfig(gatherMode, config3, flags = {}) {\n  const status = { msg: \"Initialize config\", id: \"lh:config\" };\n  lighthouse_logger_default.time(status, \"verbose\");\n  let { configWorkingCopy, configDir } = resolveWorkingCopy(config3, flags);\n  configWorkingCopy = resolveExtensions(configWorkingCopy);\n  configWorkingCopy = await mergePlugins(configWorkingCopy, configDir, flags);\n  const settings = resolveSettings(configWorkingCopy.settings || {}, flags);\n  overrideSettingsForGatherMode(settings, gatherMode);\n  overrideThrottlingWindows(settings);\n  const artifacts = await resolveArtifactsToDefns(configWorkingCopy.artifacts, configDir);\n  let resolvedConfig = {\n    artifacts,\n    audits: await resolveAuditsToDefns(configWorkingCopy.audits, configDir),\n    categories: configWorkingCopy.categories || null,\n    groups: configWorkingCopy.groups || null,\n    settings\n  };\n  assertValidConfig(resolvedConfig);\n  resolvedConfig = filterConfigByGatherMode(resolvedConfig, gatherMode);\n  resolvedConfig = filterConfigByExplicitFilters(resolvedConfig, settings);\n  lighthouse_logger_default.timeEnd(status);\n  return { resolvedConfig };\n}\n__name(initializeConfig, \"initializeConfig\");\n\n// core/lib/sentry.js\n/**\n * @license\n * Copyright 2017 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\nvar SENTRY_URL = \"https://a6bb0da87ee048cc9ae2a345fc09ab2e:63a7029f46f74265981b7e005e0f69f8@sentry.io/174697\";\nvar SAMPLE_RATE = 0.01;\nvar noop = /* @__PURE__ */ __name(() => {\n}, \"noop\");\nvar sentryDelegate = {\n  init,\n  /** @type {(message: string, level?: SeverityLevel) => void} */\n  captureMessage: noop,\n  /** @type {(breadcrumb: Breadcrumb) => void} */\n  captureBreadcrumb: noop,\n  /** @type {() => any} */\n  getContext: noop,\n  /** @type {(error: Error, options: {level?: string, tags?: {[key: string]: any}, extra?: {[key: string]: any}}) => Promise<void>} */\n  captureException: /* @__PURE__ */ __name(async () => {\n  }, \"captureException\"),\n  _shouldSample() {\n    return SAMPLE_RATE >= Math.random();\n  }\n};\nasync function init(opts) {\n  if (!opts.flags.enableErrorReporting) {\n    return;\n  }\n  if (!sentryDelegate._shouldSample()) {\n    return;\n  }\n  try {\n    const Sentry2 = await Promise.resolve().then(() => (init_cjs(), cjs_exports));\n    Sentry2.init({\n      ...opts.environmentData,\n      dsn: SENTRY_URL\n    });\n    let settings = opts.flags;\n    try {\n      const { resolvedConfig } = await initializeConfig(\"navigation\", opts.config, opts.flags);\n      settings = resolvedConfig.settings;\n    } catch {\n    }\n    const baseTags = {\n      channel: settings.channel,\n      formFactor: settings.formFactor,\n      throttlingMethod: settings.throttlingMethod\n    };\n    Sentry2.setTags(baseTags);\n    const extras = {\n      ...settings.throttling,\n      url: opts.url\n    };\n    Sentry2.setExtras(extras);\n    sentryDelegate.captureMessage = (...args) => Sentry2.captureMessage(...args);\n    sentryDelegate.captureBreadcrumb = (...args) => Sentry2.addBreadcrumb(...args);\n    sentryDelegate.getContext = () => extras;\n    const sentryExceptionCache = /* @__PURE__ */ new Map();\n    sentryDelegate.captureException = async (err, opts2 = {}) => {\n      if (!err) return;\n      if (err.expected) return;\n      const tags = opts2.tags || {};\n      if (tags.audit) {\n        const key = `audit-${tags.audit}-${err.message}`;\n        if (sentryExceptionCache.has(key)) return;\n        sentryExceptionCache.set(key, true);\n      }\n      if (tags.gatherer) {\n        const key = `gatherer-${tags.gatherer}-${err.message}`;\n        if (sentryExceptionCache.has(key)) return;\n        sentryExceptionCache.set(key, true);\n      }\n      if (err.protocolMethod) {\n        opts2.fingerprint = [\"{{ default }}\", err.protocolMethod, err.protocolError];\n        opts2.tags = opts2.tags || {};\n        opts2.tags.protocolMethod = err.protocolMethod;\n      }\n      Sentry2.withScope((scope) => {\n        if (opts2.level) {\n          scope.setLevel(opts2.level);\n        }\n        if (opts2.tags) {\n          scope.setTags(opts2.tags);\n        }\n        let extra;\n        if (opts2.extra) extra = { ...opts2.extra };\n        if (err.extra) extra = { ...extra, ...err.extra };\n        if (extra) {\n          scope.setExtras(extra);\n        }\n        Sentry2.captureException(err);\n      });\n    };\n  } catch (e) {\n    lighthouse_logger_default.warn(\n      \"sentry\",\n      \"Could not load Sentry, errors will not be reported.\"\n    );\n  }\n}\n__name(init, \"init\");\nvar Sentry = sentryDelegate;\n\n// report/generator/report-generator.js\ninit_process_global();\n\n// replace-modules:/Users/alexrudenko/src/lighthouse/report/generator/report-assets.js\ninit_process_global();\nvar reportAssets = {\n  REPORT_TEMPLATE: `<!--\n@license\nCopyright 2018 Google LLC\nSPDX-License-Identifier: Apache-2.0\n-->\n<!doctype html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"utf-8\">\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, minimum-scale=1\">\n  <link rel=\"icon\" href='data:image/svg+xml;utf8,<svg fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 48 48\"><path d=\"m14 7 10-7 10 7v10h5v7h-5l5 24H9l5-24H9v-7h5V7Z\" fill=\"%23F63\"/><path d=\"M31.561 24H14l-1.689 8.105L31.561 24ZM18.983 48H9l1.022-4.907L35.723 32.27l1.663 7.98L18.983 48Z\" fill=\"%23FFA385\"/><path fill=\"%23FF3\" d=\"M20.5 10h7v7h-7z\"/></svg>'>\n  <title>Lighthouse Report</title>\n  <style>body {margin: 0}</style>\n</head>\n<body>\n  <noscript>Lighthouse report requires JavaScript. Please enable.</noscript>\n\n  <div id=\"lh-log\"></div>\n\n  <script>window.__LIGHTHOUSE_JSON__ = %%LIGHTHOUSE_JSON%%;</script>\n  <script>%%LIGHTHOUSE_JAVASCRIPT%%\n  __initLighthouseReport__();\n  //# sourceURL=compiled-reportrenderer.js\n  </script>\n  <script>console.log('window.__LIGHTHOUSE_JSON__', __LIGHTHOUSE_JSON__);</script>\n</body>\n</html>\n`,\n  REPORT_JAVASCRIPT: '\"use strict\";(()=>{var Re=.8999999999999999,Ne=.5,Ie=.49999999999999994;function He(o){let e=Math.sign(o);o=Math.abs(o);let t=.254829592,n=-.284496736,r=1.421413741,i=-1.453152027,a=1.061405429,s=1/(1+.3275911*o),c=s*(t+s*(n+s*(r+s*(i+s*a))));return e*(1-c*Math.exp(-o*o))}function fe({median:o,p10:e},t){if(o<=0)throw new Error(\"median must be greater than zero\");if(e<=0)throw new Error(\"p10 must be greater than zero\");if(e>=o)throw new Error(\"p10 must be less than the median\");if(t<=0)return 1;let n=.9061938024368232,r=Math.max(Number.MIN_VALUE,t/o),i=Math.log(r),a=Math.max(Number.MIN_VALUE,e/o),l=-Math.log(a),s=i*n/l,c=(1-He(s))/2,d;return t<=e?d=Math.max(.9,Math.min(1,c)):t<=o?d=Math.max(Ne,Math.min(Re,c)):d=Math.max(0,Math.min(Ie,c)),d}var U=\"\\\\u2026\",Oe=\"\\\\xA0\",ve=.9,$e={PASS:{label:\"pass\",minScore:ve},AVERAGE:{label:\"average\",minScore:.5},FAIL:{label:\"fail\"},ERROR:{label:\"error\"}},Ve=[\"com\",\"co\",\"gov\",\"edu\",\"ac\",\"org\",\"go\",\"gob\",\"or\",\"net\",\"in\",\"ne\",\"nic\",\"gouv\\\n\",\"web\",\"spb\",\"blog\",\"jus\",\"kiev\",\"mil\",\"wi\",\"qc\",\"ca\",\"bel\",\"on\"],E=class o{static get RATINGS(){return $e}static get PASS_THRESHOLD(){return ve}static get MS_DISPLAY_VALUE(){return`%10d${Oe}ms`}static getFinalDisplayedUrl(e){if(e.finalDisplayedUrl)return e.finalDisplayedUrl;if(e.finalUrl)return e.finalUrl;throw new Error(\"Could not determine final displayed URL\")}static getMainDocumentUrl(e){return e.mainDocumentUrl||e.finalUrl}static getFullPageScreenshot(e){return e.fullPageScreenshot?e.fullPageScreenshot:e.audits[\"full-page-screenshot\"]?.details}static getEntityFromUrl(e,t){return t&&t.find(r=>r.origins.find(i=>e.startsWith(i)))||o.getPseudoRootDomain(e)}static splitMarkdownCodeSpans(e){let t=[],n=e.split(/`(.*?)`/g);for(let r=0;r<n.length;r++){let i=n[r];if(!i)continue;let a=r%2!==0;t.push({isCode:a,text:i})}return t}static splitMarkdownLink(e){let t=[],n=e.split(/\\\\[([^\\\\]]+?)\\\\]\\\\((https?:\\\\/\\\\/.*?)\\\\)/g);for(;n.length;){let[r,i,a]=n.splice(0,3);r&&t.push({isLink:!1,text:r}),i&&a&&t.p\\\nush({isLink:!0,text:i,linkHref:a})}return t}static truncate(e,t,n=\"\\\\u2026\"){if(e.length<=t)return e;let i=new Intl.Segmenter(void 0,{granularity:\"grapheme\"}).segment(e)[Symbol.iterator](),a=0;for(let l=0;l<=t-n.length;l++){let s=i.next();if(s.done)return e;a=s.value.index}for(let l=0;l<n.length;l++)if(i.next().done)return e;return e.slice(0,a)+n}static getURLDisplayName(e,t){t=t||{numPathParts:void 0,preserveQuery:void 0,preserveHost:void 0};let n=t.numPathParts!==void 0?t.numPathParts:2,r=t.preserveQuery!==void 0?t.preserveQuery:!0,i=t.preserveHost||!1,a;if(e.protocol===\"about:\"||e.protocol===\"data:\")a=e.href;else{a=e.pathname;let s=a.split(\"/\").filter(c=>c.length);n&&s.length>n&&(a=U+s.slice(-1*n).join(\"/\")),i&&(a=`${e.host}/${a.replace(/^\\\\//,\"\")}`),r&&(a=`${a}${e.search}`)}let l=64;if(e.protocol!==\"data:\"&&(a=a.slice(0,200),a=a.replace(/([a-f0-9]{7})[a-f0-9]{13}[a-f0-9]*/g,`$1${U}`),a=a.replace(/([a-zA-Z0-9-_]{9})(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])[a-zA-Z0-9-_]{10,}/g,`$1${U}`),a=a.re\\\nplace(/(\\\\d{3})\\\\d{6,}/g,`$1${U}`),a=a.replace(/\\\\u2026+/g,U),a.length>l&&a.includes(\"?\")&&(a=a.replace(/\\\\?([^=]*)(=)?.*/,`?$1$2${U}`),a.length>l&&(a=a.replace(/\\\\?.*/,`?${U}`)))),a.length>l){let s=a.lastIndexOf(\".\");s>=0?a=a.slice(0,l-1-(a.length-s))+`${U}${a.slice(s)}`:a=a.slice(0,l-1)+U}return a}static getChromeExtensionOrigin(e){let t=new URL(e);return t.protocol+\"//\"+t.host}static parseURL(e){let t=new URL(e);return{file:o.getURLDisplayName(t),hostname:t.hostname,origin:t.protocol===\"chrome-extension:\"?o.getChromeExtensionOrigin(e):t.origin}}static createOrReturnURL(e){return e instanceof URL?e:new URL(e)}static getPseudoTld(e){let t=e.split(\".\").slice(-2);return Ve.includes(t[0])?`.${t.join(\".\")}`:`.${t[t.length-1]}`}static getPseudoRootDomain(e){let t=o.createOrReturnURL(e).hostname,r=o.getPseudoTld(t).split(\".\");return t.split(\".\").slice(-r.length).join(\".\")}static filterRelevantLines(e,t,n){if(t.length===0)return e.slice(0,n*2+1);let r=3,i=new Set;return t=t.sort((a,l)=>(a.lineNum\\\nber||0)-(l.lineNumber||0)),t.forEach(({lineNumber:a})=>{let l=a-n,s=a+n;for(;l<1;)l++,s++;i.has(l-r-1)&&(l-=r);for(let c=l;c<=s;c++){let d=c;i.add(d)}}),e.filter(a=>i.has(a.lineNumber))}static computeLogNormalScore(e,t){let n=fe(e,t);return n>.9&&(n+=.05*(n-.9)),Math.floor(n*100)/100}};function Ge(o){let e=o.createFragment(),t=o.createElement(\"style\");t.append(`\\n    .lh-3p-filter {\\n      color: var(--color-gray-600);\\n      float: right;\\n      padding: 6px var(--stackpack-padding-horizontal);\\n    }\\n    .lh-3p-filter-label, .lh-3p-filter-input {\\n      vertical-align: middle;\\n      user-select: none;\\n    }\\n    .lh-3p-filter-input:disabled + .lh-3p-ui-string {\\n      text-decoration: line-through;\\n    }\\n  `),e.append(t);let n=o.createElement(\"div\",\"lh-3p-filter\"),r=o.createElement(\"label\",\"lh-3p-filter-label\"),i=o.createElement(\"input\",\"lh-3p-filter-input\");i.setAttribute(\"type\",\"checkbox\"),i.setAttribute(\"checked\",\"\");let a=o.createElement(\"span\",\"lh-3p-ui-string\");a.append(\"Show 3rd party\\\n resources\");let l=o.createElement(\"span\",\"lh-3p-filter-count\");return r.append(\" \",i,\" \",a,\" (\",l,\") \"),n.append(\" \",r,\" \"),e.append(n),e}function Be(o){let e=o.createFragment(),t=o.createElement(\"div\",\"lh-audit\"),n=o.createElement(\"details\",\"lh-expandable-details\"),r=o.createElement(\"summary\"),i=o.createElement(\"div\",\"lh-audit__header lh-expandable-details__summary\"),a=o.createElement(\"span\",\"lh-audit__score-icon\"),l=o.createElement(\"span\",\"lh-audit__title-and-text\"),s=o.createElement(\"span\",\"lh-audit__title\"),c=o.createElement(\"span\",\"lh-audit__display-text\");l.append(\" \",s,\" \",c,\" \");let d=o.createElement(\"div\",\"lh-chevron-container\");i.append(\" \",a,\" \",l,\" \",d,\" \"),r.append(\" \",i,\" \");let h=o.createElement(\"div\",\"lh-audit__description\"),p=o.createElement(\"div\",\"lh-audit__stackpacks\");return n.append(\" \",r,\" \",h,\" \",p,\" \"),t.append(\" \",n,\" \"),e.append(t),e}function qe(o){let e=o.createFragment(),t=o.createElement(\"div\",\"lh-category-header\"),n=o.createElement(\"div\",\"lh-score__gauge\"\\\n);n.setAttribute(\"role\",\"heading\"),n.setAttribute(\"aria-level\",\"2\");let r=o.createElement(\"div\",\"lh-category-header__description\");return t.append(\" \",n,\" \",r,\" \"),e.append(t),e}function je(o){let e=o.createFragment(),t=o.createElementNS(\"http://www.w3.org/2000/svg\",\"svg\",\"lh-chevron\");t.setAttribute(\"viewBox\",\"0 0 100 100\");let n=o.createElementNS(\"http://www.w3.org/2000/svg\",\"g\",\"lh-chevron__lines\"),r=o.createElementNS(\"http://www.w3.org/2000/svg\",\"path\",\"lh-chevron__line lh-chevron__line-left\");r.setAttribute(\"d\",\"M10 50h40\");let i=o.createElementNS(\"http://www.w3.org/2000/svg\",\"path\",\"lh-chevron__line lh-chevron__line-right\");return i.setAttribute(\"d\",\"M90 50H50\"),n.append(\" \",r,\" \",i,\" \"),t.append(\" \",n,\" \"),e.append(t),e}function We(o){let e=o.createFragment(),t=o.createElement(\"div\",\"lh-audit-group\"),n=o.createElement(\"details\",\"lh-clump\"),r=o.createElement(\"summary\"),i=o.createElement(\"div\",\"lh-audit-group__summary\"),a=o.createElement(\"div\",\"lh-audit-group__header\"),l=o.createE\\\nlement(\"span\",\"lh-audit-group__title\"),s=o.createElement(\"span\",\"lh-audit-group__itemcount\");a.append(\" \",l,\" \",s,\" \",\" \",\" \");let c=o.createElement(\"div\",\"lh-clump-toggle\"),d=o.createElement(\"span\",\"lh-clump-toggletext--show\"),h=o.createElement(\"span\",\"lh-clump-toggletext--hide\");return c.append(\" \",d,\" \",h,\" \"),i.append(\" \",a,\" \",c,\" \"),r.append(\" \",i,\" \"),n.append(\" \",r,\" \"),t.append(\" \",\" \",n,\" \"),e.append(t),e}function Ke(o){let e=o.createFragment(),t=o.createElement(\"div\",\"lh-crc-container\"),n=o.createElement(\"style\");n.append(`\\n      .lh-crc .lh-tree-marker {\\n        width: 12px;\\n        height: 26px;\\n        display: block;\\n        float: left;\\n        background-position: top left;\\n      }\\n      .lh-crc .lh-horiz-down {\\n        background: url(\\'data:image/svg+xml;utf8,<svg width=\"16\" height=\"26\" viewBox=\"0 0 16 26\" xmlns=\"http://www.w3.org/2000/svg\"><g fill=\"%23D8D8D8\" fill-rule=\"evenodd\"><path d=\"M16 12v2H-2v-2z\"/><path d=\"M9 12v14H7V12z\"/></g></svg>\\');\\n      }\\n      .lh-crc \\\n.lh-right {\\n        background: url(\\'data:image/svg+xml;utf8,<svg width=\"16\" height=\"26\" viewBox=\"0 0 16 26\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M16 12v2H0v-2z\" fill=\"%23D8D8D8\" fill-rule=\"evenodd\"/></svg>\\');\\n      }\\n      .lh-crc .lh-up-right {\\n        background: url(\\'data:image/svg+xml;utf8,<svg width=\"16\" height=\"26\" viewBox=\"0 0 16 26\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M7 0h2v14H7zm2 12h7v2H9z\" fill=\"%23D8D8D8\" fill-rule=\"evenodd\"/></svg>\\');\\n      }\\n      .lh-crc .lh-vert-right {\\n        background: url(\\'data:image/svg+xml;utf8,<svg width=\"16\" height=\"26\" viewBox=\"0 0 16 26\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M7 0h2v27H7zm2 12h7v2H9z\" fill=\"%23D8D8D8\" fill-rule=\"evenodd\"/></svg>\\');\\n      }\\n      .lh-crc .lh-vert {\\n        background: url(\\'data:image/svg+xml;utf8,<svg width=\"16\" height=\"26\" viewBox=\"0 0 16 26\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M7 0h2v26H7z\" fill=\"%23D8D8D8\" fill-rule=\"evenodd\"/></svg>\\');\\n      }\\n      .lh-crc .lh-crc-tree {\\n    \\\n    font-size: 14px;\\n        width: 100%;\\n        overflow-x: auto;\\n      }\\n      .lh-crc .lh-crc-node {\\n        height: 26px;\\n        line-height: 26px;\\n        white-space: nowrap;\\n      }\\n      .lh-crc .lh-crc-node__longest {\\n        color: var(--color-average-secondary);\\n      }\\n      .lh-crc .lh-crc-node__tree-value {\\n        margin-left: 10px;\\n      }\\n      .lh-crc .lh-crc-node__tree-value div {\\n        display: inline;\\n      }\\n      .lh-crc .lh-crc-node__chain-duration {\\n        font-weight: 700;\\n      }\\n      .lh-crc .lh-crc-initial-nav {\\n        color: #595959;\\n        font-style: italic;\\n      }\\n      .lh-crc__summary-value {\\n        margin-bottom: 10px;\\n      }\\n    `);let r=o.createElement(\"div\"),i=o.createElement(\"div\",\"lh-crc__summary-value\"),a=o.createElement(\"span\",\"lh-crc__longest_duration_label\"),l=o.createElement(\"b\",\"lh-crc__longest_duration\");i.append(\" \",a,\" \",l,\" \"),r.append(\" \",i,\" \");let s=o.createElement(\"div\",\"lh-crc\"),c=o.createElement(\"div\",\"lh-crc-initial-n\\\nav\");return s.append(\" \",c,\" \",\" \"),t.append(\" \",n,\" \",r,\" \",s,\" \"),e.append(t),e}function Je(o){let e=o.createFragment(),t=o.createElement(\"div\",\"lh-crc-node\"),n=o.createElement(\"span\",\"lh-crc-node__tree-marker\"),r=o.createElement(\"span\",\"lh-crc-node__tree-value\");return t.append(\" \",n,\" \",r,\" \"),e.append(t),e}function Ze(o){let e=o.createFragment(),t=o.createElement(\"div\",\"lh-element-screenshot\"),n=o.createElement(\"div\",\"lh-element-screenshot__content\"),r=o.createElement(\"div\",\"lh-element-screenshot__image\"),i=o.createElement(\"div\",\"lh-element-screenshot__mask\"),a=o.createElementNS(\"http://www.w3.org/2000/svg\",\"svg\");a.setAttribute(\"height\",\"0\"),a.setAttribute(\"width\",\"0\");let l=o.createElementNS(\"http://www.w3.org/2000/svg\",\"defs\"),s=o.createElementNS(\"http://www.w3.org/2000/svg\",\"clipPath\");s.setAttribute(\"clipPathUnits\",\"objectBoundingBox\"),l.append(\" \",s,\" \",\" \"),a.append(\" \",l,\" \"),i.append(\" \",a,\" \");let c=o.createElement(\"div\",\"lh-element-screenshot__element-marker\");return r.\\\nappend(\" \",i,\" \",c,\" \"),n.append(\" \",r,\" \"),t.append(\" \",n,\" \"),e.append(t),e}function Qe(o){let e=o.createFragment(),t=o.createElement(\"div\",\"lh-exp-gauge-component\"),n=o.createElement(\"div\",\"lh-exp-gauge__wrapper\");n.setAttribute(\"target\",\"_blank\");let r=o.createElement(\"div\",\"lh-exp-gauge__svg-wrapper\"),i=o.createElementNS(\"http://www.w3.org/2000/svg\",\"svg\",\"lh-exp-gauge\"),a=o.createElementNS(\"http://www.w3.org/2000/svg\",\"g\",\"lh-exp-gauge__inner\"),l=o.createElementNS(\"http://www.w3.org/2000/svg\",\"circle\",\"lh-exp-gauge__bg\"),s=o.createElementNS(\"http://www.w3.org/2000/svg\",\"circle\",\"lh-exp-gauge__base lh-exp-gauge--faded\"),c=o.createElementNS(\"http://www.w3.org/2000/svg\",\"circle\",\"lh-exp-gauge__arc\"),d=o.createElementNS(\"http://www.w3.org/2000/svg\",\"text\",\"lh-exp-gauge__percentage\");a.append(\" \",l,\" \",s,\" \",c,\" \",d,\" \");let h=o.createElementNS(\"http://www.w3.org/2000/svg\",\"g\",\"lh-exp-gauge__outer\"),p=o.createElementNS(\"http://www.w3.org/2000/svg\",\"circle\",\"lh-cover\");h.append(\" \",p,\"\\\n \");let g=o.createElementNS(\"http://www.w3.org/2000/svg\",\"text\",\"lh-exp-gauge__label\");return g.setAttribute(\"text-anchor\",\"middle\"),g.setAttribute(\"x\",\"0\"),g.setAttribute(\"y\",\"60\"),i.append(\" \",a,\" \",h,\" \",g,\" \"),r.append(\" \",i,\" \"),n.append(\" \",r,\" \"),t.append(\" \",n,\" \"),e.append(t),e}function Ye(o){let e=o.createFragment(),t=o.createElement(\"style\");t.append(`\\n    .lh-footer {\\n      padding: var(--footer-padding-vertical) calc(var(--default-padding) * 2);\\n      max-width: var(--report-content-max-width);\\n      margin: 0 auto;\\n    }\\n    .lh-footer .lh-generated {\\n      text-align: center;\\n    }\\n  `),e.append(t);let n=o.createElement(\"footer\",\"lh-footer\"),r=o.createElement(\"ul\",\"lh-meta__items\");r.append(\" \");let i=o.createElement(\"div\",\"lh-generated\"),a=o.createElement(\"b\");a.append(\"Lighthouse\");let l=o.createElement(\"span\",\"lh-footer__version\"),s=o.createElement(\"a\",\"lh-footer__version_issue\");return s.setAttribute(\"href\",\"https://github.com/GoogleChrome/Lighthouse/issues\"),s.setAt\\\ntribute(\"target\",\"_blank\"),s.setAttribute(\"rel\",\"noopener\"),s.append(\"File an issue\"),i.append(\" \",\" Generated by \",a,\" \",l,\" | \",s,\" \"),n.append(\" \",r,\" \",i,\" \"),e.append(n),e}function Xe(o){let e=o.createFragment(),t=o.createElement(\"a\",\"lh-fraction__wrapper\"),n=o.createElement(\"div\",\"lh-fraction__content-wrapper\"),r=o.createElement(\"div\",\"lh-fraction__content\"),i=o.createElement(\"div\",\"lh-fraction__background\");r.append(\" \",i,\" \"),n.append(\" \",r,\" \");let a=o.createElement(\"div\",\"lh-fraction__label\");return t.append(\" \",n,\" \",a,\" \"),e.append(t),e}function et(o){let e=o.createFragment(),t=o.createElement(\"a\",\"lh-gauge__wrapper\"),n=o.createElement(\"div\",\"lh-gauge__svg-wrapper\"),r=o.createElementNS(\"http://www.w3.org/2000/svg\",\"svg\",\"lh-gauge\");r.setAttribute(\"viewBox\",\"0 0 120 120\");let i=o.createElementNS(\"http://www.w3.org/2000/svg\",\"circle\",\"lh-gauge-base\");i.setAttribute(\"r\",\"56\"),i.setAttribute(\"cx\",\"60\"),i.setAttribute(\"cy\",\"60\"),i.setAttribute(\"stroke-width\",\"8\");let a=o.createE\\\nlementNS(\"http://www.w3.org/2000/svg\",\"circle\",\"lh-gauge-arc\");a.setAttribute(\"r\",\"56\"),a.setAttribute(\"cx\",\"60\"),a.setAttribute(\"cy\",\"60\"),a.setAttribute(\"stroke-width\",\"8\"),r.append(\" \",i,\" \",a,\" \"),n.append(\" \",r,\" \");let l=o.createElement(\"div\",\"lh-gauge__percentage\"),s=o.createElement(\"div\",\"lh-gauge__label\");return t.append(\" \",\" \",n,\" \",l,\" \",\" \",s,\" \"),e.append(t),e}function tt(o){let e=o.createFragment(),t=o.createElement(\"style\");t.append(`\\n    /* CSS Fireworks. Originally by Eddie Lin\\n       https://codepen.io/paulirish/pen/yEVMbP\\n    */\\n    .lh-pyro {\\n      display: none;\\n      z-index: 1;\\n      pointer-events: none;\\n    }\\n    .lh-score100 .lh-pyro {\\n      display: block;\\n    }\\n    .lh-score100 .lh-lighthouse stop:first-child {\\n      stop-color: hsla(200, 12%, 95%, 0);\\n    }\\n    .lh-score100 .lh-lighthouse stop:last-child {\\n      stop-color: hsla(65, 81%, 76%, 1);\\n    }\\n\\n    .lh-pyro > .lh-pyro-before, .lh-pyro > .lh-pyro-after {\\n      position: absolute;\\n      width: 5px;\\n\\\n      height: 5px;\\n      border-radius: 2.5px;\\n      box-shadow: 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff, 0 0 #fff;\\n      animation: 1s bang ease-out infinite backwards,  1s gravity ease-in infinite backwards,  5s position linear infinite backwards;\\n      animation-delay: 1s, 1s, 1s;\\n    }\\n\\n    .lh-pyro > .lh-pyro-after {\\n      animation-delay: 2.25s, 2.25s, 2.25s;\\n      animation-duration: 1.25s, 1.25s, 6.25s;\\n    }\\n\\n    @keyframes bang {\\n      to {\\n        opacity: 1;\\n        box-shadow: -70px -115.67px #47ebbc, -28px -99.67px #eb47a\\\n4, 58px -31.67px #7eeb47, 13px -141.67px #eb47c5, -19px 6.33px #7347eb, -2px -74.67px #ebd247, 24px -151.67px #eb47e0, 57px -138.67px #b4eb47, -51px -104.67px #479eeb, 62px 8.33px #ebcf47, -93px 0.33px #d547eb, -16px -118.67px #47bfeb, 53px -84.67px #47eb83, 66px -57.67px #eb47bf, -93px -65.67px #91eb47, 30px -13.67px #86eb47, -2px -59.67px #83eb47, -44px 1.33px #eb47eb, 61px -58.67px #47eb73, 5px -22.67px #47e8eb, -66px -28.67px #ebe247, 42px -123.67px #eb5547, -75px 26.33px #7beb47, 15px -52.67px #a147eb, 36px -51.67px #eb8347, -38px -12.67px #eb5547, -46px -59.67px #47eb81, 78px -114.67px #eb47ba, 15px -156.67px #eb47bf, -36px 1.33px #eb4783, -72px -86.67px #eba147, 31px -46.67px #ebe247, -68px 29.33px #47e2eb, -55px 19.33px #ebe047, -56px 27.33px #4776eb, -13px -91.67px #eb5547, -47px -138.67px #47ebc7, -18px -96.67px #eb47ac, 11px -88.67px #4783eb, -67px -28.67px #47baeb, 53px 10.33px #ba47eb, 11px 19.33px #5247eb, -5px -11.67px #eb4791, -68px -4.67px #47eba7, 95px -37.67px #eb478\\\nb, -67px -162.67px #eb5d47, -54px -120.67px #eb6847, 49px -12.67px #ebe047, 88px 8.33px #47ebda, 97px 33.33px #eb8147, 6px -71.67px #ebbc47;\\n      }\\n    }\\n    @keyframes gravity {\\n      from {\\n        opacity: 1;\\n      }\\n      to {\\n        transform: translateY(80px);\\n        opacity: 0;\\n      }\\n    }\\n    @keyframes position {\\n      0%, 19.9% {\\n        margin-top: 4%;\\n        margin-left: 47%;\\n      }\\n      20%, 39.9% {\\n        margin-top: 7%;\\n        margin-left: 30%;\\n      }\\n      40%, 59.9% {\\n        margin-top: 6%;\\n        margin-left: 70%;\\n      }\\n      60%, 79.9% {\\n        margin-top: 3%;\\n        margin-left: 20%;\\n      }\\n      80%, 99.9% {\\n        margin-top: 3%;\\n        margin-left: 80%;\\n      }\\n    }\\n  `),e.append(t);let n=o.createElement(\"div\",\"lh-header-container\"),r=o.createElement(\"div\",\"lh-scores-wrapper-placeholder\");return n.append(\" \",r,\" \"),e.append(n),e}function nt(o){let e=o.createFragment(),t=o.createElement(\"div\",\"lh-metric\"),n=o.createElement(\"div\",\"lh-metric__in\\\nnerwrap\"),r=o.createElement(\"div\",\"lh-metric__icon\"),i=o.createElement(\"span\",\"lh-metric__title\"),a=o.createElement(\"div\",\"lh-metric__value\"),l=o.createElement(\"div\",\"lh-metric__description\");return n.append(\" \",r,\" \",i,\" \",a,\" \",l,\" \"),t.append(\" \",n,\" \"),e.append(t),e}function rt(o){let e=o.createFragment(),t=o.createElement(\"div\",\"lh-scorescale\"),n=o.createElement(\"span\",\"lh-scorescale-range lh-scorescale-range--fail\");n.append(\"0\\\\u201349\");let r=o.createElement(\"span\",\"lh-scorescale-range lh-scorescale-range--average\");r.append(\"50\\\\u201389\");let i=o.createElement(\"span\",\"lh-scorescale-range lh-scorescale-range--pass\");return i.append(\"90\\\\u2013100\"),t.append(\" \",n,\" \",r,\" \",i,\" \"),e.append(t),e}function ot(o){let e=o.createFragment(),t=o.createElement(\"style\");t.append(`\\n    .lh-scores-container {\\n      display: flex;\\n      flex-direction: column;\\n      padding: var(--default-padding) 0;\\n      position: relative;\\n      width: 100%;\\n    }\\n\\n    .lh-sticky-header {\\n      --gauge-circle\\\n-size: var(--gauge-circle-size-sm);\\n      --plugin-badge-size: 16px;\\n      --plugin-icon-size: 75%;\\n      --gauge-wrapper-width: 60px;\\n      --gauge-percentage-font-size: 13px;\\n      position: fixed;\\n      left: 0;\\n      right: 0;\\n      top: var(--topbar-height);\\n      font-weight: 500;\\n      display: none;\\n      justify-content: center;\\n      background-color: var(--sticky-header-background-color);\\n      border-bottom: 1px solid var(--color-gray-200);\\n      padding-top: var(--score-container-padding);\\n      padding-bottom: 4px;\\n      z-index: 2;\\n      pointer-events: none;\\n    }\\n\\n    .lh-devtools .lh-sticky-header {\\n      /* The report within DevTools is placed in a container with overflow, which changes the placement of this header unless we change \\\\`position\\\\` to \\\\`sticky.\\\\` */\\n      position: sticky;\\n    }\\n\\n    .lh-sticky-header--visible {\\n      display: grid;\\n      grid-auto-flow: column;\\n      pointer-events: auto;\\n    }\\n\\n    /* Disable the gauge arc animation for the sticky head\\\ner, so toggling display: none\\n       does not play the animation. */\\n    .lh-sticky-header .lh-gauge-arc {\\n      animation: none;\\n    }\\n\\n    .lh-sticky-header .lh-gauge__label,\\n    .lh-sticky-header .lh-fraction__label {\\n      display: none;\\n    }\\n\\n    .lh-highlighter {\\n      width: var(--gauge-wrapper-width);\\n      height: 1px;\\n      background-color: var(--highlighter-background-color);\\n      /* Position at bottom of first gauge in sticky header. */\\n      position: absolute;\\n      grid-column: 1;\\n      bottom: -1px;\\n      left: 0px;\\n      right: 0px;\\n    }\\n  `),e.append(t);let n=o.createElement(\"div\",\"lh-scores-wrapper\"),r=o.createElement(\"div\",\"lh-scores-container\"),i=o.createElement(\"div\",\"lh-pyro\"),a=o.createElement(\"div\",\"lh-pyro-before\"),l=o.createElement(\"div\",\"lh-pyro-after\");return i.append(\" \",a,\" \",l,\" \"),r.append(\" \",i,\" \"),n.append(\" \",r,\" \"),e.append(n),e}function it(o){let e=o.createFragment(),t=o.createElement(\"div\",\"lh-snippet\"),n=o.createElement(\"style\");return n.app\\\nend(`\\n          :root {\\n            --snippet-highlight-light: #fbf1f2;\\n            --snippet-highlight-dark: #ffd6d8;\\n          }\\n\\n         .lh-snippet__header {\\n          position: relative;\\n          overflow: hidden;\\n          padding: 10px;\\n          border-bottom: none;\\n          color: var(--snippet-color);\\n          background-color: var(--snippet-background-color);\\n          border: 1px solid var(--report-border-color-secondary);\\n        }\\n        .lh-snippet__title {\\n          font-weight: bold;\\n          float: left;\\n        }\\n        .lh-snippet__node {\\n          float: left;\\n          margin-left: 4px;\\n        }\\n        .lh-snippet__toggle-expand {\\n          padding: 1px 7px;\\n          margin-top: -1px;\\n          margin-right: -7px;\\n          float: right;\\n          background: transparent;\\n          border: none;\\n          cursor: pointer;\\n          font-size: 14px;\\n          color: #0c50c7;\\n        }\\n\\n        .lh-snippet__snippet {\\n          overflow: auto;\\n          bor\\\nder: 1px solid var(--report-border-color-secondary);\\n        }\\n        /* Container needed so that all children grow to the width of the scroll container */\\n        .lh-snippet__snippet-inner {\\n          display: inline-block;\\n          min-width: 100%;\\n        }\\n\\n        .lh-snippet:not(.lh-snippet--expanded) .lh-snippet__show-if-expanded {\\n          display: none;\\n        }\\n        .lh-snippet.lh-snippet--expanded .lh-snippet__show-if-collapsed {\\n          display: none;\\n        }\\n\\n        .lh-snippet__line {\\n          background: white;\\n          white-space: pre;\\n          display: flex;\\n        }\\n        .lh-snippet__line:not(.lh-snippet__line--message):first-child {\\n          padding-top: 4px;\\n        }\\n        .lh-snippet__line:not(.lh-snippet__line--message):last-child {\\n          padding-bottom: 4px;\\n        }\\n        .lh-snippet__line--content-highlighted {\\n          background: var(--snippet-highlight-dark);\\n        }\\n        .lh-snippet__line--message {\\n          background\\\n: var(--snippet-highlight-light);\\n        }\\n        .lh-snippet__line--message .lh-snippet__line-number {\\n          padding-top: 10px;\\n          padding-bottom: 10px;\\n        }\\n        .lh-snippet__line--message code {\\n          padding: 10px;\\n          padding-left: 5px;\\n          color: var(--color-fail);\\n          font-family: var(--report-font-family);\\n        }\\n        .lh-snippet__line--message code {\\n          white-space: normal;\\n        }\\n        .lh-snippet__line-icon {\\n          padding-top: 10px;\\n          display: none;\\n        }\\n        .lh-snippet__line--message .lh-snippet__line-icon {\\n          display: block;\\n        }\\n        .lh-snippet__line-icon:before {\\n          content: \"\";\\n          display: inline-block;\\n          vertical-align: middle;\\n          margin-right: 4px;\\n          width: var(--score-icon-size);\\n          height: var(--score-icon-size);\\n          background-image: var(--fail-icon-url);\\n        }\\n        .lh-snippet__line-number {\\n          flex-shr\\\nink: 0;\\n          width: 40px;\\n          text-align: right;\\n          font-family: monospace;\\n          padding-right: 5px;\\n          margin-right: 5px;\\n          color: var(--color-gray-600);\\n          user-select: none;\\n        }\\n    `),t.append(\" \",n,\" \"),e.append(t),e}function at(o){let e=o.createFragment(),t=o.createElement(\"div\",\"lh-snippet__snippet\"),n=o.createElement(\"div\",\"lh-snippet__snippet-inner\");return t.append(\" \",n,\" \"),e.append(t),e}function lt(o){let e=o.createFragment(),t=o.createElement(\"div\",\"lh-snippet__header\"),n=o.createElement(\"div\",\"lh-snippet__title\"),r=o.createElement(\"div\",\"lh-snippet__node\"),i=o.createElement(\"button\",\"lh-snippet__toggle-expand\"),a=o.createElement(\"span\",\"lh-snippet__btn-label-collapse lh-snippet__show-if-expanded\"),l=o.createElement(\"span\",\"lh-snippet__btn-label-expand lh-snippet__show-if-collapsed\");return i.append(\" \",a,\" \",l,\" \"),t.append(\" \",n,\" \",r,\" \",i,\" \"),e.append(t),e}function st(o){let e=o.createFragment(),t=o.createElement(\"di\\\nv\",\"lh-snippet__line\"),n=o.createElement(\"div\",\"lh-snippet__line-number\"),r=o.createElement(\"div\",\"lh-snippet__line-icon\"),i=o.createElement(\"code\");return t.append(\" \",n,\" \",r,\" \",i,\" \"),e.append(t),e}function ct(o){let e=o.createFragment(),t=o.createElement(\"style\");return t.append(`/**\\n * @license\\n * Copyright 2017 Google LLC\\n * SPDX-License-Identifier: Apache-2.0\\n */\\n\\n/*\\n  Naming convention:\\n\\n  If a variable is used for a specific component: --{component}-{property name}-{modifier}\\n\\n  Both {component} and {property name} should be kebab-case. If the target is the entire page,\\n  use \\'report\\' for the component. The property name should not be abbreviated. Use the\\n  property name the variable is intended for - if it\\'s used for multiple, a common descriptor\\n  is fine (ex: \\'size\\' for a variable applied to \\'width\\' and \\'height\\'). If a variable is shared\\n  across multiple components, either create more variables or just drop the \"{component}-\"\\n  part of the name. Append any modifiers at th\\\ne end (ex: \\'big\\', \\'dark\\').\\n\\n  For colors: --color-{hue}-{intensity}\\n\\n  {intensity} is the Material Design tag - 700, A700, etc.\\n*/\\n.lh-vars {\\n  /* Palette using Material Design Colors\\n   * https://www.materialui.co/colors */\\n  --color-amber-50: #FFF8E1;\\n  --color-blue-200: #90CAF9;\\n  --color-blue-900: #0D47A1;\\n  --color-blue-A700: #2962FF;\\n  --color-blue-primary: #06f;\\n  --color-cyan-500: #00BCD4;\\n  --color-gray-100: #F5F5F5;\\n  --color-gray-300: #CFCFCF;\\n  --color-gray-200: #E0E0E0;\\n  --color-gray-400: #BDBDBD;\\n  --color-gray-50: #FAFAFA;\\n  --color-gray-500: #9E9E9E;\\n  --color-gray-600: #757575;\\n  --color-gray-700: #616161;\\n  --color-gray-800: #424242;\\n  --color-gray-900: #212121;\\n  --color-gray: #000000;\\n  --color-green-700: #080;\\n  --color-green: #0c6;\\n  --color-lime-400: #D3E156;\\n  --color-orange-50: #FFF3E0;\\n  --color-orange-700: #C33300;\\n  --color-orange: #fa3;\\n  --color-red-700: #c00;\\n  --color-red: #f33;\\n  --color-teal-600: #00897B;\\n  --color-white: #FFFFFF;\\n\\n  /* Context-specif\\\nic colors */\\n  --color-average-secondary: var(--color-orange-700);\\n  --color-average: var(--color-orange);\\n  --color-fail-secondary: var(--color-red-700);\\n  --color-fail: var(--color-red);\\n  --color-hover: var(--color-gray-50);\\n  --color-informative: var(--color-blue-900);\\n  --color-pass-secondary: var(--color-green-700);\\n  --color-pass: var(--color-green);\\n  --color-not-applicable: var(--color-gray-600);\\n\\n  /* Component variables */\\n  --audit-description-padding-left: calc(var(--score-icon-size) + var(--score-icon-margin-left) + var(--score-icon-margin-right));\\n  --audit-explanation-line-height: 16px;\\n  --audit-group-margin-bottom: calc(var(--default-padding) * 6);\\n  --audit-group-padding-vertical: 8px;\\n  --audit-margin-horizontal: 5px;\\n  --audit-padding-vertical: 8px;\\n  --category-padding: calc(var(--default-padding) * 6) var(--edge-gap-padding) calc(var(--default-padding) * 4);\\n  --chevron-line-stroke: var(--color-gray-600);\\n  --chevron-size: 12px;\\n  --default-padding: 8px;\\n  --edge\\\n-gap-padding: calc(var(--default-padding) * 4);\\n  --env-item-background-color: var(--color-gray-100);\\n  --env-item-font-size: 28px;\\n  --env-item-line-height: 36px;\\n  --env-item-padding: 10px 0px;\\n  --env-name-min-width: 220px;\\n  --footer-padding-vertical: 16px;\\n  --gauge-circle-size-big: 96px;\\n  --gauge-circle-size: 48px;\\n  --gauge-circle-size-sm: 32px;\\n  --gauge-label-font-size-big: 18px;\\n  --gauge-label-font-size: var(--report-font-size-secondary);\\n  --gauge-label-line-height-big: 24px;\\n  --gauge-label-line-height: var(--report-line-height-secondary);\\n  --gauge-percentage-font-size-big: 38px;\\n  --gauge-percentage-font-size: var(--report-font-size-secondary);\\n  --gauge-wrapper-width: 120px;\\n  --header-line-height: 24px;\\n  --highlighter-background-color: var(--report-text-color);\\n  --icon-square-size: calc(var(--score-icon-size) * 0.88);\\n  --image-preview-size: 48px;\\n  --link-color: var(--color-blue-primary);\\n  --locale-selector-background-color: var(--color-white);\\n  --metric-toggle-l\\\nines-fill: #7F7F7F;\\n  --metric-value-font-size: calc(var(--report-font-size) * 1.8);\\n  --metrics-toggle-background-color: var(--color-gray-200);\\n  --plugin-badge-background-color: var(--color-white);\\n  --plugin-badge-size-big: calc(var(--gauge-circle-size-big) / 2.7);\\n  --plugin-badge-size: calc(var(--gauge-circle-size) / 2.7);\\n  --plugin-icon-size: 65%;\\n  --report-background-color: #fff;\\n  --report-border-color-secondary: #ebebeb;\\n  --report-font-family-monospace: monospace, \\'Roboto Mono\\', \\'Menlo\\', \\'dejavu sans mono\\', \\'Consolas\\', \\'Lucida Console\\';\\n  --report-font-family: system-ui, Roboto, Helvetica, Arial, sans-serif;\\n  --report-font-size: 14px;\\n  --report-font-size-secondary: 12px;\\n  --report-icon-size: var(--score-icon-background-size);\\n  --report-line-height: 24px;\\n  --report-line-height-secondary: 20px;\\n  --report-monospace-font-size: calc(var(--report-font-size) * 0.85);\\n  --report-text-color-secondary: var(--color-gray-800);\\n  --report-text-color: var(--color-gray-900);\\n  --rep\\\nort-content-max-width: calc(60 * var(--report-font-size)); /* defaults to 840px */\\n  --report-content-min-width: 360px;\\n  --report-content-max-width-minus-edge-gap: calc(var(--report-content-max-width) - var(--edge-gap-padding) * 2);\\n  --score-container-padding: 8px;\\n  --score-icon-background-size: 24px;\\n  --score-icon-margin-left: 6px;\\n  --score-icon-margin-right: 14px;\\n  --score-icon-margin: 0 var(--score-icon-margin-right) 0 var(--score-icon-margin-left);\\n  --score-icon-size: 12px;\\n  --score-icon-size-big: 16px;\\n  --screenshot-overlay-background: rgba(0, 0, 0, 0.3);\\n  --section-padding-vertical: calc(var(--default-padding) * 6);\\n  --snippet-background-color: var(--color-gray-50);\\n  --snippet-color: #0938C2;\\n  --stackpack-padding-horizontal: 10px;\\n  --sticky-header-background-color: var(--report-background-color);\\n  --sticky-header-buffer: var(--topbar-height);\\n  --sticky-header-height: calc(var(--gauge-circle-size-sm) + var(--score-container-padding) * 2 + 1em);\\n  --table-group-head\\\ner-background-color: #EEF1F4;\\n  --table-group-header-text-color: var(--color-gray-700);\\n  --table-higlight-background-color: #F5F7FA;\\n  --tools-icon-color: var(--color-gray-600);\\n  --topbar-background-color: var(--color-white);\\n  --topbar-height: 32px;\\n  --topbar-logo-size: 24px;\\n  --topbar-padding: 0 8px;\\n  --toplevel-warning-background-color: hsla(30, 100%, 75%, 10%);\\n  --toplevel-warning-message-text-color: var(--color-average-secondary);\\n  --toplevel-warning-padding: 18px;\\n  --toplevel-warning-text-color: var(--report-text-color);\\n\\n  /* SVGs */\\n  --plugin-icon-url-dark: url(\\'data:image/svg+xml;utf8,<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24px\" height=\"24px\" viewBox=\"0 0 24 24\" fill=\"%23FFFFFF\"><path d=\"M0 0h24v24H0z\" fill=\"none\"/><path d=\"M20.5 11H19V7c0-1.1-.9-2-2-2h-4V3.5C13 2.12 11.88 1 10.5 1S8 2.12 8 3.5V5H4c-1.1 0-1.99.9-1.99 2v3.8H3.5c1.49 0 2.7 1.21 2.7 2.7s-1.21 2.7-2.7 2.7H2V20c0 1.1.9 2 2 2h3.8v-1.5c0-1.49 1.21-2.7 2.7-2.7 1.49 0 2.7 1.21 2.7 2.7V22H17c1.1 0 2-.9 \\\n2-2v-4h1.5c1.38 0 2.5-1.12 2.5-2.5S21.88 11 20.5 11z\"/></svg>\\');\\n  --plugin-icon-url: url(\\'data:image/svg+xml;utf8,<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24px\" height=\"24px\" viewBox=\"0 0 24 24\" fill=\"%23757575\"><path d=\"M0 0h24v24H0z\" fill=\"none\"/><path d=\"M20.5 11H19V7c0-1.1-.9-2-2-2h-4V3.5C13 2.12 11.88 1 10.5 1S8 2.12 8 3.5V5H4c-1.1 0-1.99.9-1.99 2v3.8H3.5c1.49 0 2.7 1.21 2.7 2.7s-1.21 2.7-2.7 2.7H2V20c0 1.1.9 2 2 2h3.8v-1.5c0-1.49 1.21-2.7 2.7-2.7 1.49 0 2.7 1.21 2.7 2.7V22H17c1.1 0 2-.9 2-2v-4h1.5c1.38 0 2.5-1.12 2.5-2.5S21.88 11 20.5 11z\"/></svg>\\');\\n\\n  --pass-icon-url: url(\\'data:image/svg+xml;utf8,<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 48 48\"><title>check</title><path fill=\"%23178239\" d=\"M24 4C12.95 4 4 12.95 4 24c0 11.04 8.95 20 20 20 11.04 0 20-8.96 20-20 0-11.05-8.96-20-20-20zm-4 30L10 24l2.83-2.83L20 28.34l15.17-15.17L38 16 20 34z\"/></svg>\\');\\n  --average-icon-url: url(\\'data:image/svg+xml;utf8,<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 48 48\"><t\\\nitle>info</title><path fill=\"%23E67700\" d=\"M24 4C12.95 4 4 12.95 4 24s8.95 20 20 20 20-8.95 20-20S35.05 4 24 4zm2 30h-4V22h4v12zm0-16h-4v-4h4v4z\"/></svg>\\');\\n  --fail-icon-url: url(\\'data:image/svg+xml;utf8,<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 48 48\"><title>warn</title><path fill=\"%23C7221F\" d=\"M2 42h44L24 4 2 42zm24-6h-4v-4h4v4zm0-8h-4v-8h4v8z\"/></svg>\\');\\n  --error-icon-url: url(\\'data:image/svg+xml;utf8,<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 3 15\"><title>error</title><path d=\"M0 15H 3V 12H 0V\" fill=\"%23FF4E42\"/><path d=\"M0 9H 3V 0H 0V\" fill=\"%23FF4E42\"/></svg>\\');\\n\\n  --swap-locale-icon-url: url(\\'data:image/svg+xml;utf8,<svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24px\" viewBox=\"0 0 24 24\" width=\"24px\" fill=\"%23000000\"><path d=\"M0 0h24v24H0V0z\" fill=\"none\"/><path d=\"M12.87 15.07l-2.54-2.51.03-.03c1.74-1.94 2.98-4.17 3.71-6.53H17V4h-7V2H8v2H1v1.99h11.17C11.5 7.92 10.44 9.75 9 11.35 8.07 10.32 7.3 9.19 6.69 8h-2c.73 1.63 1.73 3.17 2.98 4.56l-5.09 5.02L4 19l5\\\n-5 3.11 3.11.76-2.04zM18.5 10h-2L12 22h2l1.12-3h4.75L21 22h2l-4.5-12zm-2.62 7l1.62-4.33L19.12 17h-3.24z\"/></svg>\\');\\n}\\n\\n@media not print {\\n  .lh-dark {\\n    /* Pallete */\\n    --color-gray-200: var(--color-gray-800);\\n    --color-gray-300: #616161;\\n    --color-gray-400: var(--color-gray-600);\\n    --color-gray-700: var(--color-gray-400);\\n    --color-gray-50: #757575;\\n    --color-gray-600: var(--color-gray-500);\\n    --color-green-700: var(--color-green);\\n    --color-orange-700: var(--color-orange);\\n    --color-red-700: var(--color-red);\\n    --color-teal-600: var(--color-cyan-500);\\n\\n    /* Context-specific colors */\\n    --color-hover: rgba(0, 0, 0, 0.2);\\n    --color-informative: var(--color-blue-200);\\n\\n    /* Component variables */\\n    --env-item-background-color: #393535;\\n    --link-color: var(--color-blue-200);\\n    --locale-selector-background-color: var(--color-gray-200);\\n    --plugin-badge-background-color: var(--color-gray-800);\\n    --report-background-color: var(--color-gray-900);\\n    -\\\n-report-border-color-secondary: var(--color-gray-200);\\n    --report-text-color-secondary: var(--color-gray-400);\\n    --report-text-color: var(--color-gray-100);\\n    --snippet-color: var(--color-cyan-500);\\n    --topbar-background-color: var(--color-gray);\\n    --toplevel-warning-background-color: hsl(33deg 14% 18%);\\n    --toplevel-warning-message-text-color: var(--color-orange-700);\\n    --toplevel-warning-text-color: var(--color-gray-100);\\n    --table-group-header-background-color: rgba(186, 196, 206, 0.15);\\n    --table-group-header-text-color: var(--color-gray-100);\\n    --table-higlight-background-color: rgba(186, 196, 206, 0.09);\\n\\n    /* SVGs */\\n    --plugin-icon-url: var(--plugin-icon-url-dark);\\n  }\\n}\\n\\n/**\\n* This media query is a temporary fallback for browsers that do not support \\\\`@container query\\\\`.\\n* TODO: remove this media query when \\\\`@container query\\\\` is fully supported by browsers\\n* See https://github.com/GoogleChrome/lighthouse/pull/16332\\n*/\\n@media only screen and (max-width\\\n: 480px) {\\n  .lh-vars {\\n    --audit-group-margin-bottom: 20px;\\n    --edge-gap-padding: var(--default-padding);\\n    --env-name-min-width: 120px;\\n    --gauge-circle-size-big: 96px;\\n    --gauge-circle-size: 72px;\\n    --gauge-label-font-size-big: 22px;\\n    --gauge-label-font-size: 14px;\\n    --gauge-label-line-height-big: 26px;\\n    --gauge-label-line-height: 20px;\\n    --gauge-percentage-font-size-big: 34px;\\n    --gauge-percentage-font-size: 26px;\\n    --gauge-wrapper-width: 112px;\\n    --header-padding: 16px 0 16px 0;\\n    --image-preview-size: 24px;\\n    --plugin-icon-size: 75%;\\n    --report-font-size: 14px;\\n    --report-line-height: 20px;\\n    --score-icon-margin-left: 2px;\\n    --score-icon-size: 10px;\\n    --topbar-height: 28px;\\n    --topbar-logo-size: 20px;\\n  }\\n}\\n\\n@container lh-container (max-width: 480px) {\\n  .lh-vars {\\n    --audit-group-margin-bottom: 20px;\\n    --edge-gap-padding: var(--default-padding);\\n    --env-name-min-width: 120px;\\n    --gauge-circle-size-big: 96px;\\n    --gauge-circle-\\\nsize: 72px;\\n    --gauge-label-font-size-big: 22px;\\n    --gauge-label-font-size: 14px;\\n    --gauge-label-line-height-big: 26px;\\n    --gauge-label-line-height: 20px;\\n    --gauge-percentage-font-size-big: 34px;\\n    --gauge-percentage-font-size: 26px;\\n    --gauge-wrapper-width: 112px;\\n    --header-padding: 16px 0 16px 0;\\n    --image-preview-size: 24px;\\n    --plugin-icon-size: 75%;\\n    --report-font-size: 14px;\\n    --report-line-height: 20px;\\n    --score-icon-margin-left: 2px;\\n    --score-icon-size: 10px;\\n    --topbar-height: 28px;\\n    --topbar-logo-size: 20px;\\n  }\\n}\\n\\n.lh-vars.lh-devtools {\\n  --audit-explanation-line-height: 14px;\\n  --audit-group-margin-bottom: 20px;\\n  --audit-group-padding-vertical: 12px;\\n  --audit-padding-vertical: 4px;\\n  --category-padding: 12px;\\n  --default-padding: 12px;\\n  --env-name-min-width: 120px;\\n  --footer-padding-vertical: 8px;\\n  --gauge-circle-size-big: 72px;\\n  --gauge-circle-size: 64px;\\n  --gauge-label-font-size-big: 22px;\\n  --gauge-label-font-size: 14px;\\n  --\\\ngauge-label-line-height-big: 26px;\\n  --gauge-label-line-height: 20px;\\n  --gauge-percentage-font-size-big: 34px;\\n  --gauge-percentage-font-size: 26px;\\n  --gauge-wrapper-width: 97px;\\n  --header-line-height: 20px;\\n  --header-padding: 16px 0 16px 0;\\n  --screenshot-overlay-background: transparent;\\n  --plugin-icon-size: 75%;\\n  --report-font-size: 12px;\\n  --report-line-height: 20px;\\n  --score-icon-margin-left: 2px;\\n  --score-icon-size: 10px;\\n  --section-padding-vertical: 8px;\\n}\\n\\n.lh-devtools :focus-visible {\\n  outline: -webkit-focus-ring-color auto 1px;\\n}\\n\\n.lh-container:has(.lh-sticky-header) {\\n  --sticky-header-buffer: calc(var(--topbar-height) + var(--sticky-header-height));\\n}\\n\\n.lh-container:not(.lh-topbar + .lh-container) {\\n  --topbar-height: 0;\\n  --sticky-header-height: 0;\\n  --sticky-header-buffer: 0;\\n}\\n\\n.lh-max-viewport {\\n  display: flex;\\n  flex-direction: column;\\n  min-height: 100vh;\\n  width: 100%;\\n}\\n\\n.lh-devtools.lh-root {\\n  height: 100%;\\n}\\n.lh-devtools.lh-root img {\\n  /* Override devt\\\nools default \\'min-width: 0\\' so svg without size in a flexbox isn\\'t collapsed. */\\n  min-width: auto;\\n}\\n.lh-devtools .lh-container {\\n  overflow-y: scroll;\\n  height: calc(100% - var(--topbar-height));\\n  /** The .lh-container is the scroll parent in DevTools so we exclude the topbar from the sticky header buffer. */\\n  --sticky-header-buffer: 0;\\n}\\n.lh-devtools .lh-container:has(.lh-sticky-header) {\\n  /** The .lh-container is the scroll parent in DevTools so we exclude the topbar from the sticky header buffer. */\\n  --sticky-header-buffer: var(--sticky-header-height);\\n}\\n@media print {\\n  .lh-devtools .lh-container {\\n    overflow: unset;\\n  }\\n}\\n.lh-devtools .lh-sticky-header {\\n  /* This is normally the height of the topbar, but we want it to stick to the top of our scroll container .lh-container\\\\` */\\n  top: 0;\\n}\\n.lh-devtools .lh-element-screenshot__overlay {\\n  position: absolute;\\n}\\n\\n@keyframes fadeIn {\\n  0% { opacity: 0;}\\n  100% { opacity: 0.6;}\\n}\\n\\n.lh-root *, .lh-root *::before, .lh-root *::aft\\\ner {\\n  box-sizing: border-box;\\n}\\n\\n.lh-root {\\n  font-family: var(--report-font-family);\\n  font-size: var(--report-font-size);\\n  margin: 0;\\n  line-height: var(--report-line-height);\\n  background: var(--report-background-color);\\n  color: var(--report-text-color);\\n}\\n\\n.lh-root [hidden] {\\n  display: none !important;\\n}\\n\\n.lh-root pre {\\n  margin: 0;\\n}\\n\\n.lh-root pre,\\n.lh-root code {\\n  font-family: var(--report-font-family-monospace);\\n}\\n\\n.lh-root details > summary {\\n  cursor: pointer;\\n}\\n\\n.lh-hidden {\\n  display: none !important;\\n}\\n\\n.lh-container {\\n  /*\\n  Text wrapping in the report is so much FUN!\\n  We have a \\\\`word-break: break-word;\\\\` globally here to prevent a few common scenarios, namely\\n  long non-breakable text (usually URLs) found in:\\n    1. The footer\\n    2. .lh-node (outerHTML)\\n    3. .lh-code\\n\\n  With that sorted, the next challenge is appropriate column sizing and text wrapping inside our\\n  .lh-details tables. Even more fun.\\n    * We don\\'t want table headers (\"Est Savings (ms)\") to wrap \\\nor their column values, but\\n      we\\'d be happy for the URL column to wrap if the URLs are particularly long.\\n    * We want the narrow columns to remain narrow, providing the most column width for URL\\n    * We don\\'t want the table to extend past 100% width.\\n    * Long URLs in the URL column can wrap. Util.getURLDisplayName maxes them out at 64 characters,\\n      but they do not get any overflow:ellipsis treatment.\\n  */\\n  word-break: break-word;\\n\\n  container-name: lh-container;\\n  container-type: inline-size;\\n}\\n\\n.lh-audit-group a,\\n.lh-category-header__description a,\\n.lh-audit__description a,\\n.lh-warnings a,\\n.lh-footer a,\\n.lh-table-column--link a {\\n  color: var(--link-color);\\n}\\n\\n.lh-audit__description, .lh-audit__stackpack, .lh-list-section__description {\\n  --inner-audit-padding-right: var(--stackpack-padding-horizontal);\\n  padding-left: var(--audit-description-padding-left);\\n  padding-right: var(--inner-audit-padding-right);\\n  padding-top: 8px;\\n  padding-bottom: 8px;\\n}\\n\\n.lh-details {\\n  ma\\\nrgin-top: var(--default-padding);\\n  margin-bottom: var(--default-padding);\\n  margin-left: var(--audit-description-padding-left);\\n}\\n\\n.lh-audit__stackpack {\\n  display: flex;\\n  align-items: center;\\n}\\n\\n.lh-audit__stackpack__img {\\n  max-width: 30px;\\n  margin-right: var(--default-padding)\\n}\\n\\n/* Report header */\\n\\n.lh-report-icon {\\n  display: flex;\\n  align-items: center;\\n  padding: 10px 12px;\\n  cursor: pointer;\\n}\\n.lh-report-icon[disabled] {\\n  opacity: 0.3;\\n  pointer-events: none;\\n}\\n\\n.lh-report-icon::before {\\n  content: \"\";\\n  margin: 4px;\\n  background-repeat: no-repeat;\\n  width: var(--report-icon-size);\\n  height: var(--report-icon-size);\\n  opacity: 0.7;\\n  display: inline-block;\\n  vertical-align: middle;\\n}\\n.lh-report-icon:hover::before {\\n  opacity: 1;\\n}\\n.lh-dark .lh-report-icon::before {\\n  filter: invert(1);\\n}\\n.lh-report-icon--print::before {\\n  background-image: url(\\'data:image/svg+xml;utf8,<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><path d=\"M19 8H5c-1.66 \\\n0-3 1.34-3 3v6h4v4h12v-4h4v-6c0-1.66-1.34-3-3-3zm-3 11H8v-5h8v5zm3-7c-.55 0-1-.45-1-1s.45-1 1-1 1 .45 1 1-.45 1-1 1zm-1-9H6v4h12V3z\"/><path fill=\"none\" d=\"M0 0h24v24H0z\"/></svg>\\');\\n}\\n.lh-report-icon--copy::before {\\n  background-image: url(\\'data:image/svg+xml;utf8,<svg height=\"24\" viewBox=\"0 0 24 24\" width=\"24\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M0 0h24v24H0z\" fill=\"none\"/><path d=\"M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm3 4H8c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h11c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm0 16H8V7h11v14z\"/></svg>\\');\\n}\\n.lh-report-icon--open::before {\\n  background-image: url(\\'data:image/svg+xml;utf8,<svg height=\"24\" viewBox=\"0 0 24 24\" width=\"24\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M0 0h24v24H0z\" fill=\"none\"/><path d=\"M19 4H5c-1.11 0-2 .9-2 2v12c0 1.1.89 2 2 2h4v-2H5V8h14v10h-4v2h4c1.1 0 2-.9 2-2V6c0-1.1-.89-2-2-2zm-7 6l-4 4h3v6h2v-6h3l-4-4z\"/></svg>\\');\\n}\\n.lh-report-icon--download::before {\\n  background-image: url(\\'data:image/svg+xml;utf8,<svg height=\"24\" viewBox=\"0 0 \\\n24 24\" width=\"24\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M19 9h-4V3H9v6H5l7 7 7-7zM5 18v2h14v-2H5z\"/><path d=\"M0 0h24v24H0z\" fill=\"none\"/></svg>\\');\\n}\\n.lh-report-icon--dark::before {\\n  background-image:url(\\'data:image/svg+xml;utf8,<svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24\" viewBox=\"0 0 100 125\"><path d=\"M50 23.587c-16.27 0-22.799 12.574-22.799 21.417 0 12.917 10.117 22.451 12.436 32.471h20.726c2.32-10.02 12.436-19.554 12.436-32.471 0-8.843-6.528-21.417-22.799-21.417zM39.637 87.161c0 3.001 1.18 4.181 4.181 4.181h.426l.41 1.231C45.278 94.449 46.042 95 48.019 95h3.963c1.978 0 2.74-.551 3.365-2.427l.409-1.231h.427c3.002 0 4.18-1.18 4.18-4.181V80.91H39.637v6.251zM50 18.265c1.26 0 2.072-.814 2.072-2.073v-9.12C52.072 5.813 51.26 5 50 5c-1.259 0-2.072.813-2.072 2.073v9.12c0 1.259.813 2.072 2.072 2.072zM68.313 23.727c.994.774 2.135.634 2.91-.357l5.614-7.187c.776-.992.636-2.135-.356-2.909-.992-.776-2.135-.636-2.91.357l-5.613 7.186c-.778.993-.636 2.135.355 2.91zM91.157 36.373c-.306-1\\\n.222-1.291-1.815-2.513-1.51l-8.85 2.207c-1.222.305-1.814 1.29-1.51 2.512.305 1.223 1.291 1.814 2.513 1.51l8.849-2.206c1.223-.305 1.816-1.291 1.511-2.513zM86.757 60.48l-8.331-3.709c-1.15-.512-2.225-.099-2.736 1.052-.512 1.151-.1 2.224 1.051 2.737l8.33 3.707c1.15.514 2.225.101 2.736-1.05.513-1.149.1-2.223-1.05-2.737zM28.779 23.37c.775.992 1.917 1.131 2.909.357.992-.776 1.132-1.917.357-2.91l-5.615-7.186c-.775-.992-1.917-1.132-2.909-.357s-1.131 1.917-.356 2.909l5.614 7.187zM21.715 39.583c.305-1.223-.288-2.208-1.51-2.513l-8.849-2.207c-1.222-.303-2.208.289-2.513 1.511-.303 1.222.288 2.207 1.511 2.512l8.848 2.206c1.222.304 2.208-.287 2.513-1.509zM21.575 56.771l-8.331 3.711c-1.151.511-1.563 1.586-1.05 2.735.511 1.151 1.586 1.563 2.736 1.052l8.331-3.711c1.151-.511 1.563-1.586 1.05-2.735-.512-1.15-1.585-1.562-2.736-1.052z\"/></svg>\\');\\n}\\n.lh-report-icon--treemap::before {\\n  background-image: url(\\'data:image/svg+xml;utf8,<svg xmlns=\"http://www.w3.org/2000/svg\" height=\"24px\" viewBox=\"0 0 24 24\" widt\\\nh=\"24px\" fill=\"black\"><path d=\"M3 5v14h19V5H3zm2 2h15v4H5V7zm0 10v-4h4v4H5zm6 0v-4h9v4h-9z\"/></svg>\\');\\n}\\n\\n.lh-report-icon--date::before {\\n  background-image: url(\\'data:image/svg+xml;utf8,<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><path d=\"M7 11h2v2H7v-2zm14-5v14a2 2 0 01-2 2H5a2 2 0 01-2-2V6c0-1.1.9-2 2-2h1V2h2v2h8V2h2v2h1a2 2 0 012 2zM5 8h14V6H5v2zm14 12V10H5v10h14zm-4-7h2v-2h-2v2zm-4 0h2v-2h-2v2z\"/></svg>\\');\\n}\\n.lh-report-icon--devices::before {\\n  background-image: url(\\'data:image/svg+xml;utf8,<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><path d=\"M4 6h18V4H4a2 2 0 00-2 2v11H0v3h14v-3H4V6zm19 2h-6a1 1 0 00-1 1v10c0 .6.5 1 1 1h6c.6 0 1-.5 1-1V9c0-.6-.5-1-1-1zm-1 9h-4v-7h4v7z\"/></svg>\\');\\n}\\n.lh-report-icon--world::before {\\n  background-image: url(\\'data:image/svg+xml;utf8,<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><path d=\"M12 2a10 10 0 1 0 0 20 10 10 0 0 0 0-20zm7 6h-3c-.3-1.3-.8-2.5-1.4-3.6A8 8 0 0 1 18.9 8zm-7-4a14 14 0 0 1 2 4h-4a14 14 0\\\n 0 1 2-4zM4.3 14a8.2 8.2 0 0 1 0-4h3.3a16.5 16.5 0 0 0 0 4H4.3zm.8 2h3a14 14 0 0 0 1.3 3.6A8 8 0 0 1 5.1 16zm3-8H5a8 8 0 0 1 4.3-3.6L8 8zM12 20a14 14 0 0 1-2-4h4a14 14 0 0 1-2 4zm2.3-6H9.7a14.7 14.7 0 0 1 0-4h4.6a14.6 14.6 0 0 1 0 4zm.3 5.6c.6-1.2 1-2.4 1.4-3.6h3a8 8 0 0 1-4.4 3.6zm1.8-5.6a16.5 16.5 0 0 0 0-4h3.3a8.2 8.2 0 0 1 0 4h-3.3z\"/></svg>\\');\\n}\\n.lh-report-icon--stopwatch::before {\\n  background-image: url(\\'data:image/svg+xml;utf8,<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><path d=\"M15 1H9v2h6V1zm-4 13h2V8h-2v6zm8.1-6.6L20.5 6l-1.4-1.4L17.7 6A9 9 0 0 0 3 13a9 9 0 1 0 16-5.6zm-7 12.6a7 7 0 1 1 0-14 7 7 0 0 1 0 14z\"/></svg>\\');\\n}\\n.lh-report-icon--networkspeed::before {\\n  background-image: url(\\'data:image/svg+xml;utf8,<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><path d=\"M15.9 5c-.2 0-.3 0-.4.2v.2L10.1 17a2 2 0 0 0-.2 1 2 2 0 0 0 4 .4l2.4-12.9c0-.3-.2-.5-.5-.5zM1 9l2 2c2.9-2.9 6.8-4 10.5-3.6l1.2-2.7C10 3.8 4.7 5.3 1 9zm20 2 2-2a15.4 15.4 0 0 0-5.6-3.6L17\\\n 8.2c1.5.7 2.9 1.6 4.1 2.8zm-4 4 2-2a9.9 9.9 0 0 0-2.7-1.9l-.5 3 1.2.9zM5 13l2 2a7.1 7.1 0 0 1 4-2l1.3-2.9C9.7 10.1 7 11 5 13z\"/></svg>\\');\\n}\\n.lh-report-icon--samples-one::before {\\n  background-image: url(\\'data:image/svg+xml;utf8,<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><circle cx=\"7\" cy=\"14\" r=\"3\"/><path d=\"M7 18a4 4 0 1 1 0-8 4 4 0 0 1 0 8zm0-6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm4-2a4 4 0 1 1 0-8 4 4 0 0 1 0 8zm0-6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm5.6 17.6a4 4 0 1 1 0-8 4 4 0 0 1 0 8zm0-6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z\"/></svg>\\');\\n}\\n.lh-report-icon--samples-many::before {\\n  background-image: url(\\'data:image/svg+xml;utf8,<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><path d=\"M7 18a4 4 0 1 1 0-8 4 4 0 0 1 0 8zm0-6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm4-2a4 4 0 1 1 0-8 4 4 0 0 1 0 8zm0-6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm5.6 17.6a4 4 0 1 1 0-8 4 4 0 0 1 0 8zm0-6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z\"\\\n/><circle cx=\"7\" cy=\"14\" r=\"3\"/><circle cx=\"11\" cy=\"6\" r=\"3\"/></svg>\\');\\n}\\n.lh-report-icon--chrome::before {\\n  background-image: url(\\'data:image/svg+xml;utf8,<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"-50 -50 562 562\"><path d=\"M256 25.6v25.6a204 204 0 0 1 144.8 60 204 204 0 0 1 60 144.8 204 204 0 0 1-60 144.8 204 204 0 0 1-144.8 60 204 204 0 0 1-144.8-60 204 204 0 0 1-60-144.8 204 204 0 0 1 60-144.8 204 204 0 0 1 144.8-60V0a256 256 0 1 0 0 512 256 256 0 0 0 0-512v25.6z\"/><path d=\"M256 179.2v25.6a51.3 51.3 0 0 1 0 102.4 51.3 51.3 0 0 1 0-102.4v-51.2a102.3 102.3 0 1 0-.1 204.7 102.3 102.3 0 0 0 .1-204.7v25.6z\"/><path d=\"M256 204.8h217.6a25.6 25.6 0 0 0 0-51.2H256a25.6 25.6 0 0 0 0 51.2m44.3 76.8L191.5 470.1a25.6 25.6 0 1 0 44.4 25.6l108.8-188.5a25.6 25.6 0 1 0-44.4-25.6m-88.6 0L102.9 93.2a25.7 25.7 0 0 0-35-9.4 25.7 25.7 0 0 0-9.4 35l108.8 188.5a25.7 25.7 0 0 0 35 9.4 25.9 25.9 0 0 0 9.4-35.1\"/></svg>\\');\\n}\\n.lh-report-icon--external::before {\\n  background-image: url(\\'data:image/svg+x\\\nml;utf8,<svg xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M3.15 11.9a1.01 1.01 0 0 1-.743-.307 1.01 1.01 0 0 1-.306-.743v-7.7c0-.292.102-.54.306-.744a1.01 1.01 0 0 1 .744-.306H7v1.05H3.15v7.7h7.7V7h1.05v3.85c0 .291-.103.54-.307.743a1.01 1.01 0 0 1-.743.307h-7.7Zm2.494-2.8-.743-.744 5.206-5.206H8.401V2.1h3.5v3.5h-1.05V3.893L5.644 9.1Z\"/></svg>\\');\\n}\\n.lh-report-icon--experiment::before {\\n  background-image: url(\\'data:image/svg+xml;utf8,<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" fill=\"none\"><path d=\"M4.50002 17C3.86136 17 3.40302 16.7187 3.12502 16.156C2.84702 15.5933 2.90936 15.069 3.31202 14.583L7.50002 9.5V4.5H6.75002C6.54202 4.5 6.36502 4.427 6.21902 4.281C6.07302 4.135 6.00002 3.958 6.00002 3.75C6.00002 3.542 6.07302 3.365 6.21902 3.219C6.36502 3.073 6.54202 3 6.75002 3H13.25C13.458 3 13.635 3.073 13.781 3.219C13.927 3.365 14 3.542 14 3.75C14 3.958 13.927 4.135 13.781 4.281C13.635 4.427 13.458 4.5 13.25 4.5H12.5V9.5L16.688 14.583C17.0767 15.069 17.132 15.5933 16.854 16\\\n.156C16.5767 16.7187 16.1254 17 15.5 17H4.50002ZM4.50002 15.5H15.5L11 10V4.5H9.00002V10L4.50002 15.5Z\" fill=\"black\"/></svg>\\');\\n}\\n\\n/** These are still icons, but w/o the auto-color invert / opacity / etc. that come with .lh-report-icon */\\n\\n.lh-report-plain-icon {\\n  display: flex;\\n  align-items: center;\\n}\\n.lh-report-plain-icon::before {\\n  content: \"\";\\n  background-repeat: no-repeat;\\n  width: var(--report-icon-size);\\n  height: var(--report-icon-size);\\n  display: inline-block;\\n  margin-right: 5px;\\n}\\n\\n.lh-report-plain-icon--checklist-pass::before {\\n  --icon-url: url(\\'data:image/svg+xml;utf8,<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\"><path d=\"M8.938 13L13.896 8.062L12.833 7L8.938 10.875L7.167 9.125L6.104 10.188L8.938 13ZM10 18C8.90267 18 7.868 17.7917 6.896 17.375C5.924 16.9583 5.07333 16.3853 4.344 15.656C3.61467 14.9267 3.04167 14.076 2.625 13.104C2.20833 12.132 2 11.0973 2 10C2 8.88867 2.20833 7.85033 2.625 6.885C3.04167 5.92033 3.61467 5.07333 4.344 4.344C5.07333 3.61467\\\n 5.924 3.04167 6.896 2.625C7.868 2.20833 8.90267 2 10 2C11.1113 2 12.1497 2.20833 13.115 2.625C14.0797 3.04167 14.9267 3.61467 15.656 4.344C16.3853 5.07333 16.9583 5.92033 17.375 6.885C17.7917 7.85033 18 8.88867 18 10C18 11.0973 17.7917 12.132 17.375 13.104C16.9583 14.076 16.3853 14.9267 15.656 15.656C14.9267 16.3853 14.0797 16.9583 13.115 17.375C12.1497 17.7917 11.1113 18 10 18ZM10 16.5C11.8053 16.5 13.34 15.868 14.604 14.604C15.868 13.34 16.5 11.8053 16.5 10C16.5 8.19467 15.868 6.66 14.604 5.396C13.34 4.132 11.8053 3.5 10 3.5C8.19467 3.5 6.66 4.132 5.396 5.396C4.132 6.66 3.5 8.19467 3.5 10C3.5 11.8053 4.132 13.34 5.396 14.604C6.66 15.868 8.19467 16.5 10 16.5Z\" fill=\"black\"/></svg>\\');\\n  background-color: var(--color-pass);\\n  mask: var(--icon-url) center / contain no-repeat;\\n}\\n.lh-report-plain-icon--checklist-fail::before {\\n  --icon-url: url(\\'data:image/svg+xml;utf8,<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\"><path fill-rule=\"evenodd\" clip-rule=\"evenodd\" d=\"M17.5 10C17.\\\n5 14.1421 14.1421 17.5 10 17.5C5.85786 17.5 2.5 14.1421 2.5 10C2.5 5.85786 5.85786 2.5 10 2.5C14.1421 2.5 17.5 5.85786 17.5 10ZM16 10C16 13.3137 13.3137 16 10 16C8.6135 16 7.33683 15.5297 6.32083 14.7399L14.7399 6.32083C15.5297 7.33683 16 8.6135 16 10ZM5.26016 13.6793L13.6793 5.26016C12.6633 4.47033 11.3866 4 10 4C6.68629 4 4 6.68629 4 10C4 11.3866 4.47033 12.6633 5.26016 13.6793Z\" fill=\"black\"/></svg>\\');\\n  background-color: var(--color-fail);\\n  mask: var(--icon-url) center / contain no-repeat;\\n}\\n\\n.lh-buttons {\\n  display: flex;\\n  flex-wrap: wrap;\\n  margin: var(--default-padding) 0;\\n}\\n.lh-button {\\n  height: 32px;\\n  border: 1px solid var(--report-border-color-secondary);\\n  border-radius: 3px;\\n  color: var(--link-color);\\n  background-color: var(--report-background-color);\\n  margin: 5px;\\n}\\n\\n.lh-button:first-of-type {\\n  margin-left: 0;\\n}\\n\\n/* Node */\\n.lh-node {\\n  display: flow-root;\\n}\\n\\n.lh-node__snippet {\\n  font-family: var(--report-font-family-monospace);\\n  color: var(--snippet-color);\\n  fo\\\nnt-size: var(--report-monospace-font-size);\\n  line-height: 20px;\\n}\\n\\n.lh-checklist {\\n  list-style: none;\\n  padding: 0;\\n}\\n\\n.lh-checklist-item {\\n  margin: 10px 0 10px 0;\\n}\\n\\n/* Score */\\n\\n.lh-audit__score-icon {\\n  width: var(--score-icon-size);\\n  height: var(--score-icon-size);\\n  margin: var(--score-icon-margin);\\n}\\n\\n.lh-audit--pass .lh-audit__display-text {\\n  color: var(--color-pass-secondary);\\n}\\n.lh-audit--pass .lh-audit__score-icon,\\n.lh-scorescale-range--pass::before {\\n  border-radius: 100%;\\n  background: var(--color-pass);\\n}\\n\\n.lh-audit--average .lh-audit__display-text {\\n  color: var(--color-average-secondary);\\n}\\n.lh-audit--average .lh-audit__score-icon,\\n.lh-scorescale-range--average::before {\\n  background: var(--color-average);\\n  width: var(--icon-square-size);\\n  height: var(--icon-square-size);\\n}\\n\\n.lh-audit--fail .lh-audit__display-text {\\n  color: var(--color-fail-secondary);\\n}\\n.lh-audit--fail .lh-audit__score-icon,\\n.lh-audit--error .lh-audit__score-icon,\\n.lh-scorescale-range--fail::bef\\\nore {\\n  border-left: calc(var(--score-icon-size) / 2) solid transparent;\\n  border-right: calc(var(--score-icon-size) / 2) solid transparent;\\n  border-bottom: var(--score-icon-size) solid var(--color-fail);\\n}\\n\\n.lh-audit--error .lh-audit__score-icon,\\n.lh-metric--error .lh-metric__icon {\\n  background-image: var(--error-icon-url);\\n  background-repeat: no-repeat;\\n  background-position: center;\\n  border: none;\\n}\\n\\n.lh-gauge__wrapper--fail .lh-gauge--error {\\n  background-image: var(--error-icon-url);\\n  background-repeat: no-repeat;\\n  background-position: center;\\n  transform: scale(0.5);\\n  top: var(--score-container-padding);\\n}\\n\\n.lh-audit--manual .lh-audit__display-text,\\n.lh-audit--notapplicable .lh-audit__display-text {\\n  color: var(--color-gray-600);\\n}\\n.lh-audit--manual .lh-audit__score-icon,\\n.lh-audit--notapplicable .lh-audit__score-icon {\\n  border: calc(0.2 * var(--score-icon-size)) solid var(--color-gray-400);\\n  border-radius: 100%;\\n  background: none;\\n}\\n\\n.lh-audit--informative .lh-audit__\\\ndisplay-text {\\n  color: var(--color-gray-600);\\n}\\n\\n.lh-audit--informative .lh-audit__score-icon {\\n  border: calc(0.2 * var(--score-icon-size)) solid var(--color-gray-400);\\n  border-radius: 100%;\\n}\\n\\n.lh-audit__description,\\n.lh-audit__stackpack {\\n  color: var(--report-text-color-secondary);\\n}\\n.lh-audit__adorn {\\n  border: 1px solid var(--color-gray-500);\\n  border-radius: 3px;\\n  margin: 0 3px;\\n  padding: 0 2px;\\n  line-height: 1.1;\\n  display: inline-block;\\n  font-size: 90%;\\n  color: var(--report-text-color-secondary);\\n}\\n\\n.lh-category-header__description  {\\n  text-align: center;\\n  color: var(--color-gray-700);\\n  margin: 0px auto;\\n  max-width: 400px;\\n}\\n\\n\\n.lh-audit__display-text,\\n.lh-chevron-container {\\n  margin: 0 var(--audit-margin-horizontal);\\n}\\n.lh-chevron-container {\\n  margin-right: 0;\\n}\\n\\n.lh-audit__title-and-text {\\n  flex: 1;\\n}\\n\\n.lh-audit__title-and-text code {\\n  color: var(--snippet-color);\\n  font-size: var(--report-monospace-font-size);\\n}\\n\\n/* Prepend display text with em dash separator.\\\n */\\n.lh-audit__display-text:not(:empty):before {\\n  content: \\'\\\\u2014\\';\\n  margin-right: var(--audit-margin-horizontal);\\n}\\n\\n/* Expandable Details (Audit Groups, Audits) */\\n.lh-audit__header {\\n  display: flex;\\n  align-items: center;\\n  padding: var(--default-padding);\\n}\\n\\n\\n.lh-metricfilter {\\n  display: grid;\\n  justify-content: end;\\n  align-items: center;\\n  grid-auto-flow: column;\\n  gap: 4px;\\n  color: var(--color-gray-700);\\n}\\n\\n.lh-metricfilter__radio {\\n  /*\\n   * Instead of hiding, position offscreen so it\\'s still accessible to screen readers\\n   * https://bugs.chromium.org/p/chromium/issues/detail?id=1439785\\n   */\\n  position: fixed;\\n  left: -9999px;\\n}\\n.lh-metricfilter input[type=\\'radio\\']:focus-visible + label {\\n  outline: -webkit-focus-ring-color auto 1px;\\n}\\n\\n.lh-metricfilter__label {\\n  display: inline-flex;\\n  padding: 0 4px;\\n  height: 16px;\\n  text-decoration: underline;\\n  align-items: center;\\n  cursor: pointer;\\n  font-size: 90%;\\n}\\n\\n.lh-metricfilter__label--active {\\n  background: var(--color-b\\\nlue-primary);\\n  color: var(--color-white);\\n  border-radius: 3px;\\n  text-decoration: none;\\n}\\n/* Give the \\'All\\' choice a more muted display */\\n.lh-metricfilter__label--active[for=\"metric-All\"] {\\n  background-color: var(--color-blue-200) !important;\\n  color: black !important;\\n}\\n\\n.lh-metricfilter__text {\\n  margin-right: 8px;\\n}\\n\\n/* If audits are filtered, hide the itemcount for Passed Audits\\\\u2026 */\\n.lh-category--filtered .lh-audit-group .lh-audit-group__itemcount {\\n  display: none;\\n}\\n\\n\\n.lh-audit__header:hover {\\n  background-color: var(--color-hover);\\n}\\n\\n/* We want to hide the browser\\'s default arrow marker on summary elements. Admittedly, it\\'s complicated. */\\n.lh-root details > summary {\\n  /* Blink 89+ and Firefox will hide the arrow when display is changed from (new) default of \\\\`list-item\\\\` to block.  https://chromestatus.com/feature/6730096436051968*/\\n  display: block;\\n}\\n/* Safari and Blink <=88 require using the -webkit-details-marker selector */\\n.lh-root details > summary::-webkit-de\\\ntails-marker {\\n  display: none;\\n}\\n\\n/* Perf Metric */\\n\\n.lh-metrics-container {\\n  display: grid;\\n  grid-auto-rows: 1fr;\\n  grid-template-columns: 1fr 1fr;\\n  grid-column-gap: var(--report-line-height);\\n  margin-bottom: var(--default-padding);\\n}\\n\\n.lh-metric {\\n  border-top: 1px solid var(--report-border-color-secondary);\\n}\\n\\n.lh-category:not(.lh--hoisted-meta) .lh-metric:nth-last-child(-n+2) {\\n  border-bottom: 1px solid var(--report-border-color-secondary);\\n}\\n\\n.lh-metric__innerwrap {\\n  display: grid;\\n  /**\\n   * Icon -- Metric Name\\n   *      -- Metric Value\\n   */\\n  grid-template-columns: calc(var(--score-icon-size) + var(--score-icon-margin-left) + var(--score-icon-margin-right)) 1fr;\\n  align-items: center;\\n  padding: var(--default-padding);\\n}\\n\\n.lh-metric__details {\\n  order: -1;\\n}\\n\\n.lh-metric__title {\\n  flex: 1;\\n}\\n\\n.lh-calclink {\\n  padding-left: calc(1ex / 3);\\n}\\n\\n.lh-metric__description {\\n  display: none;\\n  grid-column-start: 2;\\n  grid-column-end: 4;\\n  color: var(--report-text-color-secondary)\\\n;\\n}\\n\\n.lh-metric__value {\\n  font-size: var(--metric-value-font-size);\\n  margin: calc(var(--default-padding) / 2) 0;\\n  white-space: nowrap; /* No wrapping between metric value and the icon */\\n  grid-column-start: 2;\\n}\\n\\n/**\\n* This media query is a temporary fallback for browsers that do not support \\\\`@container query\\\\`.\\n* TODO: remove this media query when \\\\`@container query\\\\` is fully supported by browsers\\n* See https://github.com/GoogleChrome/lighthouse/pull/16332\\n*/\\n@media screen and (max-width: 535px) {\\n  .lh-metrics-container {\\n    display: block;\\n  }\\n\\n  .lh-metric {\\n    border-bottom: none !important;\\n  }\\n  .lh-category:not(.lh--hoisted-meta) .lh-metric:nth-last-child(1) {\\n    border-bottom: 1px solid var(--report-border-color-secondary) !important;\\n  }\\n\\n  /* Change the grid to 3 columns for narrow viewport. */\\n  .lh-metric__innerwrap {\\n  /**\\n   * Icon -- Metric Name -- Metric Value\\n   */\\n    grid-template-columns: calc(var(--score-icon-size) + var(--score-icon-margin-left) + var(--\\\nscore-icon-margin-right)) 2fr 1fr;\\n  }\\n  .lh-metric__value {\\n    justify-self: end;\\n    grid-column-start: unset;\\n  }\\n}\\n\\n@container lh-container (max-width: 535px) {\\n  .lh-metrics-container {\\n    display: block;\\n  }\\n\\n  .lh-metric {\\n    border-bottom: none !important;\\n  }\\n  .lh-category:not(.lh--hoisted-meta) .lh-metric:nth-last-child(1) {\\n    border-bottom: 1px solid var(--report-border-color-secondary) !important;\\n  }\\n\\n  /* Change the grid to 3 columns for narrow viewport. */\\n  .lh-metric__innerwrap {\\n  /**\\n   * Icon -- Metric Name -- Metric Value\\n   */\\n    grid-template-columns: calc(var(--score-icon-size) + var(--score-icon-margin-left) + var(--score-icon-margin-right)) 2fr 1fr;\\n  }\\n  .lh-metric__value {\\n    justify-self: end;\\n    grid-column-start: unset;\\n  }\\n}\\n\\n/* No-JS toggle switch */\\n/* Keep this selector sync\\'d w/ \\\\`magicSelector\\\\` in report-ui-features-test.js */\\n .lh-metrics-toggle__input:checked ~ .lh-metrics-container .lh-metric__description {\\n  display: block;\\n}\\n\\n/* TODO \\\nget rid of the SVGS and clean up these some more */\\n.lh-metrics-toggle__input {\\n  opacity: 0;\\n  position: absolute;\\n  right: 0;\\n  top: 0px;\\n}\\n\\n.lh-metrics-toggle__input + div > label > .lh-metrics-toggle__labeltext--hide,\\n.lh-metrics-toggle__input:checked + div > label > .lh-metrics-toggle__labeltext--show {\\n  display: none;\\n}\\n.lh-metrics-toggle__input:checked + div > label > .lh-metrics-toggle__labeltext--hide {\\n  display: inline;\\n}\\n.lh-metrics-toggle__input:focus + div > label {\\n  outline: -webkit-focus-ring-color auto 3px;\\n}\\n\\n.lh-metrics-toggle__label {\\n  cursor: pointer;\\n  font-size: var(--report-font-size-secondary);\\n  line-height: var(--report-line-height-secondary);\\n  color: var(--color-gray-700);\\n}\\n\\n/* Pushes the metric description toggle button to the right. */\\n.lh-audit-group--metrics .lh-audit-group__header {\\n  display: flex;\\n  justify-content: space-between;\\n}\\n\\n.lh-metric__icon,\\n.lh-scorescale-range::before {\\n  content: \\'\\';\\n  width: var(--score-icon-size);\\n  height: var(--s\\\ncore-icon-size);\\n  display: inline-block;\\n  margin: var(--score-icon-margin);\\n}\\n\\n.lh-metric--pass .lh-metric__value {\\n  color: var(--color-pass-secondary);\\n}\\n.lh-metric--pass .lh-metric__icon {\\n  border-radius: 100%;\\n  background: var(--color-pass);\\n}\\n\\n.lh-metric--average .lh-metric__value {\\n  color: var(--color-average-secondary);\\n}\\n.lh-metric--average .lh-metric__icon {\\n  background: var(--color-average);\\n  width: var(--icon-square-size);\\n  height: var(--icon-square-size);\\n}\\n\\n.lh-metric--fail .lh-metric__value {\\n  color: var(--color-fail-secondary);\\n}\\n.lh-metric--fail .lh-metric__icon {\\n  border-left: calc(var(--score-icon-size) / 2) solid transparent;\\n  border-right: calc(var(--score-icon-size) / 2) solid transparent;\\n  border-bottom: var(--score-icon-size) solid var(--color-fail);\\n}\\n\\n.lh-metric--error .lh-metric__value,\\n.lh-metric--error .lh-metric__description {\\n  color: var(--color-fail-secondary);\\n}\\n\\n/* Filmstrip */\\n\\n.lh-filmstrip-container {\\n  /* smaller gap between metrics and\\\n filmstrip */\\n  margin: -8px auto 0 auto;\\n}\\n\\n.lh-filmstrip {\\n  display: flex;\\n  justify-content: space-between;\\n  justify-items: center;\\n  margin-bottom: var(--default-padding);\\n  width: 100%;\\n}\\n\\n.lh-filmstrip__frame {\\n  overflow: hidden;\\n  line-height: 0;\\n}\\n\\n.lh-filmstrip__thumbnail {\\n  border: 1px solid var(--report-border-color-secondary);\\n  max-height: 150px;\\n  max-width: 120px;\\n}\\n\\n.lh-dark .lh-perf-toggle-text {\\n  color: rgba(30, 164, 70, 1);\\n}\\n\\n.lh-perf-toggle-text a {\\n  color: var(--link-color);\\n}\\n\\n/* Audit */\\n\\n.lh-audit {\\n  border-bottom: 1px solid var(--report-border-color-secondary);\\n}\\n\\n/* Apply border-top to just the first audit. */\\n.lh-audit {\\n  border-top: 1px solid var(--report-border-color-secondary);\\n}\\n.lh-audit ~ .lh-audit {\\n  border-top: none;\\n}\\n\\n\\n.lh-audit--error .lh-audit__display-text {\\n  color: var(--color-fail-secondary);\\n}\\n\\n/* Audit Group */\\n\\n.lh-audit-group {\\n  margin-bottom: var(--audit-group-margin-bottom);\\n  position: relative;\\n}\\n.lh-audit-group--metrics {\\n \\\n margin-bottom: calc(var(--audit-group-margin-bottom) / 2);\\n}\\n\\n.lh-audit-group--metrics .lh-audit-group__summary {\\n  margin-top: 0;\\n  margin-bottom: 0;\\n}\\n\\n.lh-audit-group__summary {\\n  display: flex;\\n  justify-content: space-between;\\n  align-items: center;\\n}\\n\\n.lh-audit-group__header .lh-chevron {\\n  margin-top: calc((var(--report-line-height) - 5px) / 2);\\n}\\n\\n.lh-audit-group__header {\\n  letter-spacing: 0.8px;\\n  padding: var(--default-padding);\\n  padding-left: 0;\\n}\\n\\n.lh-audit-group__header, .lh-audit-group__summary {\\n  font-size: var(--report-font-size-secondary);\\n  line-height: var(--report-line-height-secondary);\\n  color: var(--color-gray-700);\\n}\\n\\n.lh-audit-group__title {\\n  text-transform: uppercase;\\n  font-weight: 500;\\n}\\n\\n.lh-audit-group__itemcount {\\n  color: var(--color-gray-600);\\n}\\n\\n.lh-audit-group__footer {\\n  color: var(--color-gray-600);\\n  display: block;\\n  margin-top: var(--default-padding);\\n}\\n\\n.lh-details,\\n.lh-category-header__description,\\n.lh-audit-group__footer {\\n  font-size: va\\\nr(--report-font-size-secondary);\\n  line-height: var(--report-line-height-secondary);\\n}\\n\\n.lh-audit-explanation {\\n  margin: var(--audit-padding-vertical) 0 calc(var(--audit-padding-vertical) / 2) var(--audit-margin-horizontal);\\n  line-height: var(--audit-explanation-line-height);\\n  display: inline-block;\\n}\\n\\n.lh-audit--fail .lh-audit-explanation {\\n  color: var(--color-fail-secondary);\\n}\\n\\n/* Report */\\n.lh-list {\\n  margin-right: calc(var(--default-padding) * 2);\\n}\\n.lh-list > :not(:last-child) {\\n  margin-bottom: calc(var(--default-padding) * 2);\\n  border-bottom: 1px solid #A8C7FA;\\n}\\n.lh-list-section {\\n  padding: calc(var(--default-padding) * 2) 0;\\n}\\n.lh-list-section__title {\\n  text-decoration: underline;\\n}\\n\\n.lh-header-container {\\n  display: block;\\n  margin: 0 auto;\\n  position: relative;\\n  word-wrap: break-word;\\n}\\n\\n.lh-header-container .lh-scores-wrapper {\\n  border-bottom: 1px solid var(--color-gray-200);\\n}\\n\\n\\n.lh-report {\\n  min-width: var(--report-content-min-width);\\n}\\n\\n.lh-exception {\\n  font\\\n-size: large;\\n}\\n\\n.lh-code {\\n  white-space: normal;\\n  margin-top: 0;\\n  font-size: var(--report-monospace-font-size);\\n}\\n\\n.lh-warnings {\\n  --item-margin: calc(var(--report-line-height) / 6);\\n  color: var(--color-average-secondary);\\n  margin: var(--audit-padding-vertical) 0;\\n  padding: var(--default-padding)\\n    var(--default-padding)\\n    var(--default-padding)\\n    calc(var(--audit-description-padding-left));\\n  background-color: var(--toplevel-warning-background-color);\\n}\\n.lh-warnings span {\\n  font-weight: bold;\\n}\\n\\n.lh-warnings--toplevel {\\n  --item-margin: calc(var(--header-line-height) / 4);\\n  color: var(--toplevel-warning-text-color);\\n  margin-left: auto;\\n  margin-right: auto;\\n  max-width: var(--report-content-max-width-minus-edge-gap);\\n  padding: var(--toplevel-warning-padding);\\n  border-radius: 8px;\\n}\\n\\n.lh-warnings__msg {\\n  color: var(--toplevel-warning-message-text-color);\\n  margin: 0;\\n}\\n\\n.lh-warnings ul {\\n  margin: 0;\\n}\\n.lh-warnings li {\\n  margin: var(--item-margin) 0;\\n}\\n.lh-warnings\\\n li:last-of-type {\\n  margin-bottom: 0;\\n}\\n\\n.lh-scores-header {\\n  display: flex;\\n  flex-wrap: wrap;\\n  justify-content: center;\\n}\\n.lh-scores-header__solo {\\n  padding: 0;\\n  border: 0;\\n}\\n\\n/* Gauge */\\n\\n.lh-gauge__wrapper--pass {\\n  color: var(--color-pass-secondary);\\n  fill: var(--color-pass);\\n  stroke: var(--color-pass);\\n}\\n\\n.lh-gauge__wrapper--average {\\n  color: var(--color-average-secondary);\\n  fill: var(--color-average);\\n  stroke: var(--color-average);\\n}\\n\\n.lh-gauge__wrapper--fail {\\n  color: var(--color-fail-secondary);\\n  fill: var(--color-fail);\\n  stroke: var(--color-fail);\\n}\\n\\n.lh-gauge__wrapper--not-applicable {\\n  color: var(--color-not-applicable);\\n  fill: var(--color-not-applicable);\\n  stroke: var(--color-not-applicable);\\n}\\n\\n.lh-fraction__wrapper .lh-fraction__content::before {\\n  content: \\'\\';\\n  height: var(--score-icon-size);\\n  width: var(--score-icon-size);\\n  margin: var(--score-icon-margin);\\n  display: inline-block;\\n}\\n.lh-fraction__wrapper--pass .lh-fraction__content {\\n  color: var(--\\\ncolor-pass-secondary);\\n}\\n.lh-fraction__wrapper--pass .lh-fraction__background {\\n  background-color: var(--color-pass);\\n}\\n.lh-fraction__wrapper--pass .lh-fraction__content::before {\\n  background-color: var(--color-pass);\\n  border-radius: 50%;\\n}\\n.lh-fraction__wrapper--average .lh-fraction__content {\\n  color: var(--color-average-secondary);\\n}\\n.lh-fraction__wrapper--average .lh-fraction__background,\\n.lh-fraction__wrapper--average .lh-fraction__content::before {\\n  background-color: var(--color-average);\\n}\\n.lh-fraction__wrapper--fail .lh-fraction__content {\\n  color: var(--color-fail);\\n}\\n.lh-fraction__wrapper--fail .lh-fraction__background {\\n  background-color: var(--color-fail);\\n}\\n.lh-fraction__wrapper--fail .lh-fraction__content::before {\\n  border-left: calc(var(--score-icon-size) / 2) solid transparent;\\n  border-right: calc(var(--score-icon-size) / 2) solid transparent;\\n  border-bottom: var(--score-icon-size) solid var(--color-fail);\\n}\\n.lh-fraction__wrapper--null .lh-fraction__content {\\n  \\\ncolor: var(--color-gray-700);\\n}\\n.lh-fraction__wrapper--null .lh-fraction__background {\\n  background-color: var(--color-gray-700);\\n}\\n.lh-fraction__wrapper--null .lh-fraction__content::before {\\n  border-radius: 50%;\\n  border: calc(0.2 * var(--score-icon-size)) solid var(--color-gray-700);\\n}\\n\\n.lh-fraction__background {\\n  position: absolute;\\n  height: 100%;\\n  width: 100%;\\n  border-radius: calc(var(--gauge-circle-size) / 2);\\n  opacity: 0.1;\\n  z-index: -1;\\n}\\n\\n.lh-fraction__content-wrapper {\\n  height: var(--gauge-circle-size);\\n  display: flex;\\n  align-items: center;\\n}\\n\\n.lh-fraction__content {\\n  display: flex;\\n  position: relative;\\n  align-items: center;\\n  justify-content: center;\\n  font-size: calc(0.3 * var(--gauge-circle-size));\\n  line-height: calc(0.4 * var(--gauge-circle-size));\\n  width: max-content;\\n  min-width: calc(1.5 * var(--gauge-circle-size));\\n  padding: calc(0.1 * var(--gauge-circle-size)) calc(0.2 * var(--gauge-circle-size));\\n  --score-icon-size: calc(0.21 * var(--gauge-circle-siz\\\ne));\\n  --score-icon-margin: 0 calc(0.15 * var(--gauge-circle-size)) 0 0;\\n}\\n\\n.lh-gauge {\\n  stroke-linecap: round;\\n  width: var(--gauge-circle-size);\\n  height: var(--gauge-circle-size);\\n}\\n\\n.lh-category .lh-gauge {\\n  --gauge-circle-size: var(--gauge-circle-size-big);\\n}\\n\\n.lh-gauge-base {\\n  opacity: 0.1;\\n}\\n\\n.lh-gauge-arc {\\n  fill: none;\\n  transform-origin: 50% 50%;\\n  animation: load-gauge var(--transition-length) ease both;\\n  animation-delay: 250ms;\\n}\\n\\n.lh-gauge__svg-wrapper {\\n  position: relative;\\n  height: var(--gauge-circle-size);\\n}\\n.lh-category .lh-gauge__svg-wrapper,\\n.lh-category .lh-fraction__wrapper {\\n  --gauge-circle-size: var(--gauge-circle-size-big);\\n}\\n\\n/* The plugin badge overlay */\\n.lh-gauge__wrapper--plugin .lh-gauge__svg-wrapper::before {\\n  width: var(--plugin-badge-size);\\n  height: var(--plugin-badge-size);\\n  background-color: var(--plugin-badge-background-color);\\n  background-image: var(--plugin-icon-url);\\n  background-repeat: no-repeat;\\n  background-size: var(--plugin-icon-\\\nsize);\\n  background-position: 58% 50%;\\n  content: \"\";\\n  position: absolute;\\n  right: -6px;\\n  bottom: 0px;\\n  display: block;\\n  z-index: 100;\\n  box-shadow: 0 0 4px rgba(0,0,0,.2);\\n  border-radius: 25%;\\n}\\n.lh-category .lh-gauge__wrapper--plugin .lh-gauge__svg-wrapper::before {\\n  width: var(--plugin-badge-size-big);\\n  height: var(--plugin-badge-size-big);\\n}\\n\\n@keyframes load-gauge {\\n  from { stroke-dasharray: 0 352; }\\n}\\n\\n.lh-gauge__percentage {\\n  width: 100%;\\n  height: var(--gauge-circle-size);\\n  line-height: var(--gauge-circle-size);\\n  position: absolute;\\n  font-family: var(--report-font-family-monospace);\\n  font-size: calc(var(--gauge-circle-size) * 0.34 + 1.3px);\\n  text-align: center;\\n  top: var(--score-container-padding);\\n}\\n\\n.lh-category .lh-gauge__percentage {\\n  --gauge-circle-size: var(--gauge-circle-size-big);\\n  --gauge-percentage-font-size: var(--gauge-percentage-font-size-big);\\n}\\n\\n.lh-gauge__wrapper,\\n.lh-fraction__wrapper {\\n  position: relative;\\n  display: flex;\\n  align-items: cent\\\ner;\\n  flex-direction: column;\\n  text-decoration: none;\\n  padding: var(--score-container-padding);\\n\\n  --transition-length: 1s;\\n\\n  /* Contain the layout style paint & layers during animation*/\\n  contain: content;\\n  will-change: opacity; /* Only using for layer promotion */\\n}\\n\\n.lh-gauge__label,\\n.lh-fraction__label {\\n  font-size: var(--gauge-label-font-size);\\n  font-weight: 500;\\n  line-height: var(--gauge-label-line-height);\\n  margin-top: 10px;\\n  text-align: center;\\n  color: var(--report-text-color);\\n  word-break: keep-all;\\n}\\n\\n/* TODO(#8185) use more BEM (.lh-gauge__label--big) instead of relying on descendant selector */\\n.lh-category .lh-gauge__label,\\n.lh-category .lh-fraction__label {\\n  --gauge-label-font-size: var(--gauge-label-font-size-big);\\n  --gauge-label-line-height: var(--gauge-label-line-height-big);\\n  margin-top: 14px;\\n}\\n\\n.lh-scores-header .lh-gauge__wrapper,\\n.lh-scores-header .lh-fraction__wrapper,\\n.lh-sticky-header .lh-gauge__wrapper,\\n.lh-sticky-header .lh-fraction__wrapper {\\n\\\n  width: var(--gauge-wrapper-width);\\n}\\n\\n.lh-scorescale {\\n  display: inline-flex;\\n\\n  gap: calc(var(--default-padding) * 4);\\n  margin: 16px auto 0 auto;\\n  font-size: var(--report-font-size-secondary);\\n  color: var(--color-gray-700);\\n\\n}\\n\\n.lh-scorescale-range {\\n  display: flex;\\n  align-items: center;\\n  font-family: var(--report-font-family-monospace);\\n  white-space: nowrap;\\n}\\n\\n.lh-category-header__finalscreenshot .lh-scorescale {\\n  border: 0;\\n  display: flex;\\n  justify-content: center;\\n}\\n\\n.lh-category-header__finalscreenshot .lh-scorescale-range {\\n  font-family: unset;\\n  font-size: 12px;\\n}\\n\\n.lh-scorescale-wrap {\\n  display: contents;\\n}\\n\\n/* Hide category score gauages if it\\'s a single category report */\\n.lh-header--solo-category .lh-scores-wrapper {\\n  display: none;\\n}\\n\\n\\n.lh-categories {\\n  width: 100%;\\n}\\n\\n.lh-category {\\n  padding: var(--category-padding);\\n  max-width: var(--report-content-max-width);\\n  margin: 0 auto;\\n\\n  scroll-margin-top: calc(var(--sticky-header-buffer) - 1em);\\n}\\n\\n.lh-categ\\\nory-wrapper {\\n  border-bottom: 1px solid var(--color-gray-200);\\n}\\n.lh-category-wrapper:last-of-type {\\n  border-bottom: 0;\\n}\\n\\n.lh-category-header {\\n  margin-bottom: var(--section-padding-vertical);\\n}\\n\\n.lh-category-header .lh-score__gauge {\\n  max-width: 400px;\\n  width: auto;\\n  margin: 0px auto;\\n}\\n\\n.lh-category-header__finalscreenshot {\\n  display: grid;\\n  grid-template: none / 1fr 1px 1fr;\\n  justify-items: center;\\n  align-items: center;\\n  gap: var(--report-line-height);\\n  min-height: 288px;\\n  margin-bottom: var(--default-padding);\\n}\\n\\n.lh-final-ss-image {\\n  /* constrain the size of the image to not be too large */\\n  max-height: calc(var(--gauge-circle-size-big) * 2.8);\\n  max-width: calc(var(--gauge-circle-size-big) * 3.5);\\n  border: 1px solid var(--color-gray-200);\\n  padding: 4px;\\n  border-radius: 3px;\\n  display: block;\\n}\\n\\n.lh-category-headercol--separator {\\n  background: var(--color-gray-200);\\n  width: 1px;\\n  height: var(--gauge-circle-size-big);\\n}\\n\\n/**\\n* This media query is a temporary f\\\nallback for browsers that do not support \\\\`@container query\\\\`.\\n* TODO: remove this media query when \\\\`@container query\\\\` is fully supported by browsers\\n* See https://github.com/GoogleChrome/lighthouse/pull/16332\\n*/\\n@media screen and (max-width: 780px) {\\n  .lh-category-header__finalscreenshot {\\n    grid-template: 1fr 1fr / none\\n  }\\n  .lh-category-headercol--separator {\\n    display: none;\\n  }\\n}\\n\\n@container lh-container (max-width: 780px) {\\n  .lh-category-header__finalscreenshot {\\n    grid-template: 1fr 1fr / none\\n  }\\n  .lh-category-headercol--separator {\\n    display: none;\\n  }\\n}\\n\\n/**\\n* This media query is a temporary fallback for browsers that do not support \\\\`@container query\\\\`.\\n* TODO: remove this media query when \\\\`@container query\\\\` is fully supported by browsers\\n* See https://github.com/GoogleChrome/lighthouse/pull/16332\\n*/\\n@media screen and (max-width: 964px) {\\n  .lh-report {\\n    margin-left: 0;\\n    width: 100%;\\n  }\\n}\\n\\n/* 964 fits the min-width of the filmstrip */\\n@container lh-con\\\ntainer (max-width: 964px) {\\n  .lh-report {\\n    margin-left: 0;\\n    width: 100%;\\n  }\\n}\\n\\n@media print {\\n  body {\\n    -webkit-print-color-adjust: exact; /* print background colors */\\n  }\\n  .lh-container {\\n    display: block;\\n  }\\n  .lh-report {\\n    margin-left: 0;\\n    padding-top: 0;\\n  }\\n  .lh-categories {\\n    margin-top: 0;\\n  }\\n  .lh-buttons, .lh-highlighter {\\n    /* hide stickyheader marker when printing. crbug.com/41486992 */\\n    display: none;\\n  }\\n}\\n\\n.lh-table {\\n  position: relative;\\n  border-collapse: separate;\\n  border-spacing: 0;\\n  /* Can\\'t assign padding to table, so shorten the width instead. */\\n  width: calc(100% - var(--audit-description-padding-left) - var(--stackpack-padding-horizontal));\\n  border: 1px solid var(--report-border-color-secondary);\\n}\\n\\n.lh-table thead th {\\n  position: sticky;\\n  top: var(--sticky-header-buffer);\\n  z-index: 1;\\n  background-color: var(--report-background-color);\\n  border-bottom: 1px solid var(--report-border-color-secondary);\\n  font-weight: normal;\\n \\\n color: var(--color-gray-600);\\n  /* See text-wrapping comment on .lh-container. */\\n  word-break: normal;\\n}\\n\\n.lh-row--group {\\n  background-color: var(--table-group-header-background-color);\\n}\\n\\n.lh-row--group td {\\n  font-weight: bold;\\n  font-size: 1.05em;\\n  color: var(--table-group-header-text-color);\\n}\\n\\n.lh-row--group td:first-child {\\n  display: block;\\n  min-width: max-content;\\n  font-weight: normal;\\n}\\n\\n.lh-row--group .lh-text {\\n  color: inherit;\\n  text-decoration: none;\\n  display: inline-block;\\n}\\n\\n.lh-row--group a.lh-link:hover {\\n  text-decoration: underline;\\n}\\n\\n.lh-row--group .lh-audit__adorn {\\n  text-transform: capitalize;\\n  font-weight: normal;\\n  padding: 2px 3px 1px 3px;\\n}\\n\\n.lh-row--group .lh-audit__adorn1p {\\n  color: var(--link-color);\\n  border-color: var(--link-color);\\n}\\n\\n.lh-row--group .lh-report-icon--external::before {\\n  content: \"\";\\n  background-repeat: no-repeat;\\n  width: 14px;\\n  height: 16px;\\n  opacity: 0.7;\\n  display: inline-block;\\n  vertical-align: middle;\\n}\\n\\n.lh-row--gro\\\nup .lh-report-icon--external {\\n  visibility: hidden;\\n}\\n\\n.lh-row--group:hover .lh-report-icon--external {\\n  visibility: visible;\\n}\\n\\n.lh-dark .lh-report-icon--external::before {\\n  filter: invert(1);\\n}\\n\\n/** Manages indentation of two-level and three-level nested adjacent rows */\\n\\n.lh-row--group ~ [data-entity]:not(.lh-row--group) td:first-child {\\n  padding-left: 20px;\\n}\\n\\n.lh-row--group ~ [data-entity]:not(.lh-row--group) ~ .lh-sub-item-row td:first-child {\\n  margin-left: 20px;\\n  padding-left: 10px;\\n  border-left: 1px solid #A8C7FA;\\n  display: block;\\n}\\n\\n.lh-row--even {\\n  background-color: var(--table-group-header-background-color);\\n}\\n.lh-row--hidden {\\n  display: none;\\n}\\n\\n.lh-table th,\\n.lh-table td {\\n  padding: var(--default-padding);\\n}\\n\\n.lh-table tr {\\n  vertical-align: middle;\\n}\\n\\n.lh-table tr:hover {\\n  background-color: var(--table-higlight-background-color);\\n}\\n\\n/* Looks unnecessary, but mostly for keeping the <th>s left-aligned */\\n.lh-table-column--text,\\n.lh-table-column--source-location,\\\n\\n.lh-table-column--url,\\n/* .lh-table-column--thumbnail, */\\n/* .lh-table-column--empty,*/\\n.lh-table-column--code,\\n.lh-table-column--node {\\n  text-align: left;\\n}\\n\\n.lh-table-column--code {\\n  min-width: 100px;\\n}\\n\\n.lh-table-column--bytes,\\n.lh-table-column--timespanMs,\\n.lh-table-column--ms,\\n.lh-table-column--numeric {\\n  text-align: right;\\n  word-break: normal;\\n}\\n\\n\\n\\n.lh-table .lh-table-column--thumbnail {\\n  width: var(--image-preview-size);\\n}\\n\\n.lh-table-column--url {\\n  min-width: 250px;\\n}\\n\\n.lh-table-column--text {\\n  min-width: 80px;\\n}\\n\\n/* Keep columns narrow if they follow the URL column */\\n/* 12% was determined to be a decent narrow width, but wide enough for column headings */\\n.lh-table-column--url + th.lh-table-column--bytes,\\n.lh-table-column--url + .lh-table-column--bytes + th.lh-table-column--bytes,\\n.lh-table-column--url + .lh-table-column--ms,\\n.lh-table-column--url + .lh-table-column--ms + th.lh-table-column--bytes,\\n.lh-table-column--url + .lh-table-column--bytes + th.lh-table-column--t\\\nimespanMs {\\n  width: 12%;\\n}\\n\\n/** Tweak styling for tables in insight audits. */\\n.lh-audit[id$=\"-insight\"] .lh-table {\\n  border: none;\\n}\\n\\n.lh-audit[id$=\"-insight\"] .lh-table thead th {\\n  font-weight: bold;\\n  color: unset;\\n}\\n\\n.lh-audit[id$=\"-insight\"] .lh-table th,\\n.lh-audit[id$=\"-insight\"] .lh-table td {\\n  padding: calc(var(--default-padding) / 2);\\n}\\n\\n.lh-audit[id$=\"-insight\"] .lh-table .lh-row--even,\\n.lh-audit[id$=\"-insight\"] .lh-table tr:not(.lh-row--group):hover {\\n  background-color: unset;\\n}\\n\\n.lh-text__url-host {\\n  display: inline;\\n}\\n\\n.lh-text__url-host {\\n  margin-left: calc(var(--report-font-size) / 2);\\n  opacity: 0.6;\\n  font-size: 90%\\n}\\n\\n.lh-thumbnail {\\n  object-fit: cover;\\n  width: var(--image-preview-size);\\n  height: var(--image-preview-size);\\n  display: block;\\n}\\n\\n.lh-unknown pre {\\n  overflow: scroll;\\n  border: solid 1px var(--color-gray-200);\\n}\\n\\n.lh-text__url > a {\\n  color: inherit;\\n  text-decoration: none;\\n}\\n\\n.lh-text__url > a:hover {\\n  text-decoration: underline dotted #999;\\n\\\n}\\n\\n.lh-sub-item-row {\\n  margin-left: 20px;\\n  margin-bottom: 0;\\n  color: var(--color-gray-700);\\n}\\n\\n.lh-sub-item-row td {\\n  padding-top: 4px;\\n  padding-bottom: 4px;\\n  padding-left: 20px;\\n}\\n\\n.lh-sub-item-row .lh-element-screenshot {\\n  zoom: 0.6;\\n}\\n\\n/* Chevron\\n   https://codepen.io/paulirish/pen/LmzEmK\\n */\\n.lh-chevron {\\n  --chevron-angle: 42deg;\\n  /* Edge doesn\\'t support transform: rotate(calc(...)), so we define it here */\\n  --chevron-angle-right: -42deg;\\n  width: var(--chevron-size);\\n  height: var(--chevron-size);\\n  margin-top: calc((var(--report-line-height) - 12px) / 2);\\n}\\n\\n.lh-chevron__lines {\\n  transition: transform 0.4s;\\n  transform: translateY(var(--report-line-height));\\n}\\n.lh-chevron__line {\\n stroke: var(--chevron-line-stroke);\\n stroke-width: var(--chevron-size);\\n stroke-linecap: square;\\n transform-origin: 50%;\\n transform: rotate(var(--chevron-angle));\\n transition: transform 300ms, stroke 300ms;\\n}\\n\\n.lh-expandable-details .lh-chevron__line-right,\\n.lh-expandable-details[open] .lh-ch\\\nevron__line-left {\\n transform: rotate(var(--chevron-angle-right));\\n}\\n\\n.lh-expandable-details[open] .lh-chevron__line-right {\\n  transform: rotate(var(--chevron-angle));\\n}\\n\\n\\n.lh-expandable-details[open]  .lh-chevron__lines {\\n transform: translateY(calc(var(--chevron-size) * -1));\\n}\\n\\n.lh-expandable-details[open] {\\n  animation: 300ms openDetails forwards;\\n  padding-bottom: var(--default-padding);\\n}\\n\\n@keyframes openDetails {\\n  from {\\n    outline: 1px solid var(--report-background-color);\\n  }\\n  to {\\n   outline: 1px solid;\\n   box-shadow: 0 2px 4px rgba(0, 0, 0, .24);\\n  }\\n}\\n\\n/**\\n* This media query is a temporary fallback for browsers that do not support \\\\`@container query\\\\`.\\n* TODO: remove this media query when \\\\`@container query\\\\` is fully supported by browsers\\n* See https://github.com/GoogleChrome/lighthouse/pull/16332\\n*/\\n@media screen and (max-width: 780px) {\\n  /* no black outline if we\\'re not confident the entire table can be displayed within bounds */\\n  .lh-expandable-details[open] {\\n    \\\nanimation: none;\\n  }\\n}\\n\\n@container lh-container (max-width: 780px) {\\n  /* no black outline if we\\'re not confident the entire table can be displayed within bounds */\\n  .lh-expandable-details[open] {\\n    animation: none;\\n  }\\n}\\n\\n.lh-expandable-details[open] summary, details.lh-clump > summary {\\n  border-bottom: 1px solid var(--report-border-color-secondary);\\n}\\ndetails.lh-clump[open] > summary {\\n  border-bottom-width: 0;\\n}\\n\\n\\n\\ndetails .lh-clump-toggletext--hide,\\ndetails[open] .lh-clump-toggletext--show { display: none; }\\ndetails[open] .lh-clump-toggletext--hide { display: block;}\\n\\n\\n/* Tooltip */\\n.lh-tooltip-boundary {\\n  position: relative;\\n}\\n\\n.lh-tooltip {\\n  position: absolute;\\n  display: none; /* Don\\'t retain these layers when not needed */\\n  opacity: 0;\\n  background: #ffffff;\\n  white-space: pre-line; /* Render newlines in the text */\\n  min-width: 246px;\\n  max-width: 275px;\\n  padding: 15px;\\n  border-radius: 5px;\\n  text-align: initial;\\n  line-height: 1.4;\\n}\\n\\n/**\\n* This media query is a temp\\\norary fallback for browsers that do not support \\\\`@container query\\\\`.\\n* TODO: remove this media query when \\\\`@container query\\\\` is fully supported by browsers\\n* See https://github.com/GoogleChrome/lighthouse/pull/16332\\n*/\\n@media screen and (max-width: 535px) {\\n  .lh-tooltip {\\n    min-width: 45cqi;\\n    padding: 3cqi;\\n  }\\n}\\n\\n/* shrink tooltips to not be cutoff on left edge of narrow container\\n   45vw is chosen to be ~= width of the left column of metrics\\n*/\\n@container lh-container (max-width: 535px) {\\n  .lh-tooltip {\\n    min-width: 45cqi;\\n    padding: 3cqi;\\n  }\\n}\\n\\n.lh-tooltip-boundary:hover .lh-tooltip {\\n  display: block;\\n  animation: fadeInTooltip 250ms;\\n  animation-fill-mode: forwards;\\n  animation-delay: 850ms;\\n  bottom: 100%;\\n  z-index: 1;\\n  will-change: opacity;\\n  right: 0;\\n  pointer-events: none;\\n}\\n\\n.lh-tooltip::before {\\n  content: \"\";\\n  border: solid transparent;\\n  border-bottom-color: #fff;\\n  border-width: 10px;\\n  position: absolute;\\n  bottom: -20px;\\n  right: 6px;\\n  transform: rot\\\nate(180deg);\\n  pointer-events: none;\\n}\\n\\n@keyframes fadeInTooltip {\\n  0% { opacity: 0; }\\n  75% { opacity: 1; }\\n  100% { opacity: 1;  filter: drop-shadow(1px 0px 1px #aaa) drop-shadow(0px 2px 4px hsla(206, 6%, 25%, 0.15)); pointer-events: auto; }\\n}\\n\\n/* Element screenshot */\\n.lh-element-screenshot {\\n  float: left;\\n  margin-right: 20px;\\n}\\n.lh-element-screenshot__content {\\n  overflow: hidden;\\n  min-width: 110px;\\n  display: flex;\\n  justify-content: center;\\n  background-color: var(--report-background-color);\\n}\\n.lh-element-screenshot__image {\\n  position: relative;\\n  /* Set by ElementScreenshotRenderer.installFullPageScreenshotCssVariable */\\n  background-image: var(--element-screenshot-url);\\n  outline: 2px solid #777;\\n  background-color: white;\\n  background-repeat: no-repeat;\\n}\\n.lh-element-screenshot__mask {\\n  position: absolute;\\n  background: #555;\\n  opacity: 0.8;\\n}\\n.lh-element-screenshot__element-marker {\\n  position: absolute;\\n  outline: 2px solid var(--color-lime-400);\\n}\\n.lh-element-screensh\\\not__overlay {\\n  position: fixed;\\n  top: 0;\\n  left: 0;\\n  right: 0;\\n  bottom: 0;\\n  z-index: 2000; /* .lh-topbar is 1000 */\\n  background: var(--screenshot-overlay-background);\\n  display: flex;\\n  align-items: center;\\n  justify-content: center;\\n  cursor: zoom-out;\\n}\\n\\n.lh-element-screenshot__overlay .lh-element-screenshot {\\n  margin-right: 0; /* clearing margin used in thumbnail case */\\n  outline: 1px solid var(--color-gray-700);\\n}\\n\\n.lh-screenshot-overlay--enabled .lh-element-screenshot {\\n  cursor: zoom-out;\\n}\\n.lh-screenshot-overlay--enabled .lh-node .lh-element-screenshot {\\n  cursor: zoom-in;\\n}\\n\\n\\n.lh-meta__items {\\n  --meta-icon-size: calc(var(--report-icon-size) * 0.667);\\n  padding: var(--default-padding);\\n  display: grid;\\n  grid-template-columns: 1fr 1fr 1fr;\\n  background-color: var(--env-item-background-color);\\n  border-radius: 3px;\\n  margin: 0 0 var(--default-padding) 0;\\n  font-size: 12px;\\n  column-gap: var(--default-padding);\\n  color: var(--color-gray-700);\\n}\\n\\n.lh-meta__item {\\n  display\\\n: block;\\n  list-style-type: none;\\n  position: relative;\\n  padding: 0 0 0 calc(var(--meta-icon-size) + var(--default-padding) * 2);\\n  cursor: unset; /* disable pointer cursor from report-icon */\\n}\\n\\n.lh-meta__item.lh-tooltip-boundary {\\n  text-decoration: dotted underline var(--color-gray-500);\\n  cursor: help;\\n}\\n\\n.lh-meta__item.lh-report-icon::before {\\n  position: absolute;\\n  left: var(--default-padding);\\n  width: var(--meta-icon-size);\\n  height: var(--meta-icon-size);\\n}\\n\\n.lh-meta__item.lh-report-icon:hover::before {\\n  opacity: 0.7;\\n}\\n\\n.lh-meta__item .lh-tooltip {\\n  color: var(--color-gray-800);\\n}\\n\\n.lh-meta__item .lh-tooltip::before {\\n  right: auto; /* Set the tooltip arrow to the leftside */\\n  left: 6px;\\n}\\n\\n.lh-meta__item:hover .lh-tooltip {\\n  right: auto;\\n  left: 6px;\\n}\\n/**\\n* This media query is a temporary fallback for browsers that do not support \\\\`@container query\\\\`.\\n* TODO: remove this media query when \\\\`@container query\\\\` is fully supported by browsers\\n* See https://github.com/Goog\\\nleChrome/lighthouse/pull/16332\\n*/\\n@media screen and (max-width: 640px) {\\n  .lh-meta__items {\\n    grid-template-columns: 1fr 1fr;\\n  }\\n}\\n\\n/* Change the grid for narrow container */\\n@container lh-container (max-width: 640px) {\\n  .lh-meta__items {\\n    grid-template-columns: 1fr 1fr;\\n  }\\n}\\n\\n/**\\n* This media query is a temporary fallback for browsers that do not support \\\\`@container query\\\\`.\\n* TODO: remove this media query when \\\\`@container query\\\\` is fully supported by browsers\\n* See https://github.com/GoogleChrome/lighthouse/pull/16332\\n*/\\n@media screen and (max-width: 535px) {\\n  .lh-meta__items {\\n    display: block;\\n  }\\n}\\n\\n@container lh-container (max-width: 535px) {\\n  .lh-meta__items {\\n    display: block;\\n  }\\n}\\n\\n/* Explodey gauge */\\n\\n.lh-exp-gauge-component {\\n  margin-bottom: 10px;\\n}\\n\\n.lh-exp-gauge-component circle {\\n  stroke: currentcolor;\\n  r: var(--radius);\\n}\\n\\n.lh-exp-gauge-component text {\\n  font-size: calc(var(--radius) * 0.2);\\n}\\n\\n.lh-exp-gauge-component .lh-exp-gauge {\\n  margin: 0 a\\\nuto;\\n  width: 225px;\\n  stroke-width: var(--stroke-width);\\n  stroke-linecap: round;\\n\\n  /* for better rendering perf */\\n  contain: strict;\\n  height: 225px;\\n  will-change: transform;\\n}\\n.lh-exp-gauge-component .lh-exp-gauge--faded {\\n  opacity: 0.1;\\n}\\n.lh-exp-gauge-component .lh-exp-gauge__wrapper {\\n  font-family: var(--report-font-family-monospace);\\n  text-align: center;\\n  text-decoration: none;\\n  transition: .3s;\\n}\\n.lh-exp-gauge-component .lh-exp-gauge__wrapper--pass {\\n  color: var(--color-pass);\\n}\\n.lh-exp-gauge-component .lh-exp-gauge__wrapper--average {\\n  color: var(--color-average);\\n}\\n.lh-exp-gauge-component .lh-exp-gauge__wrapper--fail {\\n  color: var(--color-fail);\\n}\\n.lh-exp-gauge-component .state--expanded {\\n  transition: color .3s;\\n}\\n.lh-exp-gauge-component .state--highlight {\\n  color: var(--color-highlight);\\n}\\n.lh-exp-gauge-component .lh-exp-gauge__svg-wrapper {\\n  display: flex;\\n  flex-direction: column-reverse;\\n}\\n\\n.lh-exp-gauge-component .lh-exp-gauge__label {\\n  fill: var(--report\\\n-text-color);\\n  font-family: var(--report-font-family);\\n  font-size: 12px;\\n}\\n\\n.lh-exp-gauge-component .lh-exp-gauge__cutout {\\n  opacity: .999;\\n  transition: opacity .3s;\\n}\\n.lh-exp-gauge-component .state--highlight .lh-exp-gauge__cutout {\\n  opacity: 0;\\n}\\n\\n.lh-exp-gauge-component .lh-exp-gauge__inner {\\n  color: inherit;\\n}\\n.lh-exp-gauge-component .lh-exp-gauge__base {\\n  fill: currentcolor;\\n}\\n\\n\\n.lh-exp-gauge-component .lh-exp-gauge__arc {\\n  fill: none;\\n  transition: opacity .3s;\\n}\\n.lh-exp-gauge-component .lh-exp-gauge__arc--metric {\\n  color: var(--metric-color);\\n  stroke-dashoffset: var(--metric-offset);\\n  opacity: 0.3;\\n}\\n.lh-exp-gauge-component .lh-exp-gauge-hovertarget {\\n  color: currentcolor;\\n  opacity: 0.001;\\n  stroke-linecap: butt;\\n  stroke-width: 24;\\n  /* hack. move the hover target out of the center. ideally i tweak the r instead but that rquires considerably more math. */\\n  transform: scale(1.15);\\n}\\n.lh-exp-gauge-component .lh-exp-gauge__arc--metric.lh-exp-gauge--miniarc {\\n  opacit\\\ny: 0;\\n  stroke-dasharray: 0 calc(var(--circle-meas) * var(--radius));\\n  transition: 0s .005s;\\n}\\n.lh-exp-gauge-component .state--expanded .lh-exp-gauge__arc--metric.lh-exp-gauge--miniarc {\\n  opacity: .999;\\n  stroke-dasharray: var(--metric-array);\\n  transition: 0.3s; /*  calc(.005s + var(--i)*.05s); entrace animation */\\n}\\n.lh-exp-gauge-component .state--expanded .lh-exp-gauge__inner .lh-exp-gauge__arc {\\n  opacity: 0;\\n}\\n\\n\\n.lh-exp-gauge-component .lh-exp-gauge__percentage {\\n  text-anchor: middle;\\n  dominant-baseline: middle;\\n  opacity: .999;\\n  font-size: calc(var(--radius) * 0.625);\\n  transition: opacity .3s ease-in;\\n}\\n.lh-exp-gauge-component .state--highlight .lh-exp-gauge__percentage {\\n  opacity: 0;\\n}\\n\\n.lh-exp-gauge-component .lh-exp-gauge__wrapper--fail .lh-exp-gauge__percentage {\\n  fill: var(--color-fail);\\n}\\n.lh-exp-gauge-component .lh-exp-gauge__wrapper--average .lh-exp-gauge__percentage {\\n  fill: var(--color-average);\\n}\\n.lh-exp-gauge-component .lh-exp-gauge__wrapper--pass .lh-exp-gau\\\nge__percentage {\\n  fill: var(--color-pass);\\n}\\n\\n.lh-exp-gauge-component .lh-cover {\\n  fill: none;\\n  opacity: .001;\\n  pointer-events: none;\\n}\\n.lh-exp-gauge-component .state--expanded .lh-cover {\\n  pointer-events: auto;\\n}\\n\\n.lh-exp-gauge-component .metric {\\n  transform: scale(var(--scale-initial));\\n  opacity: 0;\\n  transition: transform .1s .2s ease-out,  opacity .3s ease-out;\\n  pointer-events: none;\\n}\\n.lh-exp-gauge-component .metric text {\\n  pointer-events: none;\\n}\\n.lh-exp-gauge-component .metric__value {\\n  fill: currentcolor;\\n  opacity: 0;\\n  transition: opacity 0.2s;\\n}\\n.lh-exp-gauge-component .state--expanded .metric {\\n  transform: scale(1);\\n  opacity: .999;\\n  transition: transform .3s ease-out,  opacity .3s ease-in,  stroke-width .1s ease-out;\\n  transition-delay: calc(var(--i)*.05s);\\n  pointer-events: auto;\\n}\\n.lh-exp-gauge-component .state--highlight .metric {\\n  opacity: .3;\\n}\\n.lh-exp-gauge-component .state--highlight .metric--highlight {\\n  opacity: .999;\\n  stroke-width: calc(1.5*var(--s\\\ntroke-width));\\n}\\n.lh-exp-gauge-component .state--highlight .metric--highlight .metric__value {\\n  opacity: 0.999;\\n}\\n\\n\\n/*\\n the initial first load peek\\n*/\\n.lh-exp-gauge-component .lh-exp-gauge__bg {  /* needed for the use zindex stacking w/ transparency */\\n  fill: var(--report-background-color);\\n  stroke: var(--report-background-color);\\n}\\n.lh-exp-gauge-component .state--peek .metric {\\n  transition-delay: 0ms;\\n  animation: peek var(--peek-dur) cubic-bezier(0.46, 0.03, 0.52, 0.96);\\n  animation-fill-mode: forwards;\\n}\\n.lh-exp-gauge-component .state--peek .lh-exp-gauge__inner .lh-exp-gauge__arc {\\n  opacity: 1;\\n}\\n.lh-exp-gauge-component .state--peek .lh-exp-gauge__arc.lh-exp-gauge--faded {\\n  opacity: 0.3; /* just a tad stronger cuz its fighting with a big solid arg */\\n}\\n/* do i need to set expanded and override this? */\\n.lh-exp-gauge-component .state--peek .lh-exp-gauge__arc--metric.lh-exp-gauge--miniarc {\\n  transition: opacity 0.3s;\\n}\\n.lh-exp-gauge-component .state--peek {\\n  color: unset;\\n}\\n.l\\\nh-exp-gauge-component .state--peek .metric__label {\\n  display: none;\\n}\\n\\n.lh-exp-gauge-component .metric__label {\\n  fill: var(--report-text-color);\\n}\\n\\n@keyframes peek {\\n  /* biggest it should go is 0.92. smallest is 0.8 */\\n  0% {\\n    transform: scale(0.8);\\n    opacity: 0.8;\\n  }\\n\\n  50% {\\n    transform: scale(0.92);\\n    opacity: 1;\\n  }\\n\\n  100% {\\n    transform: scale(0.8);\\n    opacity: 0.8;\\n  }\\n}\\n\\n.lh-exp-gauge-component .wrapper {\\n  width: 620px;\\n}\\n\\n/*# sourceURL=report-styles.css */\\n`),e.append(t),e}function dt(o){let e=o.createFragment(),t=o.createElement(\"style\");t.append(`\\n    .lh-topbar {\\n      position: sticky;\\n      top: 0;\\n      left: 0;\\n      right: 0;\\n      z-index: 1000;\\n      display: flex;\\n      align-items: center;\\n      height: var(--topbar-height);\\n      padding: var(--topbar-padding);\\n      font-size: var(--report-font-size-secondary);\\n      background-color: var(--topbar-background-color);\\n      border-bottom: 1px solid var(--color-gray-200);\\n    }\\n\\n    .lh-topbar__logo \\\n{\\n      width: var(--topbar-logo-size);\\n      height: var(--topbar-logo-size);\\n      user-select: none;\\n      flex: none;\\n    }\\n\\n    .lh-topbar__url {\\n      margin: var(--topbar-padding);\\n      text-decoration: none;\\n      color: var(--report-text-color);\\n      text-overflow: ellipsis;\\n      overflow: hidden;\\n      white-space: nowrap;\\n    }\\n\\n    .lh-tools {\\n      display: flex;\\n      align-items: center;\\n      margin-left: auto;\\n      will-change: transform;\\n      min-width: var(--report-icon-size);\\n    }\\n    .lh-tools__button {\\n      width: var(--report-icon-size);\\n      min-width: 24px;\\n      height: var(--report-icon-size);\\n      cursor: pointer;\\n      margin-right: 5px;\\n      /* This is actually a button element, but we want to style it like a transparent div. */\\n      display: flex;\\n      background: none;\\n      color: inherit;\\n      border: none;\\n      padding: 0;\\n      font: inherit;\\n    }\\n    .lh-tools__button svg {\\n      fill: var(--tools-icon-color);\\n    }\\n    .lh-dark .lh-t\\\nools__button svg {\\n      filter: invert(1);\\n    }\\n    .lh-tools__button.lh-active + .lh-tools__dropdown {\\n      opacity: 1;\\n      clip: rect(-1px, 194px, 270px, -3px);\\n      visibility: visible;\\n    }\\n    .lh-tools__dropdown {\\n      position: absolute;\\n      background-color: var(--report-background-color);\\n      border: 1px solid var(--report-border-color);\\n      border-radius: 3px;\\n      padding: calc(var(--default-padding) / 2) 0;\\n      cursor: pointer;\\n      top: 36px;\\n      right: 0;\\n      box-shadow: 1px 1px 3px #ccc;\\n      min-width: 125px;\\n      clip: rect(0, 164px, 0, 0);\\n      visibility: hidden;\\n      opacity: 0;\\n      transition: all 200ms cubic-bezier(0,0,0.2,1);\\n    }\\n    .lh-tools__dropdown a {\\n      color: currentColor;\\n      text-decoration: none;\\n      white-space: nowrap;\\n      padding: 0 6px;\\n      line-height: 2;\\n    }\\n    .lh-tools__dropdown a:hover,\\n    .lh-tools__dropdown a:focus {\\n      background-color: var(--color-gray-200);\\n      outline: none;\\n    }\\n    /* \\\nsave-gist option hidden in report. */\\n    .lh-tools__dropdown a[data-action=\\'save-gist\\'] {\\n      display: none;\\n    }\\n\\n    .lh-locale-selector {\\n      width: 100%;\\n      color: var(--report-text-color);\\n      background-color: var(--locale-selector-background-color);\\n      padding: 2px;\\n    }\\n    .lh-tools-locale {\\n      display: flex;\\n      align-items: center;\\n      flex-direction: row-reverse;\\n    }\\n    .lh-tools-locale__selector-wrapper {\\n      transition: opacity 0.15s;\\n      opacity: 0;\\n      max-width: 200px;\\n    }\\n    .lh-button.lh-tool-locale__button {\\n      height: var(--topbar-height);\\n      color: var(--tools-icon-color);\\n      padding: calc(var(--default-padding) / 2);\\n    }\\n    .lh-tool-locale__button.lh-active + .lh-tools-locale__selector-wrapper {\\n      opacity: 1;\\n      clip: rect(-1px, 255px, 242px, -3px);\\n      visibility: visible;\\n      margin: 0 4px;\\n    }\\n\\n    /**\\n    * This media query is a temporary fallback for browsers that do not support \\\\`@container query\\\\`.\\\n\\n    * TODO: remove this media query when \\\\`@container query\\\\` is fully supported by browsers\\n    * See https://github.com/GoogleChrome/lighthouse/pull/16332\\n    */\\n    @media screen and (max-width: 964px) {\\n      .lh-tools__dropdown {\\n        right: 0;\\n        left: initial;\\n      }\\n    }\\n\\n    @container lh-container (max-width: 964px) {\\n      .lh-tools__dropdown {\\n        right: 0;\\n        left: initial;\\n      }\\n    }\\n\\n    @media print {\\n      .lh-topbar {\\n        position: static;\\n        margin-left: 0;\\n      }\\n\\n      .lh-tools__dropdown {\\n        display: none;\\n      }\\n    }\\n  `),e.append(t);let n=o.createElement(\"div\",\"lh-topbar\"),r=o.createElementNS(\"http://www.w3.org/2000/svg\",\"svg\",\"lh-topbar__logo\");r.setAttribute(\"role\",\"img\"),r.setAttribute(\"title\",\"Lighthouse logo\"),r.setAttribute(\"fill\",\"none\"),r.setAttribute(\"xmlns\",\"http://www.w3.org/2000/svg\"),r.setAttribute(\"viewBox\",\"0 0 48 48\");let i=o.createElementNS(\"http://www.w3.org/2000/svg\",\"path\");i.setAttribute(\"d\",\"m14 7 10\\\n-7 10 7v10h5v7h-5l5 24H9l5-24H9v-7h5V7Z\"),i.setAttribute(\"fill\",\"#F63\");let a=o.createElementNS(\"http://www.w3.org/2000/svg\",\"path\");a.setAttribute(\"d\",\"M31.561 24H14l-1.689 8.105L31.561 24ZM18.983 48H9l1.022-4.907L35.723 32.27l1.663 7.98L18.983 48Z\"),a.setAttribute(\"fill\",\"#FFA385\");let l=o.createElementNS(\"http://www.w3.org/2000/svg\",\"path\");l.setAttribute(\"fill\",\"#FF3\"),l.setAttribute(\"d\",\"M20.5 10h7v7h-7z\"),r.append(\" \",i,\" \",a,\" \",l,\" \");let s=o.createElement(\"a\",\"lh-topbar__url\");s.setAttribute(\"href\",\"\"),s.setAttribute(\"target\",\"_blank\"),s.setAttribute(\"rel\",\"noopener\");let c=o.createElement(\"div\",\"lh-tools\"),d=o.createElement(\"div\",\"lh-tools-locale lh-hidden\"),h=o.createElement(\"button\",\"lh-button lh-tool-locale__button\");h.setAttribute(\"id\",\"lh-button__swap-locales\"),h.setAttribute(\"title\",\"Show Language Picker\"),h.setAttribute(\"aria-label\",\"Toggle language picker\"),h.setAttribute(\"aria-haspopup\",\"menu\"),h.setAttribute(\"aria-expanded\",\"false\"),h.setAttribute(\"aria-controls\",\"l\\\nh-tools-locale__selector-wrapper\");let p=o.createElementNS(\"http://www.w3.org/2000/svg\",\"svg\");p.setAttribute(\"width\",\"20px\"),p.setAttribute(\"height\",\"20px\"),p.setAttribute(\"viewBox\",\"0 0 24 24\"),p.setAttribute(\"fill\",\"currentColor\");let g=o.createElementNS(\"http://www.w3.org/2000/svg\",\"path\");g.setAttribute(\"d\",\"M0 0h24v24H0V0z\"),g.setAttribute(\"fill\",\"none\");let b=o.createElementNS(\"http://www.w3.org/2000/svg\",\"path\");b.setAttribute(\"d\",\"M12.87 15.07l-2.54-2.51.03-.03c1.74-1.94 2.98-4.17 3.71-6.53H17V4h-7V2H8v2H1v1.99h11.17C11.5 7.92 10.44 9.75 9 11.35 8.07 10.32 7.3 9.19 6.69 8h-2c.73 1.63 1.73 3.17 2.98 4.56l-5.09 5.02L4 19l5-5 3.11 3.11.76-2.04zM18.5 10h-2L12 22h2l1.12-3h4.75L21 22h2l-4.5-12zm-2.62 7l1.62-4.33L19.12 17h-3.24z\"),p.append(g,b),h.append(\" \",p,\" \");let w=o.createElement(\"div\",\"lh-tools-locale__selector-wrapper\");w.setAttribute(\"id\",\"lh-tools-locale__selector-wrapper\"),w.setAttribute(\"role\",\"menu\"),w.setAttribute(\"aria-labelledby\",\"lh-button__swap-locales\"),w.setAttrib\\\nute(\"aria-hidden\",\"true\"),w.append(\" \",\" \"),d.append(\" \",h,\" \",w,\" \");let f=o.createElement(\"button\",\"lh-tools__button\");f.setAttribute(\"id\",\"lh-tools-button\"),f.setAttribute(\"title\",\"Tools menu\"),f.setAttribute(\"aria-label\",\"Toggle report tools menu\"),f.setAttribute(\"aria-haspopup\",\"menu\"),f.setAttribute(\"aria-expanded\",\"false\"),f.setAttribute(\"aria-controls\",\"lh-tools-dropdown\");let u=o.createElementNS(\"http://www.w3.org/2000/svg\",\"svg\");u.setAttribute(\"width\",\"100%\"),u.setAttribute(\"height\",\"100%\"),u.setAttribute(\"viewBox\",\"0 0 24 24\");let v=o.createElementNS(\"http://www.w3.org/2000/svg\",\"path\");v.setAttribute(\"d\",\"M0 0h24v24H0z\"),v.setAttribute(\"fill\",\"none\");let _=o.createElementNS(\"http://www.w3.org/2000/svg\",\"path\");_.setAttribute(\"d\",\"M12 8c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm0 2c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0 6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z\"),u.append(\" \",v,\" \",_,\" \"),f.append(\" \",u,\" \");let x=o.createElement(\"div\",\"lh-tools__dropdown\");x.s\\\netAttribute(\"id\",\"lh-tools-dropdown\"),x.setAttribute(\"role\",\"menu\"),x.setAttribute(\"aria-labelledby\",\"lh-tools-button\");let S=o.createElement(\"a\",\"lh-report-icon lh-report-icon--print\");S.setAttribute(\"role\",\"menuitem\"),S.setAttribute(\"tabindex\",\"-1\"),S.setAttribute(\"href\",\"#\"),S.setAttribute(\"data-i18n\",\"dropdownPrintSummary\"),S.setAttribute(\"data-action\",\"print-summary\");let A=o.createElement(\"a\",\"lh-report-icon lh-report-icon--print\");A.setAttribute(\"role\",\"menuitem\"),A.setAttribute(\"tabindex\",\"-1\"),A.setAttribute(\"href\",\"#\"),A.setAttribute(\"data-i18n\",\"dropdownPrintExpanded\"),A.setAttribute(\"data-action\",\"print-expanded\");let z=o.createElement(\"a\",\"lh-report-icon lh-report-icon--copy\");z.setAttribute(\"role\",\"menuitem\"),z.setAttribute(\"tabindex\",\"-1\"),z.setAttribute(\"href\",\"#\"),z.setAttribute(\"data-i18n\",\"dropdownCopyJSON\"),z.setAttribute(\"data-action\",\"copy\");let M=o.createElement(\"a\",\"lh-report-icon lh-report-icon--download lh-hidden\");M.setAttribute(\"role\",\"menuitem\"),M.setAttrib\\\nute(\"tabindex\",\"-1\"),M.setAttribute(\"href\",\"#\"),M.setAttribute(\"data-i18n\",\"dropdownSaveHTML\"),M.setAttribute(\"data-action\",\"save-html\");let $=o.createElement(\"a\",\"lh-report-icon lh-report-icon--download\");$.setAttribute(\"role\",\"menuitem\"),$.setAttribute(\"tabindex\",\"-1\"),$.setAttribute(\"href\",\"#\"),$.setAttribute(\"data-i18n\",\"dropdownSaveJSON\"),$.setAttribute(\"data-action\",\"save-json\");let R=o.createElement(\"a\",\"lh-report-icon lh-report-icon--open\");R.setAttribute(\"role\",\"menuitem\"),R.setAttribute(\"tabindex\",\"-1\"),R.setAttribute(\"href\",\"#\"),R.setAttribute(\"data-i18n\",\"dropdownViewer\"),R.setAttribute(\"data-action\",\"open-viewer\");let N=o.createElement(\"a\",\"lh-report-icon lh-report-icon--open\");N.setAttribute(\"role\",\"menuitem\"),N.setAttribute(\"tabindex\",\"-1\"),N.setAttribute(\"href\",\"#\"),N.setAttribute(\"data-i18n\",\"dropdownSaveGist\"),N.setAttribute(\"data-action\",\"save-gist\");let D=o.createElement(\"a\",\"lh-report-icon lh-report-icon--open lh-hidden\");D.setAttribute(\"role\",\"menuitem\"),D.setAttr\\\nibute(\"tabindex\",\"-1\"),D.setAttribute(\"href\",\"#\"),D.setAttribute(\"data-i18n\",\"dropdownViewUnthrottledTrace\"),D.setAttribute(\"data-action\",\"view-unthrottled-trace\");let I=o.createElement(\"a\",\"lh-report-icon lh-report-icon--dark\");return I.setAttribute(\"role\",\"menuitem\"),I.setAttribute(\"tabindex\",\"-1\"),I.setAttribute(\"href\",\"#\"),I.setAttribute(\"data-i18n\",\"dropdownDarkTheme\"),I.setAttribute(\"data-action\",\"toggle-dark\"),x.append(\" \",S,\" \",A,\" \",z,\" \",\" \",M,\" \",$,\" \",R,\" \",N,\" \",\" \",D,\" \",I,\" \"),c.append(\" \",d,\" \",f,\" \",x,\" \"),n.append(\" \",\" \",r,\" \",s,\" \",c,\" \"),e.append(n),e}function ht(o){let e=o.createFragment(),t=o.createElement(\"div\",\"lh-warnings lh-warnings--toplevel\"),n=o.createElement(\"p\",\"lh-warnings__msg\"),r=o.createElement(\"ul\");return t.append(\" \",n,\" \",r,\" \"),e.append(t),e}function be(o,e){switch(e){case\"3pFilter\":return Ge(o);case\"audit\":return Be(o);case\"categoryHeader\":return qe(o);case\"chevron\":return je(o);case\"clump\":return We(o);case\"crc\":return Ke(o);case\"crcChain\":ret\\\nurn Je(o);case\"elementScreenshot\":return Ze(o);case\"explodeyGauge\":return Qe(o);case\"footer\":return Ye(o);case\"fraction\":return Xe(o);case\"gauge\":return et(o);case\"heading\":return tt(o);case\"metric\":return nt(o);case\"scorescale\":return rt(o);case\"scoresWrapper\":return ot(o);case\"snippet\":return it(o);case\"snippetContent\":return at(o);case\"snippetHeader\":return lt(o);case\"snippetLine\":return st(o);case\"styles\":return ct(o);case\"topbar\":return dt(o);case\"warningsToplevel\":return ht(o)}throw new Error(\"unexpected component: \"+e)}var ee=class{constructor(e,t){this._document=e,this._lighthouseChannel=\"unknown\",this._componentCache=new Map,this.rootEl=t}createElement(e,t){let n=this._document.createElement(e);if(t)for(let r of t.split(/\\\\s+/))r&&n.classList.add(r);return n}createElementNS(e,t,n){let r=this._document.createElementNS(e,t);if(n)for(let i of n.split(/\\\\s+/))i&&r.classList.add(i);return r}createSVGElement(e,t){return this._document.createElementNS(\"http://www.w3.org/2000/svg\",e,t)}\\\ncreateFragment(){return this._document.createDocumentFragment()}createTextNode(e){return this._document.createTextNode(e)}createChildOf(e,t,n){let r=this.createElement(t,n);return e.append(r),r}createComponent(e){let t=this._componentCache.get(e);if(t){let r=t.cloneNode(!0);return this.findAll(\"style\",r).forEach(i=>i.remove()),r}return t=be(this,e),this._componentCache.set(e,t),t.cloneNode(!0)}clearComponentCache(){this._componentCache.clear()}convertMarkdownLinkSnippets(e,t={}){let n=this.createElement(\"span\");for(let r of E.splitMarkdownLink(e)){let i=r.text.includes(\"`\")?this.convertMarkdownCodeSnippets(r.text):r.text;if(!r.isLink){n.append(i);continue}let a=new URL(r.linkHref);([\"https://developers.google.com\",\"https://web.dev\",\"https://developer.chrome.com\"].includes(a.origin)||t.alwaysAppendUtmSource)&&(a.searchParams.set(\"utm_source\",\"lighthouse\"),a.searchParams.set(\"utm_medium\",this._lighthouseChannel));let s=this.createElement(\"a\");s.rel=\"noopener\",s.target=\"_blank\",s.append(i\\\n),this.safelySetHref(s,a.href),n.append(s)}return n}safelySetHref(e,t){if(t=t||\"\",t.startsWith(\"#\")){e.href=t;return}let n=[\"https:\",\"http:\"],r;try{r=new URL(t)}catch{}r&&n.includes(r.protocol)&&(e.href=r.href)}safelySetBlobHref(e,t){if(t.type!==\"text/html\"&&t.type!==\"application/json\")throw new Error(\"Unsupported blob type\");let n=URL.createObjectURL(t);e.href=n}convertMarkdownCodeSnippets(e){let t=this.createElement(\"span\");for(let n of E.splitMarkdownCodeSpans(e))if(n.isCode){let r=this.createElement(\"code\");r.textContent=n.text,t.append(r)}else t.append(this._document.createTextNode(n.text));return t}setLighthouseChannel(e){this._lighthouseChannel=e}document(){return this._document}isDevTools(){return!!this._document.querySelector(\".lh-devtools\")}find(e,t=this.rootEl??this._document){let n=this.maybeFind(e,t);if(n===null)throw new Error(`query ${e} not found`);return n}maybeFind(e,t=this.rootEl??this._document){return t.querySelector(e)}findAll(e,t){return Array.from(t.querySelecto\\\nrAll(e))}fireEventOn(e,t=this._document,n){let r=new CustomEvent(e,n?{detail:n}:void 0);t.dispatchEvent(r)}saveFile(e,t){let n=this.createElement(\"a\");n.download=t,this.safelySetBlobHref(n,e),this._document.body.append(n),n.click(),this._document.body.removeChild(n),setTimeout(()=>URL.revokeObjectURL(n.href),500)}};var _e=0,m=class o{static i18n=null;static strings={};static reportJson=null;static apply(e){o.strings={...we,...e.providedStrings},o.i18n=e.i18n,o.reportJson=e.reportJson}static getUniqueSuffix(){return _e++}static resetUniqueSuffix(){_e=0}};var ye=\"data:image/jpeg;base64,\";function xe(o){o.configSettings.locale||(o.configSettings.locale=\"en\"),o.configSettings.formFactor||(o.configSettings.formFactor=o.configSettings.emulatedFormFactor),o.finalDisplayedUrl=E.getFinalDisplayedUrl(o),o.mainDocumentUrl=E.getMainDocumentUrl(o);for(let n of Object.values(o.audits))if((n.scoreDisplayMode===\"not_applicable\"||n.scoreDisplayMode===\"not-applicable\")&&(n.scoreDisplayMode=\"notApplicabl\\\ne\"),n.scoreDisplayMode===\"informative\"&&(n.score=1),n.details){if((n.details.type===void 0||n.details.type===\"diagnostic\")&&(n.details.type=\"debugdata\"),n.details.type===\"filmstrip\")for(let r of n.details.items)r.data.startsWith(ye)||(r.data=ye+r.data);if(n.details.type===\"table\")for(let r of n.details.headings){let{itemType:i,text:a}=r;i!==void 0&&(r.valueType=i,delete r.itemType),a!==void 0&&(r.label=a,delete r.text);let l=r.subItemsHeading?.itemType;r.subItemsHeading&&l!==void 0&&(r.subItemsHeading.valueType=l,delete r.subItemsHeading.itemType)}if(n.id===\"third-party-summary\"&&(n.details.type===\"opportunity\"||n.details.type===\"table\")){let{headings:r,items:i}=n.details;if(r[0].valueType===\"link\"){r[0].valueType=\"text\";for(let a of i)typeof a.entity==\"object\"&&a.entity.type===\"link\"&&(a.entity=a.entity.text);n.details.isEntityGrouped=!0}}}let[e]=o.lighthouseVersion.split(\".\").map(Number),t=o.categories.performance;if(t){if(e<9){o.categoryGroups||(o.categoryGroups={}),o.categoryGroups\\\n.hidden={title:\"\"};for(let n of t.auditRefs)n.group?n.group===\"load-opportunities\"&&(n.group=\"diagnostics\"):n.group=\"hidden\"}else if(e<12)for(let n of t.auditRefs)n.group||(n.group=\"diagnostics\")}if(e<12&&t){let n=new Map;for(let r of t.auditRefs){let i=r.relevantAudits;if(!(!i||!r.acronym))for(let a of i){let l=n.get(a)||[];l.push(r.acronym),n.set(a,l)}}for(let[r,i]of n){if(!i.length)continue;let a=o.audits[r];if(a&&!a.metricSavings){a.metricSavings={};for(let l of i)a.metricSavings[l]=0}}}if(o.environment||(o.environment={benchmarkIndex:0,networkUserAgent:o.userAgent,hostUserAgent:o.userAgent}),o.configSettings.screenEmulation||(o.configSettings.screenEmulation={width:-1,height:-1,deviceScaleFactor:-1,mobile:/mobile/i.test(o.environment.hostUserAgent),disabled:!1}),o.i18n||(o.i18n={}),o.audits[\"full-page-screenshot\"]){let n=o.audits[\"full-page-screenshot\"].details;n?o.fullPageScreenshot={screenshot:n.screenshot,nodes:n.nodes}:o.fullPageScreenshot=null,delete o.audits[\"full-page-scree\\\nnshot\"]}}var O=E.RATINGS,k=class o{static prepareReportResult(e){let t=JSON.parse(JSON.stringify(e));xe(t);for(let r of Object.values(t.audits))r.details&&(r.details.type===\"opportunity\"||r.details.type===\"table\")&&!r.details.isEntityGrouped&&t.entities&&o.classifyEntities(t.entities,r.details);if(typeof t.categories!=\"object\")throw new Error(\"No categories provided.\");let n=new Map;for(let r of Object.values(t.categories))r.auditRefs.forEach(i=>{i.acronym&&n.set(i.acronym,i)}),r.auditRefs.forEach(i=>{let a=t.audits[i.id];i.result=a;let l=Object.keys(i.result.metricSavings||{});if(l.length){i.relevantMetrics=[];for(let s of l){let c=n.get(s);c&&i.relevantMetrics.push(c)}}if(t.stackPacks){let s=[i.id,...i.result.replacesAudits??[]];t.stackPacks.forEach(c=>{let d=s.find(h=>c.descriptions[h]);d&&c.descriptions[d]&&(i.stackPacks=i.stackPacks||[],i.stackPacks.push({title:c.title,iconDataURL:c.iconDataURL,description:c.descriptions[d]}))})}});return t}static getUrlLocatorFn(e){let t=e.find(r\\\n=>r.valueType===\"url\")?.key;if(t&&typeof t==\"string\")return r=>{let i=r[t];if(typeof i==\"string\")return i};let n=e.find(r=>r.valueType===\"source-location\")?.key;if(n)return r=>{let i=r[n];if(typeof i==\"object\"&&i.type===\"source-location\")return i.url}}static classifyEntities(e,t){let{items:n,headings:r}=t;if(!n.length||n.some(a=>a.entity))return;let i=o.getUrlLocatorFn(r);if(i)for(let a of n){let l=i(a);if(!l)continue;let s=\"\";try{s=E.parseURL(l).origin}catch{}if(!s)continue;let c=e.find(d=>d.origins.includes(s));c&&(a.entity=c.name)}}static getTableItemSortComparator(e){return(t,n)=>{for(let r of e){let i=t[r],a=n[r];if((typeof i!=typeof a||![\"number\",\"string\"].includes(typeof i))&&console.warn(`Warning: Attempting to sort unsupported value type: ${r}.`),typeof i==\"number\"&&typeof a==\"number\"&&i!==a)return a-i;if(typeof i==\"string\"&&typeof a==\"string\"&&i!==a)return i.localeCompare(a)}return 0}}static getEmulationDescriptions(e){let t,n,r,i=e.throttling,a=m.i18n,l=m.strings;switch(e.th\\\nrottlingMethod){case\"provided\":r=n=t=l.throttlingProvided;break;case\"devtools\":{let{cpuSlowdownMultiplier:p,requestLatencyMs:g}=i;t=`${a.formatNumber(p)}x slowdown (DevTools)`,n=`${a.formatMilliseconds(g)} HTTP RTT, ${a.formatKbps(i.downloadThroughputKbps)} down, ${a.formatKbps(i.uploadThroughputKbps)} up (DevTools)`,r=g===150*3.75&&i.downloadThroughputKbps===1.6*1024*.9&&i.uploadThroughputKbps===750*.9?l.runtimeSlow4g:l.runtimeCustom;break}case\"simulate\":{let{cpuSlowdownMultiplier:p,rttMs:g,throughputKbps:b}=i;t=`${a.formatNumber(p)}x slowdown (Simulated)`,n=`${a.formatMilliseconds(g)} TCP RTT, ${a.formatKbps(b)} throughput (Simulated)`,r=g===150&&b===1.6*1024?l.runtimeSlow4g:l.runtimeCustom;break}default:r=t=n=l.runtimeUnknown}let s=e.channel===\"devtools\"?!1:e.screenEmulation.disabled,c=e.channel===\"devtools\"?e.formFactor===\"mobile\":e.screenEmulation.mobile,d=l.runtimeMobileEmulation;s?d=l.runtimeNoEmulation:c||(d=l.runtimeDesktopEmulation);let h=s?void 0:`${e.screenEmulation.width}x\\\n${e.screenEmulation.height}, DPR ${e.screenEmulation.deviceScaleFactor}`;return{deviceEmulation:d,screenEmulation:h,cpuThrottling:t,networkThrottling:n,summary:r}}static showAsPassed(e){switch(e.scoreDisplayMode){case\"manual\":case\"notApplicable\":return!0;case\"error\":case\"informative\":return!1;case\"numeric\":case\"binary\":default:return Number(e.score)>=O.PASS.minScore}}static calculateRating(e,t){if(t===\"manual\"||t===\"notApplicable\")return O.PASS.label;if(t===\"error\")return O.ERROR.label;if(e===null)return O.FAIL.label;let n=O.FAIL.label;return e>=O.PASS.minScore?n=O.PASS.label:e>=O.AVERAGE.minScore&&(n=O.AVERAGE.label),n}static calculateCategoryFraction(e){let t=0,n=0,r=0,i=0;for(let a of e.auditRefs){let l=o.showAsPassed(a.result);if(!(a.group===\"hidden\"||a.result.scoreDisplayMode===\"manual\"||a.result.scoreDisplayMode===\"notApplicable\")){if(a.result.scoreDisplayMode===\"informative\"){l||++r;continue}++t,i+=a.weight,l&&n++}}return{numPassed:n,numPassableAudits:t,numInformative:r,totalWei\\\nght:i}}static isPluginCategory(e){return e.startsWith(\"lighthouse-plugin-\")}static shouldDisplayAsFraction(e){return e===\"timespan\"||e===\"snapshot\"}},we={varianceDisclaimer:\"Values are estimated and may vary. The [performance score is calculated](https://developer.chrome.com/docs/lighthouse/performance/performance-scoring/) directly from these metrics.\",calculatorLink:\"See calculator.\",showRelevantAudits:\"Show audits relevant to:\",opportunityResourceColumnLabel:\"Opportunity\",opportunitySavingsColumnLabel:\"Estimated Savings\",errorMissingAuditInfo:\"Report error: no audit information\",errorLabel:\"Error!\",warningHeader:\"Warnings: \",warningAuditsGroupTitle:\"Passed audits but with warnings\",passedAuditsGroupTitle:\"Passed audits\",notApplicableAuditsGroupTitle:\"Not applicable\",manualAuditsGroupTitle:\"Additional items to manually check\",toplevelWarningsMessage:\"There were issues affecting this run of Lighthouse:\",crcInitialNavigation:\"Initial Navigation\",crcLongestDurationLabel:\"Maximum critica\\\nl path latency:\",snippetExpandButtonLabel:\"Expand snippet\",snippetCollapseButtonLabel:\"Collapse snippet\",lsPerformanceCategoryDescription:\"[Lighthouse](https://developers.google.com/web/tools/lighthouse/) analysis of the current page on an emulated mobile network. Values are estimated and may vary.\",labDataTitle:\"Lab Data\",thirdPartyResourcesLabel:\"Show 3rd-party resources\",viewTreemapLabel:\"View Treemap\",viewTraceLabel:\"View Trace\",dropdownPrintSummary:\"Print Summary\",dropdownPrintExpanded:\"Print Expanded\",dropdownCopyJSON:\"Copy JSON\",dropdownSaveHTML:\"Save as HTML\",dropdownSaveJSON:\"Save as JSON\",dropdownViewer:\"Open in Viewer\",dropdownSaveGist:\"Save as Gist\",dropdownDarkTheme:\"Toggle Dark Theme\",dropdownViewUnthrottledTrace:\"View Unthrottled Trace\",runtimeSettingsDevice:\"Device\",runtimeSettingsNetworkThrottling:\"Network throttling\",runtimeSettingsCPUThrottling:\"CPU throttling\",runtimeSettingsUANetwork:\"User agent (network)\",runtimeSettingsBenchmark:\"Unthrottled CPU/Memory Power\",run\\\ntimeSettingsAxeVersion:\"Axe version\",runtimeSettingsScreenEmulation:\"Screen emulation\",footerIssue:\"File an issue\",runtimeNoEmulation:\"No emulation\",runtimeMobileEmulation:\"Emulated Moto G Power\",runtimeDesktopEmulation:\"Emulated Desktop\",runtimeUnknown:\"Unknown\",runtimeSingleLoad:\"Single page session\",runtimeAnalysisWindow:\"Initial page load\",runtimeAnalysisWindowTimespan:\"User interactions timespan\",runtimeAnalysisWindowSnapshot:\"Point-in-time snapshot\",runtimeSingleLoadTooltip:\"This data is taken from a single page session, as opposed to field data summarizing many sessions.\",throttlingProvided:\"Provided by environment\",show:\"Show\",hide:\"Hide\",expandView:\"Expand view\",collapseView:\"Collapse view\",runtimeSlow4g:\"Slow 4G throttling\",runtimeCustom:\"Custom throttling\",firstPartyChipLabel:\"1st party\",openInANewTabTooltip:\"Open in a new tab\",unattributable:\"Unattributable\",unscoredLabel:\"Unscored\",unscoredTitle:\"This audit does not contribute to the overall category score.\"};var G=class{c\\\nonstructor(e,t){this.dom=e,this.detailsRenderer=t}get _clumpTitles(){return{warning:m.strings.warningAuditsGroupTitle,manual:m.strings.manualAuditsGroupTitle,passed:m.strings.passedAuditsGroupTitle,notApplicable:m.strings.notApplicableAuditsGroupTitle}}renderAudit(e){let t=m.strings,n=this.dom.createComponent(\"audit\"),r=this.dom.find(\"div.lh-audit\",n);r.id=e.result.id;let i=e.result.scoreDisplayMode;e.result.displayValue&&(this.dom.find(\".lh-audit__display-text\",r).textContent=e.result.displayValue);let a=this.dom.find(\".lh-audit__title\",r);a.append(this.dom.convertMarkdownCodeSnippets(e.result.title));let l=this.dom.find(\".lh-audit__description\",r);l.append(this.dom.convertMarkdownLinkSnippets(e.result.description));for(let p of e.relevantMetrics||[]){let g=this.dom.createChildOf(l,\"span\",\"lh-audit__adorn\");g.title=`Relevant to ${p.result.title}`,g.textContent=p.acronym||p.id}if(e.weight===0){let p=this.dom.createChildOf(l,\"span\",\"lh-audit__adorn\");p.title=m.strings.unscoredTitle,p.te\\\nxtContent=m.strings.unscoredLabel}e.stackPacks&&e.stackPacks.forEach(p=>{let g=this.dom.createElement(\"img\",\"lh-audit__stackpack__img\");g.src=p.iconDataURL,g.alt=p.title;let b=this.dom.convertMarkdownLinkSnippets(p.description,{alwaysAppendUtmSource:!0}),w=this.dom.createElement(\"div\",\"lh-audit__stackpack\");w.append(g,b),this.dom.find(\".lh-audit__stackpacks\",r).append(w)});let s=this.dom.find(\"details\",r);if(e.result.details){let p=this.detailsRenderer.render(e.result.details);p&&(p.classList.add(\"lh-details\"),s.append(p))}if(this.dom.find(\".lh-chevron-container\",r).append(this._createChevron()),this._setRatingClass(r,e.result.score,i),e.result.scoreDisplayMode===\"error\"){r.classList.add(\"lh-audit--error\");let p=this.dom.find(\".lh-audit__display-text\",r);p.textContent=t.errorLabel,p.classList.add(\"lh-tooltip-boundary\");let g=this.dom.createChildOf(p,\"div\",\"lh-tooltip lh-tooltip--error\");g.textContent=e.result.errorMessage||t.errorMissingAuditInfo}else if(e.result.explanation){let p=thi\\\ns.dom.createChildOf(a,\"div\",\"lh-audit-explanation\");p.textContent=e.result.explanation}let c=e.result.warnings;if(!c||c.length===0)return r;let d=this.dom.find(\"summary\",s),h=this.dom.createChildOf(d,\"div\",\"lh-warnings\");if(this.dom.createChildOf(h,\"span\").textContent=t.warningHeader,c.length===1)h.append(this.dom.createTextNode(c.join(\"\")));else{let p=this.dom.createChildOf(h,\"ul\");for(let g of c){let b=this.dom.createChildOf(p,\"li\");b.textContent=g}}return r}injectFinalScreenshot(e,t,n){let r=t[\"final-screenshot\"];if(!r||r.scoreDisplayMode===\"error\"||!r.details||r.details.type!==\"screenshot\")return null;let i=this.dom.createElement(\"img\",\"lh-final-ss-image\"),a=r.details.data;i.src=a,i.alt=r.title;let l=this.dom.find(\".lh-category .lh-category-header\",e),s=this.dom.createElement(\"div\",\"lh-category-headercol\"),c=this.dom.createElement(\"div\",\"lh-category-headercol lh-category-headercol--separator\"),d=this.dom.createElement(\"div\",\"lh-category-headercol\");s.append(...l.childNodes),s.appen\\\nd(n),d.append(i),l.append(s,c,d),l.classList.add(\"lh-category-header__finalscreenshot\")}_createChevron(){let e=this.dom.createComponent(\"chevron\");return this.dom.find(\"svg.lh-chevron\",e)}_setRatingClass(e,t,n){let r=k.calculateRating(t,n);return e.classList.add(`lh-audit--${n.toLowerCase()}`),n!==\"informative\"&&e.classList.add(`lh-audit--${r}`),e}renderCategoryHeader(e,t,n){let r=this.dom.createComponent(\"categoryHeader\"),i=this.dom.find(\".lh-score__gauge\",r),a=this.renderCategoryScore(e,t,n);if(i.append(a),e.description){let l=this.dom.convertMarkdownLinkSnippets(e.description);this.dom.find(\".lh-category-header__description\",r).append(l)}return r}renderAuditGroup(e){let t=this.dom.createElement(\"div\",\"lh-audit-group\"),n=this.dom.createElement(\"div\",\"lh-audit-group__header\");this.dom.createChildOf(n,\"span\",\"lh-audit-group__title\").textContent=e.title,t.append(n);let r=null;return e.description&&(r=this.dom.convertMarkdownLinkSnippets(e.description),r.classList.add(\"lh-audit-group__de\\\nscription\",\"lh-audit-group__footer\"),t.append(r)),[t,r]}_renderGroupedAudits(e,t){let n=new Map,r=\"NotAGroup\";n.set(r,[]);for(let a of e){let l=a.group||r,s=n.get(l)||[];s.push(a),n.set(l,s)}let i=[];for(let[a,l]of n){if(a===r){for(let h of l)i.push(this.renderAudit(h));continue}let s=t[a],[c,d]=this.renderAuditGroup(s);for(let h of l)c.insertBefore(this.renderAudit(h),d);c.classList.add(`lh-audit-group--${a}`),i.push(c)}return i}renderUnexpandableClump(e,t){let n=this.dom.createElement(\"div\");return this._renderGroupedAudits(e,t).forEach(i=>n.append(i)),n}renderClump(e,{auditRefsOrEls:t,description:n,openByDefault:r}){let i=this.dom.createComponent(\"clump\"),a=this.dom.find(\".lh-clump\",i);r&&a.setAttribute(\"open\",\"\");let l=this.dom.find(\".lh-audit-group__header\",a),s=this._clumpTitles[e];this.dom.find(\".lh-audit-group__title\",l).textContent=s;let c=this.dom.find(\".lh-audit-group__itemcount\",a);c.textContent=`(${t.length})`;let d=t.map(p=>p instanceof HTMLElement?p:this.renderAudit(p));\\\na.append(...d);let h=this.dom.find(\".lh-audit-group\",i);if(n){let p=this.dom.convertMarkdownLinkSnippets(n);p.classList.add(\"lh-audit-group__description\",\"lh-audit-group__footer\"),h.append(p)}return this.dom.find(\".lh-clump-toggletext--show\",h).textContent=m.strings.show,this.dom.find(\".lh-clump-toggletext--hide\",h).textContent=m.strings.hide,a.classList.add(`lh-clump--${e.toLowerCase()}`),h}renderCategoryScore(e,t,n){let r;if(n&&k.shouldDisplayAsFraction(n.gatherMode)?r=this.renderCategoryFraction(e):r=this.renderScoreGauge(e,t),n?.omitLabel&&this.dom.find(\".lh-gauge__label,.lh-fraction__label\",r).remove(),n?.onPageAnchorRendered){let i=this.dom.find(\"a\",r);n.onPageAnchorRendered(i)}return r}renderScoreGauge(e,t){let n=this.dom.createComponent(\"gauge\"),r=this.dom.find(\"a.lh-gauge__wrapper\",n);k.isPluginCategory(e.id)&&r.classList.add(\"lh-gauge__wrapper--plugin\");let i=Number(e.score),a=this.dom.find(\".lh-gauge\",n),l=this.dom.find(\"circle.lh-gauge-arc\",a);l&&this._setGaugeArc(l,i);let \\\ns=Math.round(i*100),c=this.dom.find(\"div.lh-gauge__percentage\",n);return c.textContent=s.toString(),e.score===null&&(c.classList.add(\"lh-gauge--error\"),c.textContent=\"\",c.title=m.strings.errorLabel),e.auditRefs.length===0||this.hasApplicableAudits(e)?r.classList.add(`lh-gauge__wrapper--${k.calculateRating(e.score)}`):(r.classList.add(\"lh-gauge__wrapper--not-applicable\"),c.textContent=\"-\",c.title=m.strings.notApplicableAuditsGroupTitle),this.dom.find(\".lh-gauge__label\",n).textContent=e.title,n}renderCategoryFraction(e){let t=this.dom.createComponent(\"fraction\"),n=this.dom.find(\"a.lh-fraction__wrapper\",t),{numPassed:r,numPassableAudits:i,totalWeight:a}=k.calculateCategoryFraction(e),l=r/i,s=this.dom.find(\".lh-fraction__content\",t),c=this.dom.createElement(\"span\");c.textContent=`${r}/${i}`,s.append(c);let d=k.calculateRating(l);return a===0&&(d=\"null\"),n.classList.add(`lh-fraction__wrapper--${d}`),this.dom.find(\".lh-fraction__label\",t).textContent=e.title,t}hasApplicableAudits(e){return e\\\n.auditRefs.some(t=>t.result.scoreDisplayMode!==\"notApplicable\")}_setGaugeArc(e,t){let n=2*Math.PI*Number(e.getAttribute(\"r\")),r=Number(e.getAttribute(\"stroke-width\")),i=.25*r/n;e.style.transform=`rotate(${-90+i*360}deg)`;let a=t*n-r/2;t===0&&(e.style.opacity=\"0\"),t===1&&(a=n),e.style.strokeDasharray=`${Math.max(a,0)} ${n}`}_auditHasWarning(e){return!!e.result.warnings?.length}_getClumpIdForAuditRef(e){let t=e.result.scoreDisplayMode;return t===\"manual\"||t===\"notApplicable\"?t:k.showAsPassed(e.result)?this._auditHasWarning(e)?\"warning\":\"passed\":\"failed\"}render(e,t={},n){let r=this.dom.createElement(\"div\",\"lh-category\");r.id=e.id,r.append(this.renderCategoryHeader(e,t,n));let i=new Map;i.set(\"failed\",[]),i.set(\"warning\",[]),i.set(\"manual\",[]),i.set(\"passed\",[]),i.set(\"notApplicable\",[]);for(let l of e.auditRefs){if(l.group===\"hidden\")continue;let s=this._getClumpIdForAuditRef(l),c=i.get(s);c.push(l),i.set(s,c)}for(let l of i.values())l.sort((s,c)=>c.weight-s.weight);let a=i.get(\"failed\")?\\\n.length;for(let[l,s]of i){if(s.length===0)continue;if(l===\"failed\"){let p=this.renderUnexpandableClump(s,t);p.classList.add(\"lh-clump--failed\"),r.append(p);continue}let c=l===\"manual\"?e.manualDescription:void 0,d=l===\"warning\"||l===\"manual\"&&a===0,h=this.renderClump(l,{auditRefsOrEls:s,description:c,openByDefault:d});r.append(h)}return r}};var Y=class{static createSegment(e,t,n,r){let i=e[t],a=Object.keys(e),l=a.indexOf(t)===a.length-1,s=!!i.children&&Object.keys(i.children).length>0,c=Array.isArray(n)?n.slice(0):[];return typeof r<\"u\"&&c.push(!r),{node:i,isLastChild:l,hasChildren:s,treeMarkers:c}}static createChainNode(e,t,n){let r=e.createComponent(\"crcChain\"),i,a,l,s,c;\"request\"in t.node?(a=t.node.request.transferSize,l=t.node.request.url,i=(t.node.request.endTime-t.node.request.startTime)*1e3,s=!1):(a=t.node.transferSize,l=t.node.url,i=t.node.navStartToEndTime,s=!0,c=t.node.isLongest);let d=e.find(\".lh-crc-node\",r);d.setAttribute(\"title\",l),c&&d.classList.add(\"lh-crc-node__longest\"\\\n);let h=e.find(\".lh-crc-node__tree-marker\",r);t.treeMarkers.forEach(f=>{let u=f?\"lh-tree-marker lh-vert\":\"lh-tree-marker\";h.append(e.createElement(\"span\",u),e.createElement(\"span\",\"lh-tree-marker\"))});let p=t.isLastChild?\"lh-tree-marker lh-up-right\":\"lh-tree-marker lh-vert-right\",g=t.hasChildren?\"lh-tree-marker lh-horiz-down\":\"lh-tree-marker lh-right\";h.append(e.createElement(\"span\",p),e.createElement(\"span\",\"lh-tree-marker lh-right\"),e.createElement(\"span\",g));let b=n.renderTextURL(l),w=e.find(\".lh-crc-node__tree-value\",r);if(w.append(b),!t.hasChildren||s){let f=e.createElement(\"span\",\"lh-crc-node__chain-duration\");f.textContent=\" - \"+m.i18n.formatMilliseconds(i)+\", \";let u=e.createElement(\"span\",\"lh-crc-node__chain-size\");u.textContent=m.i18n.formatBytesToKiB(a,.01),w.append(f,u)}return r}static buildTree(e,t,n,r){if(n.append(Q.createChainNode(e,t,r)),t.node.children)for(let i of Object.keys(t.node.children)){let a=Q.createSegment(t.node.children,i,t.treeMarkers,t.isLastChild);Q.buil\\\ndTree(e,a,n,r)}}static render(e,t,n){let r=e.createComponent(\"crc\"),i=e.find(\".lh-crc\",r);e.find(\".lh-crc-initial-nav\",r).textContent=m.strings.crcInitialNavigation,e.find(\".lh-crc__longest_duration_label\",r).textContent=m.strings.crcLongestDurationLabel,e.find(\".lh-crc__longest_duration\",r).textContent=m.i18n.formatMilliseconds(t.longestChain.duration);let a=t.chains;for(let l of Object.keys(a)){let s=Q.createSegment(a,l);Q.buildTree(e,s,i,n)}return e.find(\".lh-crc-container\",r)}},Q=Y;function pt(o,e){return e.left<=o.width&&0<=e.right&&e.top<=o.height&&0<=e.bottom}function ke(o,e,t){return o<e?e:o>t?t:o}function ut(o){return{x:o.left+o.width/2,y:o.top+o.height/2}}var V=class o{static getScreenshotPositions(e,t,n){let r=ut(e),i=ke(r.x-t.width/2,0,n.width-t.width),a=ke(r.y-t.height/2,0,n.height-t.height);return{screenshot:{left:i,top:a},clip:{left:e.left-i,top:e.top-a}}}static renderClipPathInScreenshot(e,t,n,r,i){let a=e.find(\"clipPath\",t),l=`clip-${m.getUniqueSuffix()}`;a.id=l,t.styl\\\ne.clipPath=`url(#${l})`;let s=n.top/i.height,c=s+r.height/i.height,d=n.left/i.width,h=d+r.width/i.width,p=[`0,0             1,0            1,${s}          0,${s}`,`0,${c}     1,${c}    1,1               0,1`,`0,${s}        ${d},${s} ${d},${c} 0,${c}`,`${h},${s} 1,${s}       1,${c}       ${h},${c}`];for(let g of p){let b=e.createElementNS(\"http://www.w3.org/2000/svg\",\"polygon\");b.setAttribute(\"points\",g),a.append(b)}}static installFullPageScreenshot(e,t){e.style.setProperty(\"--element-screenshot-url\",`url(\\'${t.data}\\')`)}static installOverlayFeature(e){let{dom:t,rootEl:n,overlayContainerEl:r,fullPageScreenshot:i}=e,a=\"lh-screenshot-overlay--enabled\";n.classList.contains(a)||(n.classList.add(a),n.addEventListener(\"click\",l=>{let s=l.target;if(!s)return;let c=s.closest(\".lh-node > .lh-element-screenshot\");if(!c)return;let d=t.createElement(\"div\",\"lh-element-screenshot__overlay\");r.append(d);let h={width:d.clientWidth*.95,height:d.clientHeight*.8},p={width:Number(c.dataset.rectWidth),height\\\n:Number(c.dataset.rectHeight),left:Number(c.dataset.rectLeft),right:Number(c.dataset.rectLeft)+Number(c.dataset.rectWidth),top:Number(c.dataset.rectTop),bottom:Number(c.dataset.rectTop)+Number(c.dataset.rectHeight)},g=o.render(t,i.screenshot,p,h);if(!g){d.remove();return}d.append(g),d.addEventListener(\"click\",()=>d.remove())}))}static _computeZoomFactor(e,t){let r={x:t.width/e.width,y:t.height/e.height},i=.75*Math.min(r.x,r.y);return Math.min(1,i)}static render(e,t,n,r){if(!pt(t,n))return null;let i=e.createComponent(\"elementScreenshot\"),a=e.find(\"div.lh-element-screenshot\",i);a.dataset.rectWidth=n.width.toString(),a.dataset.rectHeight=n.height.toString(),a.dataset.rectLeft=n.left.toString(),a.dataset.rectTop=n.top.toString();let l=this._computeZoomFactor(n,r),s={width:r.width/l,height:r.height/l};s.width=Math.min(t.width,s.width),s.height=Math.min(t.height,s.height);let c={width:s.width*l,height:s.height*l},d=o.getScreenshotPositions(n,s,{width:t.width,height:t.height}),h=e.find(\"div.\\\nlh-element-screenshot__image\",a);h.style.width=c.width+\"px\",h.style.height=c.height+\"px\",h.style.backgroundPositionY=-(d.screenshot.top*l)+\"px\",h.style.backgroundPositionX=-(d.screenshot.left*l)+\"px\",h.style.backgroundSize=`${t.width*l}px ${t.height*l}px`;let p=e.find(\"div.lh-element-screenshot__element-marker\",a);p.style.width=n.width*l+\"px\",p.style.height=n.height*l+\"px\",p.style.left=d.clip.left*l+\"px\",p.style.top=d.clip.top*l+\"px\";let g=e.find(\"div.lh-element-screenshot__mask\",a);return g.style.width=c.width+\"px\",g.style.height=c.height+\"px\",o.renderClipPathInScreenshot(e,g,d.clip,n,s),a}};var gt=[\"http://\",\"https://\",\"data:\"],mt=[\"bytes\",\"numeric\",\"ms\",\"timespanMs\"],X=class{constructor(e,t={}){this._dom=e,this._fullPageScreenshot=t.fullPageScreenshot,this._entities=t.entities}render(e){switch(e.type){case\"filmstrip\":return this._renderFilmstrip(e);case\"list\":return this._renderList(e);case\"checklist\":return this._renderChecklist(e);case\"table\":case\"opportunity\":return this._renderT\\\nable(e);case\"network-tree\":case\"criticalrequestchain\":return Y.render(this._dom,e,this);case\"screenshot\":case\"debugdata\":case\"treemap-data\":return null;default:return this._renderUnknown(e.type,e)}}_renderBytes(e){let t=m.i18n.formatBytesToKiB(e.value,e.granularity||.1),n=this._renderText(t);return n.title=m.i18n.formatBytes(e.value),n}_renderMilliseconds(e){let t;return e.displayUnit===\"duration\"?t=m.i18n.formatDuration(e.value):t=m.i18n.formatMilliseconds(e.value,e.granularity||10),this._renderText(t)}renderTextURL(e){let t=e,n,r,i;try{let l=E.parseURL(t);n=l.file===\"/\"?l.origin:l.file,r=l.file===\"/\"||l.hostname===\"\"?\"\":`(${l.hostname})`,i=t}catch{n=t}let a=this._dom.createElement(\"div\",\"lh-text__url\");if(a.append(this._renderLink({text:n,url:t})),r){let l=this._renderText(r);l.classList.add(\"lh-text__url-host\"),a.append(l)}return i&&(a.title=t,a.dataset.url=t),a}_renderLink(e){let t=this._dom.createElement(\"a\");if(this._dom.safelySetHref(t,e.url),!t.href){let n=this._renderText(e.te\\\nxt);return n.classList.add(\"lh-link\"),n}return t.rel=\"noopener\",t.target=\"_blank\",t.textContent=e.text,t.classList.add(\"lh-link\"),t}_renderText(e){let t=this._dom.createElement(\"div\",\"lh-text\");return t.textContent=e,t}_renderNumeric(e){let t=m.i18n.formatNumber(e.value,e.granularity||.1),n=this._dom.createElement(\"div\",\"lh-numeric\");return n.textContent=t,n}_renderThumbnail(e){let t=this._dom.createElement(\"img\",\"lh-thumbnail\"),n=e;return t.src=n,t.title=n,t.alt=\"\",t}_renderUnknown(e,t){console.error(`Unknown details type: ${e}`,t);let n=this._dom.createElement(\"details\",\"lh-unknown\");return this._dom.createChildOf(n,\"summary\").textContent=`We don\\'t know how to render audit details of type \\\\`${e}\\\\`. The Lighthouse version that collected this data is likely newer than the Lighthouse version of the report renderer. Expand for the raw JSON.`,this._dom.createChildOf(n,\"pre\").textContent=JSON.stringify(t,null,2),n}_renderTableValue(e,t){if(e==null)return null;if(typeof e==\"object\")switch(e\\\n.type){case\"code\":return this._renderCode(e.value);case\"link\":return this._renderLink(e);case\"node\":return this.renderNode(e);case\"numeric\":return this._renderNumeric(e);case\"text\":return this._renderText(e.value);case\"source-location\":return this.renderSourceLocation(e);case\"url\":return this.renderTextURL(e.value);default:return this._renderUnknown(e.type,e)}switch(t.valueType){case\"bytes\":{let n=Number(e);return this._renderBytes({value:n,granularity:t.granularity})}case\"code\":{let n=String(e);return this._renderCode(n)}case\"ms\":{let n={value:Number(e),granularity:t.granularity,displayUnit:t.displayUnit};return this._renderMilliseconds(n)}case\"numeric\":{let n=Number(e);return this._renderNumeric({value:n,granularity:t.granularity})}case\"text\":{let n=String(e);return this._renderText(n)}case\"thumbnail\":{let n=String(e);return this._renderThumbnail(n)}case\"timespanMs\":{let n=Number(e);return this._renderMilliseconds({value:n})}case\"url\":{let n=String(e);return gt.some(r=>n.startsWith(r\\\n))?this.renderTextURL(n):this._renderCode(n)}default:return this._renderUnknown(t.valueType,e)}}_getDerivedSubItemsHeading(e){return e.subItemsHeading?{key:e.subItemsHeading.key||\"\",valueType:e.subItemsHeading.valueType||e.valueType,granularity:e.subItemsHeading.granularity||e.granularity,displayUnit:e.subItemsHeading.displayUnit||e.displayUnit,label:\"\"}:null}_renderTableRow(e,t){let n=this._dom.createElement(\"tr\");for(let r of t){if(!r||!r.key){this._dom.createChildOf(n,\"td\",\"lh-table-column--empty\");continue}let i=e[r.key],a;if(i!=null&&(a=this._renderTableValue(i,r)),a){let l=`lh-table-column--${r.valueType}`;this._dom.createChildOf(n,\"td\",l).append(a)}else this._dom.createChildOf(n,\"td\",\"lh-table-column--empty\")}return n}_renderTableRowsFromItem(e,t){let n=this._dom.createFragment();if(n.append(this._renderTableRow(e,t)),!e.subItems)return n;let r=t.map(this._getDerivedSubItemsHeading);if(!r.some(Boolean))return n;for(let i of e.subItems.items){let a=this._renderTableRow(i,r);a.cla\\\nssList.add(\"lh-sub-item-row\"),n.append(a)}return n}_adornEntityGroupRow(e){let t=e.dataset.entity;if(!t)return;let n=this._entities?.find(i=>i.name===t);if(!n)return;let r=this._dom.find(\"td\",e);if(n.category){let i=this._dom.createElement(\"span\");i.classList.add(\"lh-audit__adorn\"),i.textContent=n.category,r.append(\" \",i)}if(n.isFirstParty){let i=this._dom.createElement(\"span\");i.classList.add(\"lh-audit__adorn\",\"lh-audit__adorn1p\"),i.textContent=m.strings.firstPartyChipLabel,r.append(\" \",i)}if(n.homepage){let i=this._dom.createElement(\"a\");i.href=n.homepage,i.target=\"_blank\",i.title=m.strings.openInANewTabTooltip,i.classList.add(\"lh-report-icon--external\"),r.append(\" \",i)}}_renderEntityGroupRow(e,t){let n={...t[0]};n.valueType=\"text\";let r=[n,...t.slice(1)],i=this._dom.createFragment();return i.append(this._renderTableRow(e,r)),this._dom.find(\"tr\",i).classList.add(\"lh-row--group\"),i}_getEntityGroupItems(e){let{items:t,headings:n,sortedBy:r}=e;if(!t.length||e.isEntityGrouped||!t.some(d=\\\n>d.entity))return[];let i=new Set(e.skipSumming||[]),a=[];for(let d of n)!d.key||i.has(d.key)||mt.includes(d.valueType)&&a.push(d.key);let l=n[0].key;if(!l)return[];let s=new Map;for(let d of t){let h=typeof d.entity==\"string\"?d.entity:void 0,p=s.get(h)||{[l]:h||m.strings.unattributable,entity:h};for(let g of a)p[g]=Number(p[g]||0)+Number(d[g]||0);s.set(h,p)}let c=[...s.values()];return r&&c.sort(k.getTableItemSortComparator(r)),c}_renderTable(e){if(!e.items.length)return this._dom.createElement(\"span\");let t=this._dom.createElement(\"table\",\"lh-table\"),n=this._dom.createChildOf(t,\"thead\"),r=this._dom.createChildOf(n,\"tr\");for(let l of e.headings){let c=`lh-table-column--${l.valueType||\"text\"}`,d=this._dom.createElement(\"div\",\"lh-text\");d.textContent=l.label,this._dom.createChildOf(r,\"th\",c).append(d)}let i=this._getEntityGroupItems(e),a=this._dom.createChildOf(t,\"tbody\");if(i.length)for(let l of i){let s=typeof l.entity==\"string\"?l.entity:void 0,c=this._renderEntityGroupRow(l,e.heading\\\ns);for(let h of e.items.filter(p=>p.entity===s))c.append(this._renderTableRowsFromItem(h,e.headings));let d=this._dom.findAll(\"tr\",c);s&&d.length&&(d.forEach(h=>h.dataset.entity=s),this._adornEntityGroupRow(d[0])),a.append(c)}else{let l=!0;for(let s of e.items){let c=this._renderTableRowsFromItem(s,e.headings),d=this._dom.findAll(\"tr\",c),h=d[0];if(typeof s.entity==\"string\"&&(h.dataset.entity=s.entity),e.isEntityGrouped&&s.entity)h.classList.add(\"lh-row--group\"),this._adornEntityGroupRow(h);else for(let p of d)p.classList.add(l?\"lh-row--even\":\"lh-row--odd\");l=!l,a.append(c)}}return t}_renderListValue(e){return e.type===\"node\"?this.renderNode(e):e.type===\"text\"?this._renderText(e.value):this.render(e)}_renderList(e){let t=this._dom.createElement(\"div\",\"lh-list\");return e.items.forEach(n=>{if(n.type===\"list-section\"){let i=this._dom.createElement(\"div\",\"lh-list-section\");n.title&&this._dom.createChildOf(i,\"div\",\"lh-list-section__title\").append(this._dom.convertMarkdownLinkSnippets(n.title\\\n)),n.description&&this._dom.createChildOf(i,\"div\",\"lh-list-section__description\").append(this._dom.convertMarkdownLinkSnippets(n.description));let a=this._renderListValue(n.value);a&&i.append(a),t.append(i);return}let r=this._renderListValue(n);r&&t.append(r)}),t}_renderChecklist(e){let t=this._dom.createElement(\"ul\",\"lh-checklist\");return Object.values(e.items).forEach(n=>{let r=this._dom.createChildOf(t,\"li\",\"lh-checklist-item\"),i=n.value?\"lh-report-plain-icon--checklist-pass\":\"lh-report-plain-icon--checklist-fail\";this._dom.createChildOf(r,\"span\",`lh-report-plain-icon ${i}`).textContent=n.label}),t}renderNode(e){let t=this._dom.createElement(\"span\",\"lh-node\");if(e.nodeLabel){let a=this._dom.createElement(\"div\");a.textContent=e.nodeLabel,t.append(a)}if(e.snippet){let a=this._dom.createElement(\"div\");a.classList.add(\"lh-node__snippet\"),a.textContent=e.snippet,t.append(a)}if(e.selector&&(t.title=e.selector),e.path&&t.setAttribute(\"data-path\",e.path),e.selector&&t.setAttribute(\"data-sel\\\nector\",e.selector),e.snippet&&t.setAttribute(\"data-snippet\",e.snippet),!this._fullPageScreenshot)return t;let n=e.lhId&&this._fullPageScreenshot.nodes[e.lhId];if(!n||n.width===0||n.height===0)return t;let r={width:147,height:100},i=V.render(this._dom,this._fullPageScreenshot.screenshot,n,r);return i&&t.prepend(i),t}renderSourceLocation(e){if(!e.url)return null;let t=`${e.url}:${e.line+1}:${e.column}`,n;e.original&&(n=`${e.original.file||\"<unmapped>\"}:${e.original.line+1}:${e.original.column}`);let r;if(e.urlProvider===\"network\"&&n)r=this._renderLink({url:e.url,text:n}),r.title=`maps to generated location ${t}`;else if(e.urlProvider===\"network\"&&!n)r=this.renderTextURL(e.url),this._dom.find(\".lh-link\",r).textContent+=`:${e.line+1}:${e.column}`;else if(e.urlProvider===\"comment\"&&n)r=this._renderText(`${n} (from source map)`),r.title=`${t} (from sourceURL)`;else if(e.urlProvider===\"comment\"&&!n)r=this._renderText(`${t} (from sourceURL)`);else return null;return r.classList.add(\"lh-source-\\\nlocation\"),r.setAttribute(\"data-source-url\",e.url),r.setAttribute(\"data-source-line\",String(e.line)),r.setAttribute(\"data-source-column\",String(e.column)),r}_renderFilmstrip(e){let t=this._dom.createElement(\"div\",\"lh-filmstrip\");for(let n of e.items){let r=this._dom.createChildOf(t,\"div\",\"lh-filmstrip__frame\"),i=this._dom.createChildOf(r,\"img\",\"lh-filmstrip__thumbnail\");i.src=n.data,i.alt=\"Screenshot\"}return t}_renderCode(e){let t=this._dom.createElement(\"pre\",\"lh-code\");return t.textContent=e,t}};var te=class{constructor(e){e===\"en-XA\"&&(e=\"de\"),this._locale=e,this._cachedNumberFormatters=new Map}_formatNumberWithGranularity(e,t,n={}){if(t!==void 0){let a=-Math.log10(t);Number.isInteger(a)||(console.warn(`granularity of ${t} is invalid. Using 1 instead`),t=1),t<1&&(n={...n},n.minimumFractionDigits=n.maximumFractionDigits=Math.ceil(a)),e=Math.round(e/t)*t,Object.is(e,-0)&&(e=0)}else Math.abs(e)<5e-4&&(e=0);let r,i=[n.minimumFractionDigits,n.maximumFractionDigits,n.style,n.unit,n.unitDi\\\nsplay,this._locale].join(\"\");return r=this._cachedNumberFormatters.get(i),r||(r=new Intl.NumberFormat(this._locale,n),this._cachedNumberFormatters.set(i,r)),r.format(e).replace(\" \",\"\\\\xA0\")}formatNumber(e,t){return this._formatNumberWithGranularity(e,t)}formatInteger(e){return this._formatNumberWithGranularity(e,1)}formatPercent(e){return new Intl.NumberFormat(this._locale,{style:\"percent\"}).format(e)}formatBytesToKiB(e,t=void 0){return this._formatNumberWithGranularity(e/1024,t)+\"\\\\xA0KiB\"}formatBytesToMiB(e,t=void 0){return this._formatNumberWithGranularity(e/1048576,t)+\"\\\\xA0MiB\"}formatBytes(e,t=1){return this._formatNumberWithGranularity(e,t,{style:\"unit\",unit:\"byte\",unitDisplay:\"long\"})}formatBytesWithBestUnit(e,t=.1){return e>=1048576?this.formatBytesToMiB(e,t):e>=1024?this.formatBytesToKiB(e,t):this._formatNumberWithGranularity(e,t,{style:\"unit\",unit:\"byte\",unitDisplay:\"narrow\"})}formatKbps(e,t=void 0){return this._formatNumberWithGranularity(e,t,{style:\"unit\",unit:\"kilobit-per-sec\\\nond\",unitDisplay:\"short\"})}formatMilliseconds(e,t=void 0){return this._formatNumberWithGranularity(e,t,{style:\"unit\",unit:\"millisecond\",unitDisplay:\"short\"})}formatSeconds(e,t=void 0){return this._formatNumberWithGranularity(e/1e3,t,{style:\"unit\",unit:\"second\",unitDisplay:\"narrow\"})}formatDateTime(e){let t={month:\"short\",day:\"numeric\",year:\"numeric\",hour:\"numeric\",minute:\"numeric\",timeZoneName:\"short\"},n;try{n=new Intl.DateTimeFormat(this._locale,t)}catch{t.timeZone=\"UTC\",n=new Intl.DateTimeFormat(this._locale,t)}return n.format(new Date(e))}formatDuration(e){let t=e/1e3;if(Math.round(t)===0)return\"None\";let n=[],r={day:3600*24,hour:3600,minute:60,second:1};return Object.keys(r).forEach(i=>{let a=r[i],l=Math.floor(t/a);if(l>0){t-=l*a;let s=this._formatNumberWithGranularity(l,1,{style:\"unit\",unit:i,unitDisplay:\"narrow\"});n.push(s)}}),n.join(\" \")}};function Ee(o){let e=o.createComponent(\"explodeyGauge\");return o.find(\".lh-exp-gauge-component\",e)}function Se(o,e,t){let n=o.find(\"div.lh-ex\\\np-gauge__wrapper\",e);n.className=\"\",n.classList.add(\"lh-exp-gauge__wrapper\",`lh-exp-gauge__wrapper--${k.calculateRating(t.score)}`),vt(o,n,t)}function ft(o,e,t){t=t||o/32;let n=o/t,r=.5*t,i=n+r+t,a=2*Math.PI*n,l=Math.acos(1-.5*Math.pow(.5*t/n,2))*n,s=2*Math.PI*i,c=Math.acos(1-.5*Math.pow(.5*t/i,2))*i;return{radiusInner:n,radiusOuter:i,circumferenceInner:a,circumferenceOuter:s,getArcLength:()=>Math.max(0,Number(e*a)),getMetricArcLength:(d,h=!1)=>{let p=h?0:2*c;return Math.max(0,Number(d*s-r-p))},endDiffInner:l,endDiffOuter:c,strokeWidth:t,strokeGap:r}}function vt(o,e,t){let i=Number(t.score),{radiusInner:a,radiusOuter:l,circumferenceInner:s,circumferenceOuter:c,getArcLength:d,getMetricArcLength:h,endDiffInner:p,endDiffOuter:g,strokeWidth:b,strokeGap:w}=ft(128,i),f=o.find(\"svg.lh-exp-gauge\",e);o.find(\".lh-exp-gauge__label\",f).textContent=t.title,f.setAttribute(\"viewBox\",[-64,-64/2,128,128/2].join(\" \")),f.style.setProperty(\"--stroke-width\",`${b}px`),f.style.setProperty(\"--circle-meas\",(2*\\\nMath.PI).toFixed(4));let u=o.find(\"g.lh-exp-gauge__outer\",e),v=o.find(\"g.lh-exp-gauge__inner\",e),_=o.find(\"circle.lh-cover\",u),x=o.find(\"circle.lh-exp-gauge__arc\",v),S=o.find(\"text.lh-exp-gauge__percentage\",v);u.style.setProperty(\"--scale-initial\",String(a/l)),u.style.setProperty(\"--radius\",`${l}px`),_.style.setProperty(\"--radius\",`${.5*(a+l)}px`),_.setAttribute(\"stroke-width\",String(w)),f.style.setProperty(\"--radius\",`${a}px`),x.setAttribute(\"stroke-dasharray\",`${d()} ${(s-d()).toFixed(4)}`),x.setAttribute(\"stroke-dashoffset\",String(.25*s-p)),S.textContent=Math.round(i*100).toString();let A=l+b,z=l-b,M=t.auditRefs.filter(y=>y.group===\"metrics\"&&y.weight),$=M.reduce((y,C)=>y+=C.weight,0),R=.25*c-g-.5*w,N=-.5*Math.PI;u.querySelectorAll(\".metric\").forEach(y=>{M.map(F=>`metric--${F.id}`).find(F=>y.classList.contains(F))||y.remove()}),M.forEach((y,C)=>{let L=y.acronym??y.id,F=!u.querySelector(`.metric--${L}`),T=o.maybeFind(`g.metric--${L}`,u)||o.createSVGElement(\"g\"),B=o.maybeFind(`.metric\\\n--${L} circle.lh-exp-gauge--faded`,u)||o.createSVGElement(\"circle\"),K=o.maybeFind(`.metric--${L} circle.lh-exp-gauge--miniarc`,u)||o.createSVGElement(\"circle\"),q=o.maybeFind(`.metric--${L} circle.lh-exp-gauge-hovertarget`,u)||o.createSVGElement(\"circle\"),P=o.maybeFind(`.metric--${L} text.metric__label`,u)||o.createSVGElement(\"text\"),H=o.maybeFind(`.metric--${L} text.metric__value`,u)||o.createSVGElement(\"text\");T.classList.add(\"metric\",`metric--${L}`),B.classList.add(\"lh-exp-gauge__arc\",\"lh-exp-gauge__arc--metric\",\"lh-exp-gauge--faded\"),K.classList.add(\"lh-exp-gauge__arc\",\"lh-exp-gauge__arc--metric\",\"lh-exp-gauge--miniarc\"),q.classList.add(\"lh-exp-gauge__arc\",\"lh-exp-gauge__arc--metric\",\"lh-exp-gauge-hovertarget\");let j=y.weight/$,de=h(j),he=y.result.score?y.result.score*j:0,pe=h(he),Pe=j*c,ue=h(j,!0),ge=k.calculateRating(y.result.score,y.result.scoreDisplayMode);T.style.setProperty(\"--metric-rating\",ge),T.style.setProperty(\"--metric-color\",`var(--color-${ge})`),T.style.setProperty(\"--\\\nmetric-offset\",`${R}`),T.style.setProperty(\"--i\",C.toString()),B.setAttribute(\"stroke-dasharray\",`${de} ${c-de}`),K.style.setProperty(\"--metric-array\",`${pe} ${c-pe}`),q.setAttribute(\"stroke-dasharray\",`${ue} ${c-ue-g}`),P.classList.add(\"metric__label\"),H.classList.add(\"metric__value\"),P.textContent=L,H.textContent=`+${Math.round(he*100)}`;let me=N+j*Math.PI,J=Math.cos(me),Z=Math.sin(me);switch(!0){case J>0:H.setAttribute(\"text-anchor\",\"end\");break;case J<0:P.setAttribute(\"text-anchor\",\"end\");break;case J===0:P.setAttribute(\"text-anchor\",\"middle\"),H.setAttribute(\"text-anchor\",\"middle\");break}switch(!0){case Z>0:P.setAttribute(\"dominant-baseline\",\"hanging\");break;case Z<0:H.setAttribute(\"dominant-baseline\",\"hanging\");break;case Z===0:P.setAttribute(\"dominant-baseline\",\"middle\"),H.setAttribute(\"dominant-baseline\",\"middle\");break}P.setAttribute(\"x\",(A*J).toFixed(2)),P.setAttribute(\"y\",(A*Z).toFixed(2)),H.setAttribute(\"x\",(z*J).toFixed(2)),H.setAttribute(\"y\",(z*Z).toFixed(2)),F&&(T.appendC\\\nhild(B),T.appendChild(K),T.appendChild(q),T.appendChild(P),T.appendChild(H),u.appendChild(T)),R-=Pe,N+=j*2*Math.PI});let D=u.querySelector(\".lh-exp-gauge-underhovertarget\")||o.createSVGElement(\"circle\");D.classList.add(\"lh-exp-gauge__arc\",\"lh-exp-gauge__arc--metric\",\"lh-exp-gauge-hovertarget\",\"lh-exp-gauge-underhovertarget\");let I=h(1,!0);if(D.setAttribute(\"stroke-dasharray\",`${I} ${c-I-g}`),D.isConnected||u.prepend(D),f.dataset.listenersSetup)return;f.dataset.listenersSetup=!0,De(f),f.addEventListener(\"pointerover\",y=>{if(y.target===f&&f.classList.contains(\"state--expanded\")){f.classList.remove(\"state--expanded\"),f.classList.contains(\"state--highlight\")&&(f.classList.remove(\"state--highlight\"),o.find(\".metric--highlight\",f).classList.remove(\"metric--highlight\"));return}if(!(y.target instanceof Element))return;let C=y.target.parentNode;if(C instanceof SVGElement){if(C&&C===v){f.classList.contains(\"state--expanded\")?f.classList.contains(\"state--highlight\")&&(f.classList.remove(\"state--h\\\nighlight\"),o.find(\".metric--highlight\",f).classList.remove(\"metric--highlight\")):f.classList.add(\"state--expanded\");return}if(C&&C.classList&&C.classList.contains(\"metric\")){let L=C.style.getPropertyValue(\"--metric-rating\");if(e.style.setProperty(\"--color-highlight\",`var(--color-${L}-secondary)`),!f.classList.contains(\"state--highlight\"))f.classList.add(\"state--highlight\"),C.classList.add(\"metric--highlight\");else{let F=o.find(\".metric--highlight\",f);C!==F&&(F.classList.remove(\"metric--highlight\"),C.classList.add(\"metric--highlight\"))}}}}),f.addEventListener(\"mouseleave\",()=>{f.classList.remove(\"state--highlight\"),f.querySelector(\".metric--highlight\")?.classList.remove(\"metric--highlight\")});async function De(y){if(await new Promise(P=>setTimeout(P,1e3)),y.classList.contains(\"state--expanded\"))return;let C=o.find(\".lh-exp-gauge__inner\",y),L=`uniq-${Math.random()}`;C.setAttribute(\"id\",L);let F=o.createSVGElement(\"use\");F.setAttribute(\"href\",`#${L}`),y.appendChild(F);let T=2.5;y.style.se\\\ntProperty(\"--peek-dur\",`${T}s`),y.classList.add(\"state--peek\",\"state--expanded\");let B=()=>{y.classList.remove(\"state--peek\",\"state--expanded\"),F.remove()},K=setTimeout(()=>{y.removeEventListener(\"mouseenter\",q),B()},T*1e3*1.5);function q(){clearTimeout(K),B()}y.addEventListener(\"mouseenter\",q,{once:!0})}}var ne=class extends G{_renderMetric(e){let t=this.dom.createComponent(\"metric\"),n=this.dom.find(\".lh-metric\",t);n.id=e.result.id;let r=k.calculateRating(e.result.score,e.result.scoreDisplayMode);n.classList.add(`lh-metric--${r}`);let i=this.dom.find(\".lh-metric__title\",t);i.textContent=e.result.title;let a=this.dom.find(\".lh-metric__value\",t);a.textContent=e.result.displayValue||\"\";let l=this.dom.find(\".lh-metric__description\",t);if(l.append(this.dom.convertMarkdownLinkSnippets(e.result.description)),e.result.scoreDisplayMode===\"error\"){l.textContent=\"\",a.textContent=\"Error!\";let s=this.dom.createChildOf(l,\"span\");s.textContent=e.result.errorMessage||\"Report error: no metric informat\\\nion\"}else e.result.scoreDisplayMode===\"notApplicable\"&&(a.textContent=\"--\");return n}_getScoringCalculatorHref(e){let t=e.filter(h=>h.group===\"metrics\"),n=e.find(h=>h.id===\"interactive\"),r=e.find(h=>h.id===\"first-cpu-idle\"),i=e.find(h=>h.id===\"first-meaningful-paint\");n&&t.push(n),r&&t.push(r),i&&typeof i.result.score==\"number\"&&t.push(i);let a=h=>Math.round(h*100)/100,s=[...t.map(h=>{let p;return typeof h.result.numericValue==\"number\"?(p=h.id===\"cumulative-layout-shift\"?a(h.result.numericValue):Math.round(h.result.numericValue),p=p.toString()):p=\"null\",[h.acronym||h.id,p]})];m.reportJson&&(s.push([\"device\",m.reportJson.configSettings.formFactor]),s.push([\"version\",m.reportJson.lighthouseVersion]));let c=new URLSearchParams(s),d=new URL(\"https://googlechrome.github.io/lighthouse/scorecalc/\");return d.hash=c.toString(),d.href}overallImpact(e,t){if(!e.result.metricSavings)return{overallImpact:0,overallLinearImpact:0};let n=0,r=0;for(let[i,a]of Object.entries(e.result.metricSavings)){if(a\\\n===void 0)continue;let l=t.find(g=>g.acronym===i);if(!l||l.result.score===null)continue;let s=l.result.numericValue;if(!s)continue;let c=a/s*l.weight;r+=c;let d=l.result.scoringOptions;if(!d)continue;let p=(E.computeLogNormalScore(d,s-a)-l.result.score)*l.weight;n+=p}return{overallImpact:n,overallLinearImpact:r}}render(e,t,n){let r=m.strings,i=this.dom.createElement(\"div\",\"lh-category\");i.id=e.id,i.append(this.renderCategoryHeader(e,t,n));let a=e.auditRefs.filter(p=>p.group===\"metrics\");if(a.length){let[p,g]=this.renderAuditGroup(t.metrics),b=this.dom.createElement(\"input\",\"lh-metrics-toggle__input\"),w=`lh-metrics-toggle${m.getUniqueSuffix()}`;b.setAttribute(\"aria-label\",\"Toggle the display of metric descriptions\"),b.type=\"checkbox\",b.id=w,p.prepend(b);let f=this.dom.find(\".lh-audit-group__header\",p),u=this.dom.createChildOf(f,\"label\",\"lh-metrics-toggle__label\");u.htmlFor=w;let v=this.dom.createChildOf(u,\"span\",\"lh-metrics-toggle__labeltext--show\"),_=this.dom.createChildOf(u,\"span\",\"lh\\\n-metrics-toggle__labeltext--hide\");v.textContent=m.strings.expandView,_.textContent=m.strings.collapseView;let x=this.dom.createElement(\"div\",\"lh-metrics-container\");if(p.insertBefore(x,g),a.forEach(S=>{x.append(this._renderMetric(S))}),i.querySelector(\".lh-gauge__wrapper\")){let S=this.dom.find(\".lh-category-header__description\",i),A=this.dom.createChildOf(S,\"div\",\"lh-metrics__disclaimer\"),z=this.dom.convertMarkdownLinkSnippets(r.varianceDisclaimer);A.append(z);let M=this.dom.createChildOf(A,\"a\",\"lh-calclink\");M.target=\"_blank\",M.textContent=r.calculatorLink,this.dom.safelySetHref(M,this._getScoringCalculatorHref(e.auditRefs))}p.classList.add(\"lh-audit-group--metrics\"),i.append(p)}let l=this.dom.createChildOf(i,\"div\",\"lh-filmstrip-container\"),c=e.auditRefs.find(p=>p.id===\"screenshot-thumbnails\")?.result;if(c?.details){l.id=c.id;let p=this.detailsRenderer.render(c.details);p&&l.append(p)}let d=this.renderFilterableSection(e,t,[\"insights\",\"diagnostics\"],a);if(d&&(d.classList.add(\"lh-perf\\\n-audits\"),i.append(d)),(!n||n?.gatherMode===\"navigation\")&&e.score!==null){let p=Ee(this.dom);Se(this.dom,p,e),this.dom.find(\".lh-score__gauge\",i).replaceWith(p)}return i}renderFilterableSection(e,t,n,r){if(n.some(u=>!t[u]))return null;let i=this.dom.createElement(\"div\"),a=u=>u.group??\"\",s=e.auditRefs.filter(u=>n.includes(a(u))).map(u=>{let{overallImpact:v,overallLinearImpact:_}=this.overallImpact(u,r),x=u.result.guidanceLevel||1,S=this.renderAudit(u);return{auditRef:u,auditEl:S,overallImpact:v,overallLinearImpact:_,guidanceLevel:x}}),c=s.filter(u=>!k.showAsPassed(u.auditRef.result)),d=s.filter(u=>k.showAsPassed(u.auditRef.result)),h={};for(let u of n){let v=this.renderAuditGroup(t[u]);v[0].classList.add(`lh-audit-group--${u}`),h[u]=v}function p(u){for(let v of s)if(u===\"All\")v.auditEl.hidden=!1;else{let _=v.auditRef.result.metricSavings?.[u]===void 0;v.auditEl.hidden=_}c.sort((v,_)=>{let x=v.auditRef.result.score||0,S=_.auditRef.result.score||0;if(x!==S)return x-S;if(u!==\"All\"){let A=\\\nv.auditRef.result.metricSavings?.[u]??-1,z=_.auditRef.result.metricSavings?.[u]??-1;if(A!==z)return z-A}return v.overallImpact!==_.overallImpact?_.overallImpact*_.guidanceLevel-v.overallImpact*v.guidanceLevel:v.overallImpact===0&&_.overallImpact===0&&v.overallLinearImpact!==_.overallLinearImpact?_.overallLinearImpact*_.guidanceLevel-v.overallLinearImpact*v.guidanceLevel:_.guidanceLevel-v.guidanceLevel});for(let v of c){if(!v.auditRef.group)continue;let _=h[a(v.auditRef)];if(!_)continue;let[x,S]=_;x.insertBefore(v.auditEl,S)}}let g=new Set;for(let u of c){let v=u.auditRef.result.metricSavings||{};for(let[_,x]of Object.entries(v))typeof x==\"number\"&&g.add(_)}let b=r.filter(u=>u.acronym&&g.has(u.acronym));b.length&&this.renderMetricAuditFilter(b,i,p),p(\"All\");for(let u of n)if(c.some(v=>a(v.auditRef)===u)){let v=h[u];if(!v)continue;i.append(v[0])}if(!d.length)return i;let w={auditRefsOrEls:d.map(u=>u.auditEl),groupDefinitions:t},f=this.renderClump(\"passed\",w);return i.append(f),i}renderMe\\\ntricAuditFilter(e,t,n){let r=this.dom.createElement(\"div\",\"lh-metricfilter\"),i=this.dom.createChildOf(r,\"span\",\"lh-metricfilter__text\");i.textContent=m.strings.showRelevantAudits;let a=[{acronym:\"All\",id:\"All\"},...e],l=m.getUniqueSuffix();for(let s of a){let c=`metric-${s.acronym}-${l}`,d=this.dom.createChildOf(r,\"input\",\"lh-metricfilter__radio\");d.type=\"radio\",d.name=`metricsfilter-${l}`,d.id=c;let h=this.dom.createChildOf(r,\"label\",\"lh-metricfilter__label\");h.htmlFor=c,h.title=\"result\"in s?s.result.title:\"\",h.textContent=s.acronym||s.id,s.acronym===\"All\"&&(d.checked=!0,h.classList.add(\"lh-metricfilter__label--active\")),t.append(r),d.addEventListener(\"input\",p=>{for(let b of t.querySelectorAll(\"label.lh-metricfilter__label\"))b.classList.toggle(\"lh-metricfilter__label--active\",b.htmlFor===c);t.classList.toggle(\"lh-category--filtered\",s.acronym!==\"All\"),n(s.acronym||\"All\");let g=t.querySelectorAll(\"div.lh-audit-group, details.lh-audit-group\");for(let b of g){b.hidden=!1;let w=Array.from\\\n(b.querySelectorAll(\"div.lh-audit\")),f=!!w.length&&w.every(u=>u.hidden);b.hidden=f}})}}};var re=class{constructor(e){this._dom=e,this._opts={}}renderReport(e,t,n){if(!this._dom.rootEl&&t){console.warn(\"Please adopt the new report API in renderer/api.js.\");let i=t.closest(\".lh-root\");i?this._dom.rootEl=i:(t.classList.add(\"lh-root\",\"lh-vars\"),this._dom.rootEl=t)}else this._dom.rootEl&&t&&(this._dom.rootEl=t);n&&(this._opts=n),this._dom.setLighthouseChannel(e.configSettings.channel||\"unknown\");let r=k.prepareReportResult(e);return this._dom.rootEl.textContent=\"\",this._dom.rootEl.append(this._renderReport(r)),this._opts.occupyEntireViewport&&this._dom.rootEl.classList.add(\"lh-max-viewport\"),this._dom.rootEl}_renderReportTopbar(e){let t=this._dom.createComponent(\"topbar\"),n=this._dom.find(\"a.lh-topbar__url\",t);return n.textContent=e.finalDisplayedUrl,n.title=e.finalDisplayedUrl,this._dom.safelySetHref(n,e.finalDisplayedUrl),t}_renderReportHeader(){let e=this._dom.createComponent(\"heading\"),\\\nt=this._dom.createComponent(\"scoresWrapper\");return this._dom.find(\".lh-scores-wrapper-placeholder\",e).replaceWith(t),e}_renderReportFooter(e){let t=this._dom.createComponent(\"footer\");return this._renderMetaBlock(e,t),this._dom.find(\".lh-footer__version_issue\",t).textContent=m.strings.footerIssue,this._dom.find(\".lh-footer__version\",t).textContent=e.lighthouseVersion,t}_renderMetaBlock(e,t){let n=k.getEmulationDescriptions(e.configSettings||{}),r=e.userAgent.match(/(\\\\w*Chrome\\\\/[\\\\d.]+)/),i=Array.isArray(r)?r[1].replace(\"/\",\" \").replace(\"Chrome\",\"Chromium\"):\"Chromium\",a=e.configSettings.channel,l=e.environment.benchmarkIndex.toFixed(0),s=e.environment.credits?.[\"axe-core\"],c=[`${m.strings.runtimeSettingsBenchmark}: ${l}`,`${m.strings.runtimeSettingsCPUThrottling}: ${n.cpuThrottling}`];n.screenEmulation&&c.push(`${m.strings.runtimeSettingsScreenEmulation}: ${n.screenEmulation}`),s&&c.push(`${m.strings.runtimeSettingsAxeVersion}: ${s}`);let d=m.strings.runtimeAnalysisWindow;e.gatherMode==\\\n=\"timespan\"?d=m.strings.runtimeAnalysisWindowTimespan:e.gatherMode===\"snapshot\"&&(d=m.strings.runtimeAnalysisWindowSnapshot);let h=[[\"date\",`Captured at ${m.i18n.formatDateTime(e.fetchTime)}`],[\"devices\",`${n.deviceEmulation} with Lighthouse ${e.lighthouseVersion}`,c.join(`\\n`)],[\"samples-one\",m.strings.runtimeSingleLoad,m.strings.runtimeSingleLoadTooltip],[\"stopwatch\",d],[\"networkspeed\",`${n.summary}`,`${m.strings.runtimeSettingsNetworkThrottling}: ${n.networkThrottling}`],[\"chrome\",`Using ${i}`+(a?` with ${a}`:\"\"),`${m.strings.runtimeSettingsUANetwork}: \"${e.environment.networkUserAgent}\"`]],p=this._dom.find(\".lh-meta__items\",t);for(let[g,b,w]of h){let f=this._dom.createChildOf(p,\"li\",\"lh-meta__item\");if(f.textContent=b,w){f.classList.add(\"lh-tooltip-boundary\");let u=this._dom.createChildOf(f,\"div\",\"lh-tooltip\");u.textContent=w}f.classList.add(\"lh-report-icon\",`lh-report-icon--${g}`)}}_renderReportWarnings(e){if(!e.runWarnings||e.runWarnings.length===0)return this._dom.createElement(\"\\\ndiv\");let t=this._dom.createComponent(\"warningsToplevel\"),n=this._dom.find(\".lh-warnings__msg\",t);n.textContent=m.strings.toplevelWarningsMessage;let r=[];for(let i of e.runWarnings){let a=this._dom.createElement(\"li\");a.append(this._dom.convertMarkdownLinkSnippets(i)),r.push(a)}return this._dom.find(\"ul\",t).append(...r),t}_renderScoreGauges(e,t,n){let r=[],i=[];for(let a of Object.values(e.categories)){let s=(n[a.id]||t).renderCategoryScore(a,e.categoryGroups||{},{gatherMode:e.gatherMode}),c=this._dom.find(\"a.lh-gauge__wrapper, a.lh-fraction__wrapper\",s);c&&(this._dom.safelySetHref(c,`#${a.id}`),c.addEventListener(\"click\",d=>{if(!c.matches(\\'[href^=\"#\"]\\'))return;let h=c.getAttribute(\"href\"),p=this._dom.rootEl;if(!h||!p)return;let g=this._dom.find(h,p);d.preventDefault(),g.scrollIntoView()}),this._opts.onPageAnchorRendered?.(c)),k.isPluginCategory(a.id)?i.push(s):r.push(s)}return[...r,...i]}_renderReport(e){m.apply({providedStrings:e.i18n.rendererFormattedStrings,i18n:new te(e.configSet\\\ntings.locale),reportJson:e});let t=new X(this._dom,{fullPageScreenshot:e.fullPageScreenshot??void 0,entities:e.entities}),n=new G(this._dom,t),r={performance:new ne(this._dom,t)},i=this._dom.createElement(\"div\");i.append(this._renderReportHeader());let a=this._dom.createElement(\"div\",\"lh-container\"),l=this._dom.createElement(\"div\",\"lh-report\");l.append(this._renderReportWarnings(e));let s;Object.keys(e.categories).length===1?i.classList.add(\"lh-header--solo-category\"):s=this._dom.createElement(\"div\",\"lh-scores-header\");let d=this._dom.createElement(\"div\");if(d.classList.add(\"lh-scorescale-wrap\"),d.append(this._dom.createComponent(\"scorescale\")),s){let b=this._dom.find(\".lh-scores-container\",i);s.append(...this._renderScoreGauges(e,n,r)),b.append(s,d);let w=this._dom.createElement(\"div\",\"lh-sticky-header\");w.append(...this._renderScoreGauges(e,n,r)),a.append(w)}let h=this._dom.createElement(\"div\",\"lh-categories\");l.append(h);let p={gatherMode:e.gatherMode};for(let b of Object.values(e.c\\\nategories)){let w=r[b.id]||n;w.dom.createChildOf(h,\"div\",\"lh-category-wrapper\").append(w.render(b,e.categoryGroups,p))}n.injectFinalScreenshot(h,e.audits,d);let g=this._dom.createFragment();return this._opts.omitGlobalStyles||g.append(this._dom.createComponent(\"styles\")),this._opts.omitTopbar||g.append(this._renderReportTopbar(e)),g.append(a),l.append(this._renderReportFooter(e)),a.append(i,l),e.fullPageScreenshot&&V.installFullPageScreenshot(this._dom.rootEl,e.fullPageScreenshot.screenshot),g}};function W(o,e){let t=o.rootEl;typeof e>\"u\"?t.classList.toggle(\"lh-dark\"):t.classList.toggle(\"lh-dark\",e)}var bt=typeof btoa<\"u\"?btoa:o=>Buffer.from(o).toString(\"base64\"),_t=typeof atob<\"u\"?atob:o=>Buffer.from(o,\"base64\").toString();async function wt(o,e){let t=new TextEncoder().encode(o);if(e.gzip)if(typeof CompressionStream<\"u\"){let i=new CompressionStream(\"gzip\"),a=i.writable.getWriter();a.write(t),a.close();let l=await new Response(i.readable).arrayBuffer();t=new Uint8Array(l)}else t=window\\\n.pako.gzip(o);let n=\"\",r=5e3;for(let i=0;i<t.length;i+=r)n+=String.fromCharCode(...t.subarray(i,i+r));return bt(n)}function yt(o,e){let t=_t(o),n=Uint8Array.from(t,r=>r.charCodeAt(0));return e.gzip?window.pako.ungzip(n,{to:\"string\"}):new TextDecoder().decode(n)}var Ce={toBase64:wt,fromBase64:yt};function se(){let o=window.location.host.endsWith(\".vercel.app\"),e=new URLSearchParams(window.location.search).has(\"dev\");return o?`https://${window.location.host}/gh-pages`:e?\"http://localhost:7333\":\"https://googlechrome.github.io/lighthouse\"}function ce(o){let e=o.generatedTime,t=o.fetchTime||e;return`${o.lighthouseVersion}-${o.finalDisplayedUrl}-${t}`}function xt(o,e,t){let n=new URL(e).origin;window.addEventListener(\"message\",function i(a){a.origin===n&&r&&a.data.opened&&(r.postMessage(o,n),window.removeEventListener(\"message\",i))});let r=window.open(e,t)}async function Ae(o,e,t){let n=new URL(e),r=!!window.CompressionStream;n.hash=await Ce.toBase64(JSON.stringify(o),{gzip:r}),r&&n.searchPa\\\nrams.set(\"gzip\",\"1\"),window.open(n.toString(),t)}async function Le(o){let e=\"viewer-\"+ce(o),t=se()+\"/viewer/\";await Ae({lhr:o},t,e)}async function ze(o){let e=\"viewer-\"+ce(o),t=se()+\"/viewer/\";xt({lhr:o},t,e)}function Me(o){if(!o.audits[\"script-treemap-data\"].details)throw new Error(\"no script treemap data found\");let t={lhr:{mainDocumentUrl:o.mainDocumentUrl,finalUrl:o.finalUrl,finalDisplayedUrl:o.finalDisplayedUrl,audits:{\"script-treemap-data\":o.audits[\"script-treemap-data\"]},configSettings:{locale:o.configSettings.locale}}},n=se()+\"/treemap/\",r=\"treemap-\"+ce(o);Ae(t,n,r)}var oe=class{constructor(e){this._dom=e,this._toggleEl,this._menuEl,this.onDocumentKeyDown=this.onDocumentKeyDown.bind(this),this.onToggleClick=this.onToggleClick.bind(this),this.onToggleKeydown=this.onToggleKeydown.bind(this),this.onMenuFocusOut=this.onMenuFocusOut.bind(this),this.onMenuKeydown=this.onMenuKeydown.bind(this),this._getNextMenuItem=this._getNextMenuItem.bind(this),this._getNextSelectableNode=this._get\\\nNextSelectableNode.bind(this),this._getPreviousMenuItem=this._getPreviousMenuItem.bind(this)}setup(e){this._toggleEl=this._dom.find(\".lh-topbar button.lh-tools__button\",this._dom.rootEl),this._toggleEl.addEventListener(\"click\",this.onToggleClick),this._toggleEl.addEventListener(\"keydown\",this.onToggleKeydown),this._menuEl=this._dom.find(\".lh-topbar div.lh-tools__dropdown\",this._dom.rootEl),this._menuEl.addEventListener(\"keydown\",this.onMenuKeydown),this._menuEl.addEventListener(\"click\",e)}close(){this._toggleEl.classList.remove(\"lh-active\"),this._toggleEl.setAttribute(\"aria-expanded\",\"false\"),this._menuEl.contains(this._dom.document().activeElement)&&this._toggleEl.focus(),this._menuEl.removeEventListener(\"focusout\",this.onMenuFocusOut),this._dom.document().removeEventListener(\"keydown\",this.onDocumentKeyDown)}open(e){this._toggleEl.classList.contains(\"lh-active\")?e.focus():this._menuEl.addEventListener(\"transitionend\",()=>{e.focus()},{once:!0}),this._toggleEl.classList.add(\"lh-active\"\\\n),this._toggleEl.setAttribute(\"aria-expanded\",\"true\"),this._menuEl.addEventListener(\"focusout\",this.onMenuFocusOut),this._dom.document().addEventListener(\"keydown\",this.onDocumentKeyDown)}onToggleClick(e){e.preventDefault(),e.stopImmediatePropagation(),this._toggleEl.classList.contains(\"lh-active\")?this.close():this.open(this._getNextMenuItem())}onToggleKeydown(e){switch(e.code){case\"ArrowUp\":e.preventDefault(),this.open(this._getPreviousMenuItem());break;case\"ArrowDown\":case\"Enter\":case\" \":e.preventDefault(),this.open(this._getNextMenuItem());break;default:}}onMenuKeydown(e){let t=e.target;switch(e.code){case\"ArrowUp\":e.preventDefault(),this._getPreviousMenuItem(t).focus();break;case\"ArrowDown\":e.preventDefault(),this._getNextMenuItem(t).focus();break;case\"Home\":e.preventDefault(),this._getNextMenuItem().focus();break;case\"End\":e.preventDefault(),this._getPreviousMenuItem().focus();break;default:}}onDocumentKeyDown(e){e.keyCode===27&&this.close()}onMenuFocusOut(e){let t=e.relatedTarge\\\nt;this._menuEl.contains(t)||this.close()}_getNextSelectableNode(e,t){let n=e.filter(i=>i instanceof HTMLElement).filter(i=>!(i.hasAttribute(\"disabled\")||window.getComputedStyle(i).display===\"none\")),r=t?n.indexOf(t)+1:0;return r>=n.length&&(r=0),n[r]}_getNextMenuItem(e){let t=Array.from(this._menuEl.childNodes);return this._getNextSelectableNode(t,e)}_getPreviousMenuItem(e){let t=Array.from(this._menuEl.childNodes).reverse();return this._getNextSelectableNode(t,e)}};var ie=class{constructor(e,t){this.lhr,this._reportUIFeatures=e,this._dom=t,this._dropDownMenu=new oe(this._dom),this._copyAttempt=!1,this.topbarEl,this.categoriesEl,this.stickyHeaderEl,this.highlightEl,this.onDropDownMenuClick=this.onDropDownMenuClick.bind(this),this.onKeyUp=this.onKeyUp.bind(this),this.onCopy=this.onCopy.bind(this),this.collapseAllDetails=this.collapseAllDetails.bind(this)}enable(e){this.lhr=e,this._dom.rootEl.addEventListener(\"keyup\",this.onKeyUp),this._dom.document().addEventListener(\"copy\",this.onCopy)\\\n,this._dropDownMenu.setup(this.onDropDownMenuClick),this._setUpCollapseDetailsAfterPrinting(),this._dom.find(\".lh-topbar__logo\",this._dom.rootEl).addEventListener(\"click\",()=>W(this._dom)),this._setupStickyHeader()}onDropDownMenuClick(e){e.preventDefault();let t=e.target;if(!(!t||!t.hasAttribute(\"data-action\"))){switch(t.getAttribute(\"data-action\")){case\"copy\":this.onCopyButtonClick();break;case\"print-summary\":this.collapseAllDetails(),this._print();break;case\"print-expanded\":this.expandAllDetails(),this._print();break;case\"save-json\":{let n=JSON.stringify(this.lhr,null,2);this._reportUIFeatures._saveFile(new Blob([n],{type:\"application/json\"}));break}case\"save-html\":{let n=this._reportUIFeatures.getReportHtml();try{this._reportUIFeatures._saveFile(new Blob([n],{type:\"text/html\"}))}catch(r){this._dom.fireEventOn(\"lh-log\",this._dom.document(),{cmd:\"error\",msg:\"Could not export as HTML. \"+r.message})}break}case\"open-viewer\":{this._dom.isDevTools()?Le(this.lhr):ze(this.lhr);break}case\"sav\\\ne-gist\":{this._reportUIFeatures.saveAsGist();break}case\"toggle-dark\":{W(this._dom);break}case\"view-unthrottled-trace\":this._reportUIFeatures._opts.onViewTrace?.()}this._dropDownMenu.close()}}onCopy(e){this._copyAttempt&&e.clipboardData&&(e.preventDefault(),e.clipboardData.setData(\"text/plain\",JSON.stringify(this.lhr,null,2)),this._dom.fireEventOn(\"lh-log\",this._dom.document(),{cmd:\"log\",msg:\"Report JSON copied to clipboard\"})),this._copyAttempt=!1}onCopyButtonClick(){this._dom.fireEventOn(\"lh-analytics\",this._dom.document(),{name:\"copy\"});try{this._dom.document().queryCommandSupported(\"copy\")&&(this._copyAttempt=!0,this._dom.document().execCommand(\"copy\")||(this._copyAttempt=!1,this._dom.fireEventOn(\"lh-log\",this._dom.document(),{cmd:\"warn\",msg:\"Your browser does not support copy to clipboard.\"})))}catch(e){this._copyAttempt=!1,this._dom.fireEventOn(\"lh-log\",this._dom.document(),{cmd:\"log\",msg:e.message})}}onKeyUp(e){(e.ctrlKey||e.metaKey)&&e.keyCode===80&&this._dropDownMenu.close()}ex\\\npandAllDetails(){this._dom.findAll(\".lh-categories details\",this._dom.rootEl).map(t=>t.open=!0)}collapseAllDetails(){this._dom.findAll(\".lh-categories details\",this._dom.rootEl).map(t=>t.open=!1)}_print(){this._reportUIFeatures._opts.onPrintOverride?this._reportUIFeatures._opts.onPrintOverride(this._dom.rootEl):self.print()}resetUIState(){this._dropDownMenu.close()}_getScrollParent(e){let{overflowY:t}=window.getComputedStyle(e);return t!==\"visible\"&&t!==\"hidden\"?e:e.parentElement?this._getScrollParent(e.parentElement):document}_setUpCollapseDetailsAfterPrinting(){\"onbeforeprint\"in self?self.addEventListener(\"afterprint\",this.collapseAllDetails):self.matchMedia(\"print\").addListener(t=>{t.matches?this.expandAllDetails():this.collapseAllDetails()})}_setupStickyHeader(){this.topbarEl=this._dom.find(\"div.lh-topbar\",this._dom.rootEl),this.categoriesEl=this._dom.find(\"div.lh-categories\",this._dom.rootEl),requestAnimationFrame(()=>requestAnimationFrame(()=>{try{this.stickyHeaderEl=this._dom.fi\\\nnd(\"div.lh-sticky-header\",this._dom.rootEl)}catch{return}this.highlightEl=this._dom.createChildOf(this.stickyHeaderEl,\"div\",\"lh-highlighter\");let e=this._getScrollParent(this._dom.find(\".lh-container\",this._dom.rootEl));e.addEventListener(\"scroll\",()=>this._updateStickyHeader());let t=e instanceof window.Document?document.documentElement:e;new window.ResizeObserver(()=>this._updateStickyHeader()).observe(t)}))}_updateStickyHeader(){if(!this.stickyHeaderEl)return;let e=this.topbarEl.getBoundingClientRect().bottom,t=this.categoriesEl.getBoundingClientRect().top,n=e>=t,i=Array.from(this._dom.rootEl.querySelectorAll(\".lh-category\")).filter(h=>h.getBoundingClientRect().top-window.innerHeight/2<0),a=i.length>0?i.length-1:0,l=this.stickyHeaderEl.querySelectorAll(\".lh-gauge__wrapper, .lh-fraction__wrapper\"),s=l[a],c=l[0].getBoundingClientRect().left,d=s.getBoundingClientRect().left-c;this.highlightEl.style.transform=`translate(${d}px)`,this.stickyHeaderEl.classList.toggle(\"lh-sticky-header--vi\\\nsible\",n)}};function kt(o,e){let t=e?new Date(e):new Date,n=t.toLocaleTimeString(\"en-US\",{hour12:!1}),r=t.toLocaleDateString(\"en-US\",{year:\"numeric\",month:\"2-digit\",day:\"2-digit\"}).split(\"/\");r.unshift(r.pop());let i=r.join(\"-\");return`${o}_${i}_${n}`.replace(/[/?<>\\\\\\\\:*|\"]/g,\"-\")}function Te(o){let e=new URL(o.finalDisplayedUrl).hostname;return kt(e,o.fetchTime)}function Et(o){return Array.from(o.tBodies[0].rows)}var ae=class{constructor(e,t={}){this.json,this._dom=e,this._opts=t,this._topbar=t.omitTopbar?null:new ie(this,e),this.onMediaQueryChange=this.onMediaQueryChange.bind(this)}initFeatures(e){this.json=e,this._fullPageScreenshot=E.getFullPageScreenshot(e),this._topbar&&(this._topbar.enable(e),this._topbar.resetUIState()),this._setupMediaQueryListeners(),this._setupThirdPartyFilter(),this._setupElementScreenshotOverlay(this._dom.rootEl);let t=this._dom.isDevTools()||this._opts.disableDarkMode||this._opts.disableAutoDarkModeAndFireworks;!t&&window.matchMedia(\"(prefers-color-scheme:\\\n dark)\").matches&&W(this._dom,!0);let r=[\"performance\",\"accessibility\",\"best-practices\",\"seo\"].every(s=>{let c=e.categories[s];return c&&c.score===1}),i=this._opts.disableFireworks||this._opts.disableAutoDarkModeAndFireworks;if(r&&!i&&(this._enableFireworks(),t||W(this._dom,!0)),e.categories.performance&&e.categories.performance.auditRefs.some(s=>!!(s.group===\"metrics\"&&e.audits[s.id].errorMessage))){let s=this._dom.find(\"input.lh-metrics-toggle__input\",this._dom.rootEl);s.checked=!0}this.json.audits[\"script-treemap-data\"]&&this.json.audits[\"script-treemap-data\"].details&&this.addButton({text:m.strings.viewTreemapLabel,icon:\"treemap\",onClick:()=>Me(this.json)}),this._opts.onViewTrace&&(e.configSettings.throttlingMethod===\"simulate\"?this._dom.find(\\'a[data-action=\"view-unthrottled-trace\"]\\',this._dom.rootEl).classList.remove(\"lh-hidden\"):this.addButton({text:m.strings.viewTraceLabel,onClick:()=>this._opts.onViewTrace?.()})),this._opts.getStandaloneReportHTML&&this._dom.find(\\'a[data-action\\\n=\"save-html\"]\\',this._dom.rootEl).classList.remove(\"lh-hidden\");for(let s of this._dom.findAll(\"[data-i18n]\",this._dom.rootEl)){let d=s.getAttribute(\"data-i18n\");s.textContent=m.strings[d]}}addButton(e){let t=this._dom.rootEl.querySelector(\".lh-audit-group--metrics\");if(!t)return;let n=t.querySelector(\".lh-buttons\");n||(n=this._dom.createChildOf(t,\"div\",\"lh-buttons\"));let r=[\"lh-button\"];e.icon&&(r.push(\"lh-report-icon\"),r.push(`lh-report-icon--${e.icon}`));let i=this._dom.createChildOf(n,\"button\",r.join(\" \"));return i.textContent=e.text,i.addEventListener(\"click\",e.onClick),i}resetUIState(){this._topbar&&this._topbar.resetUIState()}getReportHtml(){if(!this._opts.getStandaloneReportHTML)throw new Error(\"`getStandaloneReportHTML` is not set\");return this.resetUIState(),this._opts.getStandaloneReportHTML()}saveAsGist(){throw new Error(\"Cannot save as gist from base report\")}_enableFireworks(){this._dom.find(\".lh-scores-container\",this._dom.rootEl).classList.add(\"lh-score100\")}_setupMediaQ\\\nueryListeners(){let e=self.matchMedia(\"(max-width: 500px)\");e.addListener(this.onMediaQueryChange),this.onMediaQueryChange(e)}_resetUIState(){this._topbar&&this._topbar.resetUIState()}onMediaQueryChange(e){this._dom.rootEl.classList.toggle(\"lh-narrow\",e.matches)}_setupThirdPartyFilter(){let e=[\"uses-rel-preconnect\",\"third-party-facades\",\"network-dependency-tree-insight\"],t=[\"legacy-javascript\",\"legacy-javascript-insight\"];Array.from(this._dom.rootEl.querySelectorAll(\"table.lh-table\")).filter(i=>i.querySelector(\"td.lh-table-column--url, td.lh-table-column--source-location\")).filter(i=>{let a=i.closest(\".lh-audit\");if(!a)throw new Error(\".lh-table not within audit\");return!e.includes(a.id)}).forEach(i=>{let a=Et(i),l=a.filter(f=>!f.classList.contains(\"lh-sub-item-row\")),s=this._getThirdPartyRows(l,E.getFinalDisplayedUrl(this.json)),c=a.some(f=>f.classList.contains(\"lh-row--even\")),d=this._dom.createComponent(\"3pFilter\"),h=this._dom.find(\"input\",d);h.addEventListener(\"change\",f=>{let u=f.\\\ntarget instanceof HTMLInputElement&&!f.target.checked,v=!0,_=l[0];for(;_;){let x=u&&s.includes(_);do _.classList.toggle(\"lh-row--hidden\",x),c&&(_.classList.toggle(\"lh-row--even\",!x&&v),_.classList.toggle(\"lh-row--odd\",!x&&!v)),_=_.nextElementSibling;while(_&&_.classList.contains(\"lh-sub-item-row\"));x||(v=!v)}});let p=s.filter(f=>!f.classList.contains(\"lh-row--group\")).length;this._dom.find(\".lh-3p-filter-count\",d).textContent=`${p}`,this._dom.find(\".lh-3p-ui-string\",d).textContent=m.strings.thirdPartyResourcesLabel;let g=s.length===l.length,b=!s.length;if((g||b)&&(this._dom.find(\"div.lh-3p-filter\",d).hidden=!0),!i.parentNode)return;i.parentNode.insertBefore(d,i);let w=i.closest(\".lh-audit\");if(!w)throw new Error(\".lh-table not within audit\");t.includes(w.id)&&!g&&h.click()})}_setupElementScreenshotOverlay(e){this._fullPageScreenshot&&V.installOverlayFeature({dom:this._dom,rootEl:e,overlayContainerEl:e,fullPageScreenshot:this._fullPageScreenshot})}_getThirdPartyRows(e,t){let n=E.getEnti\\\ntyFromUrl(t,this.json.entities),r=this.json.entities?.find(a=>a.isFirstParty===!0)?.name,i=[];for(let a of e){if(r){if(!a.dataset.entity||a.dataset.entity===r)continue}else{let l=a.querySelector(\"div.lh-text__url\");if(!l)continue;let s=l.dataset.url;if(!s||!(E.getEntityFromUrl(s,this.json.entities)!==n))continue}i.push(a)}return i}_saveFile(e){let t=e.type.match(\"json\")?\".json\":\".html\",n=Te({finalDisplayedUrl:E.getFinalDisplayedUrl(this.json),fetchTime:this.json.fetchTime})+t;this._opts.onSaveFileOverride?this._opts.onSaveFileOverride(e,n):this._dom.saveFile(e,n)}};function Fe(o,e={}){let t=document.createElement(\"article\");t.classList.add(\"lh-root\",\"lh-vars\");let n=new ee(t.ownerDocument,t);return new re(n).renderReport(o,t,e),new ae(n,e).initFeatures(o),t}var le=class{constructor(e){this.el=e;let t=document.createElement(\"style\");if(t.textContent=`\\n      #lh-log {\\n        position: fixed;\\n        background-color: #323232;\\n        color: #fff;\\n        min-height: 48px;\\n        min-wi\\\ndth: 288px;\\n        padding: 16px 24px;\\n        box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.26);\\n        border-radius: 2px;\\n        margin: 12px;\\n        font-size: 14px;\\n        cursor: default;\\n        transition: transform 0.3s, opacity 0.3s;\\n        transform: translateY(100px);\\n        opacity: 0;\\n        bottom: 0;\\n        left: 0;\\n        z-index: 3;\\n        display: flex;\\n        flex-direction: row;\\n        justify-content: center;\\n        align-items: center;\\n      }\\n      \\n      #lh-log.lh-show {\\n        opacity: 1;\\n        transform: translateY(0);\\n      }\\n    `,!this.el.parentNode)throw new Error(\"element needs to be in the DOM\");this.el.parentNode.insertBefore(t,this.el),this._id=void 0}log(e,t=!0){this._id&&clearTimeout(this._id),this.el.textContent=e,this.el.classList.add(\"lh-show\"),t&&(this._id=setTimeout(()=>{this.el.classList.remove(\"lh-show\")},7e3))}warn(e){this.log(\"Warning: \"+e)}error(e){this.log(e),setTimeout(()=>{throw new Error(e)},0)}hide(){this._id&&clearTimeout\\\n(this._id),this.el.classList.remove(\"lh-show\")}};function St(){let o=window.__LIGHTHOUSE_JSON__,e=Fe(o,{occupyEntireViewport:!0,getStandaloneReportHTML(){return document.documentElement.outerHTML}});document.body.append(e),document.addEventListener(\"lh-analytics\",t=>{let n=t;\"gtag\"in window&&window.gtag(\"event\",n.detail.name,n.detail.data??{})}),document.addEventListener(\"lh-log\",t=>{let n=document.querySelector(\"div#lh-log\");if(!n)return;let r=new le(n),i=t.detail;switch(i.cmd){case\"log\":r.log(i.msg);break;case\"warn\":r.warn(i.msg);break;case\"error\":r.error(i.msg);break;case\"hide\":r.hide();break}})}window.__initLighthouseReport__=St;})();\\n/**\\n * @license\\n * Copyright 2017 Google LLC\\n * SPDX-License-Identifier: Apache-2.0\\n */\\n/**\\n * @license\\n * Copyright 2023 Google LLC\\n * SPDX-License-Identifier: Apache-2.0\\n */\\n/**\\n * @license\\n * Copyright 2020 Google LLC\\n * SPDX-License-Identifier: Apache-2.0\\n */\\n/**\\n * @license Copyright 2023 The Lighthouse Authors. All Rights Reserved.\\n * Licensed u\\\nnder the Apache License, Version 2.0 (the \"License\"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0\\n * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.\\n*/\\n/**\\n * @license\\n * Copyright 2018 Google LLC\\n * SPDX-License-Identifier: Apache-2.0\\n */\\n/**\\n * @license\\n * Copyright 2017 Google LLC\\n * SPDX-License-Identifier: Apache-2.0\\n *\\n * Dummy text for ensuring report robustness: <\\\\/script> pre$`post %%LIGHTHOUSE_JSON%%\\n * (this is handled by terser)\\n */\\n/**\\n * @license\\n * Copyright 2021 Google LLC\\n * SPDX-License-Identifier: Apache-2.0\\n */\\n'\n};\n\n// report/generator/report-generator.js\n/**\n * @license\n * Copyright 2017 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\nvar ReportGenerator = class _ReportGenerator {\n  static {\n    __name(this, \"ReportGenerator\");\n  }\n  /**\n   * Replaces all the specified strings in source without serial replacements.\n   * @param {string} source\n   * @param {!Array<{search: string, replacement: string}>} replacements\n   * @return {string}\n   */\n  static replaceStrings(source, replacements) {\n    if (replacements.length === 0) {\n      return source;\n    }\n    const firstReplacement = replacements[0];\n    const nextReplacements = replacements.slice(1);\n    return source.split(firstReplacement.search).map((part) => _ReportGenerator.replaceStrings(part, nextReplacements)).join(firstReplacement.replacement);\n  }\n  /**\n   * @param {unknown} object\n   * @return {string}\n   */\n  static sanitizeJson(object) {\n    return JSON.stringify(object).replace(/</g, \"\\\\u003c\").replace(/\\u2028/g, \"\\\\u2028\").replace(/\\u2029/g, \"\\\\u2029\");\n  }\n  /**\n   * Returns the standalone report HTML as a string with the report JSON and renderer JS inlined.\n   * @param {LHResult} lhr\n   * @return {string}\n   */\n  static generateReportHtml(lhr) {\n    const sanitizedJson = _ReportGenerator.sanitizeJson(lhr);\n    const sanitizedJavascript = reportAssets.REPORT_JAVASCRIPT.replace(/<\\//g, \"\\\\u003c/\");\n    return _ReportGenerator.replaceStrings(reportAssets.REPORT_TEMPLATE, [\n      { search: \"%%LIGHTHOUSE_JSON%%\", replacement: sanitizedJson },\n      { search: \"%%LIGHTHOUSE_JAVASCRIPT%%\", replacement: sanitizedJavascript }\n    ]);\n  }\n  /**\n   * Returns the standalone flow report HTML as a string with the report JSON and renderer JS inlined.\n   * @param {FlowResult} flow\n   * @return {string}\n   */\n  static generateFlowReportHtml(flow) {\n    const sanitizedJson = _ReportGenerator.sanitizeJson(flow);\n    const sanitizedJavascript = reportAssets.FLOW_REPORT_JAVASCRIPT.replace(/<\\//g, \"\\\\u003c/\");\n    return _ReportGenerator.replaceStrings(reportAssets.FLOW_REPORT_TEMPLATE, [\n      { search: \"%%LIGHTHOUSE_FLOW_JSON%%\", replacement: sanitizedJson },\n      { search: \"%%LIGHTHOUSE_FLOW_JAVASCRIPT%%\", replacement: sanitizedJavascript },\n      { search: \"/*%%LIGHTHOUSE_FLOW_CSS%%*/\", replacement: reportAssets.FLOW_REPORT_CSS }\n    ]);\n  }\n  /**\n   * Converts the results to a CSV formatted string\n   * Each row describes the result of 1 audit with\n   *  - the name of the category the audit belongs to\n   *  - the name of the audit\n   *  - a description of the audit\n   *  - the score type that is used for the audit\n   *  - the score value of the audit\n   *\n   * @param {LHResult} lhr\n   * @return {string}\n   */\n  static generateReportCSV(lhr) {\n    const CRLF = \"\\r\\n\";\n    const separator = \",\";\n    const escape = /* @__PURE__ */ __name((value) => `\"${value.replace(/\"/g, '\"\"')}\"`, \"escape\");\n    const rowFormatter = /* @__PURE__ */ __name((row) => row.map((value) => {\n      if (value === null) return \"null\";\n      return value.toString();\n    }).map(escape), \"rowFormatter\");\n    const rows = [];\n    const topLevelKeys = (\n      /** @type {const} */\n      [\"requestedUrl\", \"finalDisplayedUrl\", \"fetchTime\", \"gatherMode\"]\n    );\n    rows.push(rowFormatter(topLevelKeys));\n    rows.push(rowFormatter(topLevelKeys.map((key) => lhr[key] ?? null)));\n    rows.push([]);\n    rows.push([\"category\", \"score\"]);\n    for (const category of Object.values(lhr.categories)) {\n      rows.push(rowFormatter([\n        category.id,\n        category.score\n      ]));\n    }\n    rows.push([]);\n    rows.push([\"category\", \"audit\", \"score\", \"displayValue\", \"description\"]);\n    for (const category of Object.values(lhr.categories)) {\n      for (const auditRef of category.auditRefs) {\n        const audit = lhr.audits[auditRef.id];\n        if (!audit) continue;\n        rows.push(rowFormatter([\n          category.id,\n          auditRef.id,\n          audit.score,\n          audit.displayValue || \"\",\n          audit.description\n        ]));\n      }\n    }\n    return rows.map((row) => row.join(separator)).join(CRLF);\n  }\n  /**\n   * @param {LHResult|FlowResult} result\n   * @return {result is FlowResult}\n   */\n  static isFlowResult(result) {\n    return \"steps\" in result;\n  }\n  /**\n   * Creates the results output in a format based on the `mode`.\n   * @param {LHResult|FlowResult} result\n   * @param {LHResult['configSettings']['output']} outputModes\n   * @return {string|string[]}\n   */\n  static generateReport(result, outputModes) {\n    const outputAsArray = Array.isArray(outputModes);\n    if (typeof outputModes === \"string\") outputModes = [outputModes];\n    const output = outputModes.map((outputMode) => {\n      if (outputMode === \"html\") {\n        if (_ReportGenerator.isFlowResult(result)) {\n          return _ReportGenerator.generateFlowReportHtml(result);\n        }\n        return _ReportGenerator.generateReportHtml(result);\n      }\n      if (outputMode === \"csv\") {\n        if (_ReportGenerator.isFlowResult(result)) {\n          throw new Error(\"CSV output is not support for user flows\");\n        }\n        return _ReportGenerator.generateReportCSV(result);\n      }\n      if (outputMode === \"json\") {\n        return JSON.stringify(result, null, 2);\n      }\n      throw new Error(\"Invalid output mode: \" + outputMode);\n    });\n    return outputAsArray ? output : output[0];\n  }\n};\n\n// core/runner.js\ninit_lh_error();\ninit_root2();\ninit_esm_utils();\ninit_entity_classification();\ninit_url_utils();\n/**\n * @license\n * Copyright 2016 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\nvar Runner = class _Runner {\n  static {\n    __name(this, \"Runner\");\n  }\n  /**\n   * @param {LH.Artifacts} artifacts\n   * @param {{resolvedConfig: LH.Config.ResolvedConfig, computedCache: Map<string, ArbitraryEqualityMap>}} options\n   * @return {Promise<LH.RunnerResult|undefined>}\n   */\n  static async audit(artifacts, options) {\n    const { resolvedConfig, computedCache } = options;\n    const settings = resolvedConfig.settings;\n    try {\n      const runnerStatus = { msg: \"Audit phase\", id: \"lh:runner:audit\" };\n      lighthouse_logger_default.time(runnerStatus, \"verbose\");\n      const lighthouseRunWarnings = [];\n      if (settings.gatherMode && !settings.auditMode) return;\n      if (!resolvedConfig.audits) {\n        throw new Error(\"No audits to evaluate.\");\n      }\n      const auditResultsById = await _Runner._runAudits(\n        settings,\n        resolvedConfig.audits,\n        artifacts,\n        lighthouseRunWarnings,\n        computedCache\n      );\n      const resultsStatus = { msg: \"Generating results...\", id: \"lh:runner:generate\" };\n      lighthouse_logger_default.time(resultsStatus);\n      if (artifacts.LighthouseRunWarnings) {\n        lighthouseRunWarnings.push(...artifacts.LighthouseRunWarnings);\n      }\n      const axeVersion = artifacts.Accessibility?.version;\n      const credits = {\n        \"axe-core\": axeVersion\n      };\n      let categories = {};\n      if (resolvedConfig.categories) {\n        categories = ReportScoring.scoreAllCategories(resolvedConfig.categories, auditResultsById);\n      }\n      lighthouse_logger_default.timeEnd(resultsStatus);\n      lighthouse_logger_default.timeEnd(runnerStatus);\n      let fullPageScreenshot = artifacts.FullPageScreenshot;\n      if (resolvedConfig.settings.disableFullPageScreenshot || fullPageScreenshot instanceof Error) {\n        fullPageScreenshot = void 0;\n      }\n      const i18nLhr = {\n        lighthouseVersion,\n        requestedUrl: artifacts.URL.requestedUrl,\n        mainDocumentUrl: artifacts.URL.mainDocumentUrl,\n        finalDisplayedUrl: artifacts.URL.finalDisplayedUrl,\n        finalUrl: artifacts.URL.mainDocumentUrl,\n        fetchTime: artifacts.fetchTime,\n        gatherMode: artifacts.GatherContext.gatherMode,\n        runtimeError: _Runner.getArtifactRuntimeError(artifacts),\n        runWarnings: lighthouseRunWarnings,\n        userAgent: artifacts.HostUserAgent,\n        environment: {\n          networkUserAgent: artifacts.NetworkUserAgent,\n          hostUserAgent: artifacts.HostUserAgent,\n          benchmarkIndex: artifacts.BenchmarkIndex,\n          credits\n        },\n        audits: auditResultsById,\n        configSettings: settings,\n        categories,\n        categoryGroups: resolvedConfig.groups || void 0,\n        stackPacks: getStackPacks(artifacts.Stacks),\n        entities: await _Runner.getEntityClassification(artifacts, { computedCache }),\n        fullPageScreenshot,\n        timing: this._getTiming(artifacts),\n        i18n: {\n          rendererFormattedStrings: getRendererFormattedStrings(settings.locale),\n          icuMessagePaths: {}\n        }\n      };\n      i18nLhr.i18n.icuMessagePaths = replaceIcuMessages(i18nLhr, settings.locale);\n      const lhr = (\n        /** @type {LH.Result} */\n        i18nLhr\n      );\n      if (settings.auditMode) {\n        const path7 = _Runner._getDataSavePath(settings);\n        saveLhr(lhr, path7);\n      }\n      const report = ReportGenerator.generateReport(lhr, settings.output);\n      return { lhr, artifacts, report };\n    } catch (err) {\n      throw _Runner.createRunnerError(err, settings);\n    }\n  }\n  /**\n   * @param {LH.Artifacts} artifacts\n   * @param {LH.Artifacts.ComputedContext} context\n   */\n  static async getEntityClassification(artifacts, context) {\n    const devtoolsLog = artifacts.DevtoolsLog;\n    if (!devtoolsLog) return;\n    const classifiedEntities = await EntityClassification.request(\n      { URL: artifacts.URL, devtoolsLog },\n      context\n    );\n    const entities = [];\n    for (const [entity, entityUrls] of classifiedEntities.urlsByEntity) {\n      const uniqueOrigins = /* @__PURE__ */ new Set();\n      for (const url of entityUrls) {\n        const origin = url_utils_default.getOrigin(url);\n        if (origin) uniqueOrigins.add(origin);\n      }\n      const shortEntity = {\n        name: entity.name,\n        homepage: entity.homepage,\n        origins: [...uniqueOrigins]\n      };\n      if (entity === classifiedEntities.firstParty) shortEntity.isFirstParty = true;\n      if (entity.isUnrecognized) shortEntity.isUnrecognized = true;\n      if (entity.category) shortEntity.category = entity.category;\n      entities.push(shortEntity);\n    }\n    return entities;\n  }\n  /**\n   * User can run -G solo, -A solo, or -GA together\n   * -G and -A will run partial lighthouse pipelines,\n   * and -GA will run everything plus save artifacts and lhr to disk.\n   *\n   * @param {(runnerData: {resolvedConfig: LH.Config.ResolvedConfig}) => Promise<LH.Artifacts>} gatherFn\n   * @param {{resolvedConfig: LH.Config.ResolvedConfig, computedCache: Map<string, ArbitraryEqualityMap>}} options\n   * @return {Promise<LH.Artifacts>}\n   */\n  static async gather(gatherFn, options) {\n    const settings = options.resolvedConfig.settings;\n    try {\n      const sentryContext = Sentry.getContext();\n      Sentry.captureBreadcrumb({\n        message: \"Run started\",\n        category: \"lifecycle\",\n        data: sentryContext\n      });\n      if (settings.auditMode && !settings.gatherMode) {\n        const path7 = this._getDataSavePath(settings);\n        return loadArtifacts(path7);\n      }\n      const runnerStatus = { msg: \"Gather phase\", id: \"lh:runner:gather\" };\n      lighthouse_logger_default.time(runnerStatus, \"verbose\");\n      const artifacts = await gatherFn({ resolvedConfig: options.resolvedConfig });\n      lighthouse_logger_default.timeEnd(runnerStatus);\n      artifacts.Timing = lighthouse_logger_default.takeTimeEntries();\n      if (settings.gatherMode) {\n        const path7 = this._getDataSavePath(settings);\n        await saveArtifacts(artifacts, path7);\n      }\n      return artifacts;\n    } catch (err) {\n      throw _Runner.createRunnerError(err, settings);\n    }\n  }\n  /**\n   * @param {any} err\n   * @param {LH.Config.Settings} settings\n   */\n  static createRunnerError(err, settings) {\n    if (err.friendlyMessage) {\n      err.friendlyMessage = getFormatted(err.friendlyMessage, settings.locale);\n    }\n    Sentry.captureException(err, { level: \"fatal\" });\n    return err;\n  }\n  /**\n   * This handles both the auditMode case where gatherer entries need to be merged in and\n   * the gather/audit case where timingEntriesFromRunner contains all entries from this run,\n   * including those also in timingEntriesFromArtifacts.\n   * @param {LH.Artifacts} artifacts\n   * @return {LH.Result.Timing}\n   */\n  static _getTiming(artifacts) {\n    const timingEntriesFromArtifacts = artifacts.Timing || [];\n    const timingEntriesFromRunner = lighthouse_logger_default.takeTimeEntries();\n    const timingEntriesKeyValues = [\n      ...timingEntriesFromArtifacts,\n      ...timingEntriesFromRunner\n    ].map((entry) => (\n      /** @type {[string, PerformanceEntry]} */\n      [\n        // As entries can share a name and start time, dedupe based on the name, startTime and duration\n        `${entry.startTime}-${entry.name}-${entry.duration}`,\n        entry\n      ]\n    ));\n    const timingEntries = Array.from(new Map(timingEntriesKeyValues).values()).map((entry) => {\n      return {\n        // Don't spread entry because browser PerformanceEntries can't be spread.\n        // https://github.com/GoogleChrome/lighthouse/issues/8638\n        startTime: parseFloat(entry.startTime.toFixed(2)),\n        name: entry.name,\n        duration: parseFloat(entry.duration.toFixed(2)),\n        entryType: entry.entryType\n      };\n    }).sort((a, b) => a.startTime - b.startTime);\n    const gatherEntry = timingEntries.find((e) => e.name === \"lh:runner:gather\");\n    const auditEntry = timingEntries.find((e) => e.name === \"lh:runner:audit\");\n    const gatherTiming = gatherEntry?.duration || 0;\n    const auditTiming = auditEntry?.duration || 0;\n    return { entries: timingEntries, total: gatherTiming + auditTiming };\n  }\n  /**\n   * Run all audits with specified settings and artifacts.\n   * @param {LH.Config.Settings} settings\n   * @param {Array<LH.Config.AuditDefn>} audits\n   * @param {LH.Artifacts} artifacts\n   * @param {Array<string | LH.IcuMessage>} runWarnings\n   * @param {Map<string, ArbitraryEqualityMap>} computedCache\n   * @return {Promise<Record<string, LH.RawIcu<LH.Audit.Result>>>}\n   */\n  static async _runAudits(settings, audits, artifacts, runWarnings, computedCache) {\n    const status = { msg: \"Analyzing and running audits...\", id: \"lh:runner:auditing\" };\n    lighthouse_logger_default.time(status);\n    if (artifacts.settings) {\n      const overrides = {\n        locale: void 0,\n        gatherMode: void 0,\n        auditMode: void 0,\n        output: void 0,\n        channel: void 0\n      };\n      const normalizedGatherSettings = Object.assign({}, artifacts.settings, overrides);\n      const normalizedAuditSettings = Object.assign({}, settings, overrides);\n      const keys2 = /* @__PURE__ */ new Set([\n        ...Object.keys(normalizedGatherSettings),\n        ...Object.keys(normalizedAuditSettings)\n      ]);\n      for (const k of keys2) {\n        if (!isEqual_default(normalizedGatherSettings[k], normalizedAuditSettings[k])) {\n          throw new Error(\n            `Cannot change settings between gathering and auditing…\nDifference found at: \\`${k}\\`: ${JSON.stringify(normalizedGatherSettings[k], null, 2)}\nvs: ${JSON.stringify(normalizedAuditSettings[k], null, 2)}`\n          );\n        }\n      }\n      if (!isEqual_default(normalizedGatherSettings, normalizedAuditSettings)) {\n        throw new Error(\"Cannot change settings between gathering and auditing\");\n      }\n    }\n    const sharedAuditContext = {\n      settings,\n      computedCache\n    };\n    const auditResultsById = {};\n    for (const auditDefn of audits) {\n      const auditId = auditDefn.implementation.meta.id;\n      const auditResult = await _Runner._runAudit(\n        auditDefn,\n        artifacts,\n        sharedAuditContext,\n        runWarnings\n      );\n      auditResultsById[auditId] = auditResult;\n    }\n    lighthouse_logger_default.timeEnd(status);\n    return auditResultsById;\n  }\n  /**\n   * Checks that the audit's required artifacts exist and runs the audit if so.\n   * Otherwise returns error audit result.\n   * @param {LH.Config.AuditDefn} auditDefn\n   * @param {LH.Artifacts} artifacts\n   * @param {Pick<LH.Audit.Context, 'settings'|'computedCache'>} sharedAuditContext\n   * @param {Array<string | LH.IcuMessage>} runWarnings\n   * @return {Promise<LH.RawIcu<LH.Audit.Result>>}\n   * @private\n   */\n  static async _runAudit(auditDefn, artifacts, sharedAuditContext, runWarnings) {\n    const audit = auditDefn.implementation;\n    const status = {\n      msg: `Auditing: ${getFormatted(audit.meta.title, \"en-US\")}`,\n      id: `lh:audit:${audit.meta.id}`\n    };\n    lighthouse_logger_default.time(status);\n    let auditResult;\n    try {\n      if (artifacts.PageLoadError) throw artifacts.PageLoadError;\n      for (const artifactName of audit.meta.requiredArtifacts) {\n        const noArtifact = artifacts[artifactName] === void 0;\n        if (noArtifact) {\n          lighthouse_logger_default.warn(\n            \"Runner\",\n            `${artifactName} gatherer, required by audit ${audit.meta.id}, did not run.`\n          );\n          throw new LighthouseError(\n            LighthouseError.errors.MISSING_REQUIRED_ARTIFACT,\n            { artifactName }\n          );\n        }\n        if (artifacts[artifactName] instanceof Error) {\n          const artifactError = artifacts[artifactName];\n          lighthouse_logger_default.warn(\"Runner\", `${artifactName} gatherer, required by audit ${audit.meta.id}, encountered an error: ${artifactError.message}`);\n          const error = new LighthouseError(\n            LighthouseError.errors.ERRORED_REQUIRED_ARTIFACT,\n            { artifactName, errorMessage: artifactError.message },\n            { cause: artifactError }\n          );\n          error.expected = true;\n          throw error;\n        }\n      }\n      const auditOptions = Object.assign({}, audit.defaultOptions, auditDefn.options);\n      const auditContext = {\n        options: auditOptions,\n        ...sharedAuditContext\n      };\n      const requestedArtifacts = audit.meta.requiredArtifacts.concat(audit.meta.__internalOptionalArtifacts || []);\n      const narrowedArtifacts = requestedArtifacts.reduce(\n        (narrowedArtifacts2, artifactName) => {\n          const requestedArtifact = artifacts[artifactName];\n          narrowedArtifacts2[artifactName] = requestedArtifact;\n          return narrowedArtifacts2;\n        },\n        /** @type {LH.Artifacts} */\n        {}\n      );\n      const product = await audit.audit(narrowedArtifacts, auditContext);\n      runWarnings.push(...product.runWarnings || []);\n      auditResult = Audit.generateAuditResult(audit, product);\n    } catch (err) {\n      if (err.code !== \"MISSING_REQUIRED_ARTIFACT\" && err.code !== \"ERRORED_REQUIRED_ARTIFACT\") {\n        lighthouse_logger_default.warn(audit.meta.id, `Caught exception: ${err.message}`);\n      }\n      Sentry.captureException(err, { tags: { audit: audit.meta.id }, level: \"error\" });\n      const errorMessage = err.friendlyMessage ? err.friendlyMessage : err.message;\n      const stack = err.cause?.stack ?? err.stack;\n      auditResult = Audit.generateErrorAuditResult(audit, errorMessage, stack);\n    }\n    lighthouse_logger_default.timeEnd(status);\n    return auditResult;\n  }\n  /**\n   * Searches a pass's artifacts for any `lhrRuntimeError` error artifacts.\n   * Returns the first one found or `null` if none found.\n   * @param {LH.Artifacts} artifacts\n   * @return {LH.RawIcu<LH.Result['runtimeError']>|undefined}\n   */\n  static getArtifactRuntimeError(artifacts) {\n    const possibleErrorArtifacts = [\n      [\"PageLoadError\", artifacts.PageLoadError],\n      // Preferentially use `PageLoadError`, if it exists.\n      ...Object.entries(artifacts)\n      // Otherwise check amongst all artifacts.\n    ];\n    for (const [artifactKey, possibleErrorArtifact] of possibleErrorArtifacts) {\n      const isError = possibleErrorArtifact instanceof LighthouseError;\n      if (isError && possibleErrorArtifact.lhrRuntimeError) {\n        const errorMessage = possibleErrorArtifact.friendlyMessage || possibleErrorArtifact.message;\n        const stack = (\n          /** @type {any} */\n          possibleErrorArtifact.cause?.stack ?? possibleErrorArtifact.stack\n        );\n        return {\n          code: possibleErrorArtifact.code,\n          message: errorMessage,\n          errorStack: stack,\n          artifactKey\n        };\n      }\n    }\n    return void 0;\n  }\n  /**\n   * Returns list of audit names for external querying.\n   * @return {Array<string>}\n   */\n  static getAuditList() {\n    const ignoredFiles = [\n      \"audit.js\",\n      \"violation-audit.js\",\n      \"accessibility/axe-audit.js\",\n      \"multi-check-audit.js\",\n      \"byte-efficiency/byte-efficiency-audit.js\",\n      \"manual/manual-audit.js\",\n      \"insights/insight-audit.js\"\n    ];\n    const fileList = [\n      ...[\"accessibility\", \"audit.js\", \"autocomplete.js\", \"bf-cache.js\", \"bootup-time.js\", \"byte-efficiency\", \"clickjacking-mitigation.js\", \"csp-xss.js\", \"deprecations.js\", \"diagnostics.js\", \"dobetterweb\", \"errors-in-console.js\", \"final-screenshot.js\", \"has-hsts.js\", \"image-aspect-ratio.js\", \"image-size-responsive.js\", \"insights\", \"is-on-https.js\", \"layout-shifts.js\", \"long-tasks.js\", \"main-thread-tasks.js\", \"mainthread-work-breakdown.js\", \"manual\", \"metrics\", \"metrics.js\", \"network-requests.js\", \"network-rtt.js\", \"network-server-latency.js\", \"non-composited-animations.js\", \"oopif-iframe-test-audit.js\", \"origin-isolation.js\", \"predictive-perf.js\", \"redirects-http.js\", \"redirects.js\", \"resource-summary.js\", \"screenshot-thumbnails.js\", \"script-treemap-data.js\", \"seo\", \"server-response-time.js\", \"third-party-cookies.js\", \"trusted-types-xss.js\", \"unsized-images.js\", \"user-timings.js\", \"valid-source-maps.js\", \"violation-audit.js\"],\n      ...[\"charset.js\", \"doctype.js\", \"geolocation-on-start.js\", \"inspector-issues.js\", \"js-libraries.js\", \"notification-on-start.js\", \"paste-preventing-inputs.js\"].map((f) => `dobetterweb/${f}`),\n      ...[\"cumulative-layout-shift.js\", \"first-contentful-paint.js\", \"interaction-to-next-paint.js\", \"interactive.js\", \"largest-contentful-paint.js\", \"max-potential-fid.js\", \"speed-index.js\", \"total-blocking-time.js\"].map((f) => `metrics/${f}`),\n      ...[\"canonical.js\", \"crawlable-anchors.js\", \"hreflang.js\", \"http-status-code.js\", \"is-crawlable.js\", \"link-text.js\", \"manual\", \"meta-description.js\", \"robots-txt.js\"].map((f) => `seo/${f}`),\n      ...[\"structured-data.js\"].map((f) => `seo/manual/${f}`),\n      ...[\"accesskeys.js\", \"aria-allowed-attr.js\", \"aria-allowed-role.js\", \"aria-command-name.js\", \"aria-conditional-attr.js\", \"aria-deprecated-role.js\", \"aria-dialog-name.js\", \"aria-hidden-body.js\", \"aria-hidden-focus.js\", \"aria-input-field-name.js\", \"aria-meter-name.js\", \"aria-progressbar-name.js\", \"aria-prohibited-attr.js\", \"aria-required-attr.js\", \"aria-required-children.js\", \"aria-required-parent.js\", \"aria-roles.js\", \"aria-text.js\", \"aria-toggle-field-name.js\", \"aria-tooltip-name.js\", \"aria-treeitem-name.js\", \"aria-valid-attr-value.js\", \"aria-valid-attr.js\", \"axe-audit.js\", \"button-name.js\", \"bypass.js\", \"color-contrast.js\", \"definition-list.js\", \"dlitem.js\", \"document-title.js\", \"duplicate-id-aria.js\", \"empty-heading.js\", \"form-field-multiple-labels.js\", \"frame-title.js\", \"heading-order.js\", \"html-has-lang.js\", \"html-lang-valid.js\", \"html-xml-lang-mismatch.js\", \"identical-links-same-purpose.js\", \"image-alt.js\", \"image-redundant-alt.js\", \"input-button-name.js\", \"input-image-alt.j\\\ns\", \"label-content-name-mismatch.js\", \"label.js\", \"landmark-one-main.js\", \"link-in-text-block.js\", \"link-name.js\", \"list.js\", \"listitem.js\", \"manual\", \"meta-refresh.js\", \"meta-viewport.js\", \"object-alt.js\", \"select-name.js\", \"skip-link.js\", \"tabindex.js\", \"table-duplicate-name.js\", \"table-fake-caption.js\", \"target-size.js\", \"td-has-header.js\", \"td-headers-attr.js\", \"th-has-data-cells.js\", \"valid-lang.js\", \"video-caption.js\"].map((f) => `accessibility/${f}`),\n      ...[\"custom-controls-labels.js\", \"custom-controls-roles.js\", \"focus-traps.js\", \"focusable-controls.js\", \"interactive-element-affordance.js\", \"logical-tab-order.js\", \"managed-focus.js\", \"offscreen-content-hidden.js\", \"use-landmarks.js\", \"visual-order-follows-dom.js\"].map((f) => `accessibility/manual/${f}`),\n      ...[\"byte-efficiency-audit.js\", \"total-byte-weight.js\", \"unminified-css.js\", \"unminified-javascript.js\", \"unused-css-rules.js\", \"unused-javascript.js\"].map((f) => `byte-efficiency/${f}`),\n      ...[\"manual-audit.js\"].map((f) => `manual/${f}`),\n      ...[\"README.md\", \"cache-insight.js\", \"cls-culprits-insight.js\", \"document-latency-insight.js\", \"dom-size-insight.js\", \"duplicated-javascript-insight.js\", \"font-display-insight.js\", \"forced-reflow-insight.js\", \"image-delivery-insight.js\", \"inp-breakdown-insight.js\", \"insight-audit.js\", \"lcp-breakdown-insight.js\", \"lcp-discovery-insight.js\", \"legacy-javascript-insight.js\", \"modern-http-insight.js\", \"network-dependency-tree-insight.js\", \"render-blocking-insight.js\", \"slow-css-selector-insight.js\", \"third-parties-insight.js\", \"viewport-insight.js\"].map((f) => `insights/${f}`)\n    ];\n    return fileList.filter((f) => {\n      return /\\.js$/.test(f) && !ignoredFiles.includes(f);\n    }).sort();\n  }\n  /**\n   * Returns list of gatherer names for external querying.\n   * @return {Array<string>}\n   */\n  static getGathererList() {\n    const fileList = [\n      ...[\"accessibility.js\", \"anchor-elements.js\", \"bf-cache-failures.js\", \"console-messages.js\", \"css-usage.js\", \"devtools-log.js\", \"dobetterweb\", \"full-page-screenshot.js\", \"iframe-elements.js\", \"image-elements.js\", \"inputs.js\", \"inspector-issues.js\", \"js-usage.js\", \"link-elements.js\", \"main-document-content.js\", \"meta-elements.js\", \"network-user-agent.js\", \"scripts.js\", \"seo\", \"source-maps.js\", \"stacks.js\", \"stylesheets.js\", \"trace-elements.js\", \"trace.js\", \"viewport-dimensions.js\"],\n      ...[\"robots-txt.js\"].map((f) => `seo/${f}`),\n      ...[\"doctype.js\"].map((f) => `dobetterweb/${f}`)\n    ];\n    return fileList.filter((f) => /\\.js$/.test(f) && f !== \"gatherer.js\").sort();\n  }\n  /**\n   * Get path to use for -G and -A modes. Defaults to $CWD/latest-run\n   * @param {LH.Config.Settings} settings\n   * @return {string}\n   */\n  static _getDataSavePath(settings) {\n    const { auditMode, gatherMode } = settings;\n    if (typeof auditMode === \"string\") return path6.resolve(process.cwd(), auditMode);\n    if (typeof gatherMode === \"string\") return path6.resolve(process.cwd(), gatherMode);\n    return path6.join(process.cwd(), \"latest-run\");\n  }\n};\n\n// core/user-flow.js\ninit_process_global();\n\n// core/gather/snapshot-runner.js\ninit_process_global();\ninit_lighthouse_logger();\n\n// core/gather/driver.js\ninit_process_global();\ninit_lighthouse_logger();\n\n// core/gather/driver/execution-context.js\ninit_process_global();\ninit_lh();\ninit_page_functions();\n/**\n * @license\n * Copyright 2020 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\nvar ExecutionContext = class _ExecutionContext {\n  static {\n    __name(this, \"ExecutionContext\");\n  }\n  /** @param {LH.Gatherer.ProtocolSession} session */\n  constructor(session) {\n    this._session = session;\n    this._executionContextId = void 0;\n    this._executionContextIdentifiersCreated = 0;\n    session.on(\"Page.frameNavigated\", () => this.clearContextId());\n    session.on(\"Runtime.executionContextDestroyed\", (event) => {\n      if (event.executionContextId === this._executionContextId) {\n        this.clearContextId();\n      }\n    });\n  }\n  /**\n   * Returns the isolated context ID currently in use.\n   */\n  getContextId() {\n    return this._executionContextId;\n  }\n  /**\n   * Clears the remembered context ID. Use this method when we have knowledge that the runtime context\n   * we were using has been destroyed by the browser and is no longer available.\n   */\n  clearContextId() {\n    this._executionContextId = void 0;\n  }\n  /**\n   * Returns the cached isolated execution context ID or creates a new execution context for the main\n   * frame. The cached execution context is cleared on every gotoURL invocation, so a new one will\n   * always be created on the first call on a new page.\n   * @return {Promise<number>}\n   */\n  async _getOrCreateIsolatedContextId() {\n    if (typeof this._executionContextId === \"number\") return this._executionContextId;\n    await this._session.sendCommand(\"Page.enable\");\n    await this._session.sendCommand(\"Runtime.enable\");\n    const frameTreeResponse = await this._session.sendCommand(\"Page.getFrameTree\");\n    const mainFrameId2 = frameTreeResponse.frameTree.frame.id;\n    const isolatedWorldResponse = await this._session.sendCommand(\"Page.createIsolatedWorld\", {\n      frameId: mainFrameId2,\n      worldName: \"lighthouse_isolated_context\"\n    });\n    this._executionContextId = isolatedWorldResponse.executionContextId;\n    this._executionContextIdentifiersCreated++;\n    return isolatedWorldResponse.executionContextId;\n  }\n  /**\n   * Evaluate an expression in the given execution context; an undefined contextId implies the main\n   * page without isolation.\n   * @param {string} expression\n   * @param {number|undefined} contextId\n   * @param {number} timeout\n   * @return {Promise<*>}\n   */\n  async _evaluateInContext(expression, contextId, timeout) {\n    const uniqueExecutionContextIdentifier = contextId === void 0 ? void 0 : this._executionContextIdentifiersCreated;\n    const evaluationParams = {\n      // We need to explicitly wrap the raw expression for several purposes:\n      // 1. Ensure that the expression will be a native Promise and not a polyfill/non-Promise.\n      // 2. Ensure that errors in the expression are captured by the Promise.\n      // 3. Ensure that errors captured in the Promise are converted into plain-old JS Objects\n      //    so that they can be serialized properly b/c JSON.stringify(new Error('foo')) === '{}'\n      //\n      // `__lighthouseExecutionContextUniqueIdentifier` is only used by the FullPageScreenshot gatherer.\n      // See `getNodeDetails` in page-functions.\n      expression: `(function wrapInNativePromise() {\n        ${_ExecutionContext._cachedNativesPreamble};\n        globalThis.__lighthouseExecutionContextUniqueIdentifier =\n          ${uniqueExecutionContextIdentifier};\n        ${pageFunctions.esbuildFunctionWrapperString}\n        return new Promise(function (resolve) {\n          return Promise.resolve()\n            .then(_ => ${expression})\n            .catch(${pageFunctions.wrapRuntimeEvalErrorInBrowser})\n            .then(resolve);\n        });\n      }())\n      //# sourceURL=_lighthouse-eval.js`,\n      includeCommandLineAPI: true,\n      awaitPromise: true,\n      returnByValue: true,\n      timeout,\n      contextId\n    };\n    this._session.setNextProtocolTimeout(timeout);\n    const response = await this._session.sendCommand(\"Runtime.evaluate\", evaluationParams);\n    const ex = response.exceptionDetails;\n    if (ex) {\n      const elidedExpression = expression.replace(/\\s+/g, \" \").substring(0, 100);\n      const messageLines = [\n        \"Runtime.evaluate exception\",\n        `Expression: ${elidedExpression}\n---- (elided)`,\n        !ex.stackTrace ? `Parse error at: ${ex.lineNumber + 1}:${ex.columnNumber + 1}` : null,\n        ex.exception?.description || ex.text\n      ].filter(Boolean);\n      const evaluationError = new Error(messageLines.join(\"\\n\"));\n      return Promise.reject(evaluationError);\n    }\n    if (response.result === void 0) {\n      return Promise.reject(\n        new Error('Runtime.evaluate response did not contain a \"result\" object')\n      );\n    }\n    const value = response.result.value;\n    if (value?.__failedInBrowser) {\n      return Promise.reject(Object.assign(new Error(), value));\n    } else {\n      return value;\n    }\n  }\n  /**\n   * Evaluate an expression in the context of the current page. If useIsolation is true, the expression\n   * will be evaluated in a content script that has access to the page's DOM but whose JavaScript state\n   * is completely separate.\n   * Returns a promise that resolves on the expression's value.\n   *\n   * @deprecated Use `evaluate` instead! It has a better API, and unlike `evaluateAsync` doesn't sometimes\n   * execute invalid code.\n   * @param {string} expression\n   * @param {{useIsolation?: boolean}=} options\n   * @return {Promise<*>}\n   */\n  async evaluateAsync(expression, options = {}) {\n    const timeout = this._session.hasNextProtocolTimeout() ? this._session.getNextProtocolTimeout() : 6e4;\n    const contextId = options.useIsolation ? await this._getOrCreateIsolatedContextId() : void 0;\n    try {\n      return await this._evaluateInContext(expression, contextId, timeout);\n    } catch (err) {\n      if (contextId && err.message.includes(\"Cannot find context\")) {\n        this.clearContextId();\n        const freshContextId = await this._getOrCreateIsolatedContextId();\n        return this._evaluateInContext(expression, freshContextId, timeout);\n      }\n      throw err;\n    }\n  }\n  /**\n   * Evaluate a function in the context of the current page.\n   * If `useIsolation` is true, the function will be evaluated in a content script that has\n   * access to the page's DOM but whose JavaScript state is completely separate.\n   * Returns a promise that resolves on a value of `mainFn`'s return type.\n   * @template {unknown[]} T, R\n   * @param {((...args: T) => R)} mainFn The main function to call.\n   * @param {{args: T, useIsolation?: boolean, deps?: Array<Function|string>}} options `args` should\n   *   match the args of `mainFn`, and can be any serializable value. `deps` are functions that must be\n   *   defined for `mainFn` to work.\n   * @return {Promise<Awaited<R>>}\n   */\n  evaluate(mainFn, options) {\n    const argsSerialized = _ExecutionContext.serializeArguments(options.args);\n    const depsSerialized = _ExecutionContext.serializeDeps(options.deps);\n    const expression = `(() => {\n      ${depsSerialized}\n      return (${mainFn})(${argsSerialized});\n    })()`;\n    return this.evaluateAsync(expression, options);\n  }\n  /**\n   * Evaluate a function on every new frame from now on.\n   * @template {unknown[]} T\n   * @param {((...args: T) => void)} mainFn The main function to call.\n   * @param {{args: T, deps?: Array<Function|string>}} options `args` should\n   *   match the args of `mainFn`, and can be any serializable value. `deps` are functions that must be\n   *   defined for `mainFn` to work.\n   * @return {Promise<void>}\n   */\n  async evaluateOnNewDocument(mainFn, options) {\n    const argsSerialized = _ExecutionContext.serializeArguments(options.args);\n    const depsSerialized = _ExecutionContext.serializeDeps(options.deps);\n    const expression = `(() => {\n      ${_ExecutionContext._cachedNativesPreamble};\n      ${depsSerialized};\n      (${mainFn})(${argsSerialized});\n    })()\n    //# sourceURL=_lighthouse-eval.js`;\n    await this._session.sendCommand(\"Page.addScriptToEvaluateOnNewDocument\", { source: expression });\n  }\n  /**\n   * Cache native functions/objects inside window so we are sure polyfills do not overwrite the\n   * native implementations when the page loads.\n   * @return {Promise<void>}\n   */\n  async cacheNativesOnNewDocument() {\n    await this.evaluateOnNewDocument(() => {\n      window.__nativePromise = window.Promise;\n      window.__nativeURL = window.URL;\n      window.__nativePerformance = window.performance;\n      window.__nativeFetch = window.fetch;\n      window.__ElementMatches = window.Element.prototype.matches;\n      window.__HTMLElementBoundingClientRect = window.HTMLElement.prototype.getBoundingClientRect;\n    }, { args: [] });\n  }\n  /**\n   * Prefix every script evaluation with a shadowing of common globals that tend to be ponyfilled\n   * incorrectly by many sites. This allows functions to still refer to `Promise` instead of\n   * Lighthouse-specific backups like `__nativePromise` (injected by `cacheNativesOnNewDocument` above).\n   */\n  static _cachedNativesPreamble = [\n    \"const Promise = globalThis.__nativePromise || globalThis.Promise\",\n    \"const URL = globalThis.__nativeURL || globalThis.URL\",\n    \"const performance = globalThis.__nativePerformance || globalThis.performance\",\n    \"const fetch = globalThis.__nativeFetch || globalThis.fetch\"\n  ].join(\";\\n\");\n  /**\n   * Serializes an array of arguments for use in an `eval` string across the protocol.\n   * @param {unknown[]} args\n   * @return {string}\n   */\n  static serializeArguments(args) {\n    return args.map((arg) => arg === void 0 ? \"undefined\" : JSON.stringify(arg)).join(\",\");\n  }\n  /**\n   * Serializes an array of functions or strings.\n   *\n   * Also makes sure that an esbuild-bundled version of Lighthouse will\n   * continue to create working code to be executed within the browser.\n   * @param {Array<Function|string>=} deps\n   * @return {string}\n   */\n  static serializeDeps(deps17) {\n    deps17 = [pageFunctions.esbuildFunctionWrapperString, ...deps17 || []];\n    return deps17.map((dep) => {\n      if (typeof dep === \"function\") {\n        const output = dep.toString();\n        const runtimeName = pageFunctions.getRuntimeFunctionName(dep);\n        if (runtimeName !== dep.name) {\n          return `${output}; const ${dep.name} = ${runtimeName};`;\n        } else {\n          return output;\n        }\n      } else {\n        return dep;\n      }\n    }).join(\"\\n\");\n  }\n};\n\n// core/gather/driver/target-manager.js\ninit_process_global();\ninit_lighthouse_logger();\nimport EventEmitter4 from \"events\";\n\n// core/gather/session.js\ninit_process_global();\ninit_lighthouse_logger();\ninit_lh_error();\nimport EventEmitter3 from \"events\";\n/**\n * @license\n * Copyright 2020 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\nvar DEFAULT_PROTOCOL_TIMEOUT = 3e4;\nvar PPTR_BUFFER = 50;\nvar MAX_TIMEOUT = 2147483647 - PPTR_BUFFER;\nvar CrdpEventEmitter = (\n  /** @type {CrdpEventMessageEmitter} */\n  EventEmitter3\n);\nvar ProtocolSession = class extends CrdpEventEmitter {\n  static {\n    __name(this, \"ProtocolSession\");\n  }\n  /**\n   * @param {LH.Puppeteer.CDPSession} cdpSession\n   */\n  constructor(cdpSession) {\n    super();\n    this._cdpSession = cdpSession;\n    this._targetInfo = void 0;\n    this._nextProtocolTimeout = void 0;\n    this._handleProtocolEvent = this._handleProtocolEvent.bind(this);\n    this._cdpSession.on(\"*\", this._handleProtocolEvent);\n    let rej = /* @__PURE__ */ __name((_) => {\n    }, \"rej\");\n    this._targetCrashedPromise = /** @type {Promise<never>} */\n    new Promise((_, theRej) => rej = theRej);\n    this.on(\"Inspector.targetCrashed\", async () => {\n      lighthouse_logger_default.error(\"TargetManager\", \"Inspector.targetCrashed\");\n      void this.dispose();\n      rej(new LighthouseError(LighthouseError.errors.TARGET_CRASHED));\n    });\n  }\n  id() {\n    return this._cdpSession.id();\n  }\n  /**\n   * Re-emit protocol events from the underlying CDPSession.\n   * @template {keyof LH.CrdpEvents} E\n   * @param {E} method\n   * @param {LH.CrdpEvents[E]} params\n   */\n  _handleProtocolEvent(method, ...params) {\n    this.emit(method, ...params);\n  }\n  /** @param {LH.Crdp.Target.TargetInfo} targetInfo */\n  setTargetInfo(targetInfo) {\n    this._targetInfo = targetInfo;\n  }\n  /**\n   * @return {boolean}\n   */\n  hasNextProtocolTimeout() {\n    return this._nextProtocolTimeout !== void 0;\n  }\n  /**\n   * @return {number}\n   */\n  getNextProtocolTimeout() {\n    return this._nextProtocolTimeout || DEFAULT_PROTOCOL_TIMEOUT;\n  }\n  /**\n   * @param {number} ms\n   */\n  setNextProtocolTimeout(ms) {\n    if (ms > MAX_TIMEOUT) ms = MAX_TIMEOUT;\n    this._nextProtocolTimeout = ms;\n  }\n  /**\n   * @template {keyof LH.CrdpCommands} C\n   * @param {C} method\n   * @param {LH.CrdpCommands[C]['paramsType']} params\n   * @return {Promise<LH.CrdpCommands[C]['returnType']>}\n   */\n  sendCommand(method, ...params) {\n    const timeoutMs = this.getNextProtocolTimeout();\n    this._nextProtocolTimeout = void 0;\n    let timeout;\n    const timeoutPromise = new Promise((resolve, reject) => {\n      timeout = setTimeout(reject, timeoutMs, new LighthouseError(LighthouseError.errors.PROTOCOL_TIMEOUT, {\n        protocolMethod: method\n      }));\n    });\n    const resultPromise = this._cdpSession.send(method, ...params, {\n      // Add 50ms to the Puppeteer timeout to ensure the Lighthouse timeout finishes first.\n      timeout: timeoutMs + PPTR_BUFFER\n    }).catch((error) => {\n      lighthouse_logger_default.formatProtocol(\"method <= browser ERR\", { method }, \"error\");\n      throw LighthouseError.fromProtocolMessage(method, error);\n    });\n    const resultWithTimeoutPromise = Promise.race([resultPromise, timeoutPromise, this._targetCrashedPromise]);\n    return resultWithTimeoutPromise.finally(() => {\n      if (timeout) clearTimeout(timeout);\n    });\n  }\n  /**\n   * Send and if there's an error response, do not reject.\n   * @template {keyof LH.CrdpCommands} C\n   * @param {C} method\n   * @param {LH.CrdpCommands[C]['paramsType']} params\n   * @return {Promise<void>}\n   */\n  sendCommandAndIgnore(method, ...params) {\n    return this.sendCommand(method, ...params).catch((e) => lighthouse_logger_default.verbose(\"session\", method, e.message)).then((_) => void 0);\n  }\n  /**\n   * Disposes of a session so that it can no longer talk to Chrome.\n   * @return {Promise<void>}\n   */\n  async dispose() {\n    this._cdpSession.off(\"*\", this._handleProtocolEvent);\n    await this._cdpSession.detach().catch((e) => lighthouse_logger_default.verbose(\"session\", \"detach failed\", e.message));\n  }\n  onCrashPromise() {\n    return this._targetCrashedPromise;\n  }\n};\n\n// core/gather/driver/target-manager.js\n/**\n * @license\n * Copyright 2021 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\nvar ProtocolEventEmitter = (\n  /** @type {ProtocolEventMessageEmitter} */\n  EventEmitter4\n);\nvar TargetManager = class extends ProtocolEventEmitter {\n  static {\n    __name(this, \"TargetManager\");\n  }\n  /** @param {LH.Puppeteer.CDPSession} cdpSession */\n  constructor(cdpSession) {\n    super();\n    this._enabled = false;\n    this._rootCdpSession = cdpSession;\n    this._mainFrameId = \"\";\n    this._targetIdToTargets = /* @__PURE__ */ new Map();\n    this._executionContextIdToDescriptions = /* @__PURE__ */ new Map();\n    this._onSessionAttached = this._onSessionAttached.bind(this);\n    this._onFrameNavigated = this._onFrameNavigated.bind(this);\n    this._onExecutionContextCreated = this._onExecutionContextCreated.bind(this);\n    this._onExecutionContextDestroyed = this._onExecutionContextDestroyed.bind(this);\n    this._onExecutionContextsCleared = this._onExecutionContextsCleared.bind(this);\n  }\n  /**\n   * @param {LH.Crdp.Page.FrameNavigatedEvent} frameNavigatedEvent\n   */\n  async _onFrameNavigated(frameNavigatedEvent) {\n    if (frameNavigatedEvent.frame.parentId) return;\n    if (!this._enabled) return;\n    try {\n      await this._rootCdpSession.send(\"Target.setAutoAttach\", {\n        autoAttach: true,\n        flatten: true,\n        waitForDebuggerOnStart: true\n      });\n    } catch (err) {\n      if (this._enabled) throw err;\n    }\n  }\n  /**\n   * @param {string} sessionId\n   * @return {LH.Gatherer.ProtocolSession}\n   */\n  _findSession(sessionId) {\n    for (const { session, cdpSession } of this._targetIdToTargets.values()) {\n      if (cdpSession.id() === sessionId) return session;\n    }\n    throw new Error(`session ${sessionId} not found`);\n  }\n  /**\n   * @param {string} targetType\n   * @return {targetType is LH.Protocol.TargetType}\n   */\n  _isAcceptedTargetType(targetType) {\n    return targetType === \"page\" || targetType === \"iframe\" || targetType === \"worker\";\n  }\n  /**\n   * Returns the root session.\n   * @return {LH.Gatherer.ProtocolSession}\n   */\n  rootSession() {\n    const rootSessionId = this._rootCdpSession.id();\n    return this._findSession(rootSessionId);\n  }\n  mainFrameExecutionContexts() {\n    return [...this._executionContextIdToDescriptions.values()].filter((executionContext) => {\n      return executionContext.auxData.frameId === this._mainFrameId;\n    });\n  }\n  /**\n   * @param {LH.Puppeteer.CDPSession} cdpSession\n   */\n  async _onSessionAttached(cdpSession) {\n    const newSession = new ProtocolSession(cdpSession);\n    let targetType;\n    try {\n      const { targetInfo } = await newSession.sendCommand(\"Target.getTargetInfo\");\n      targetType = targetInfo.type;\n      if (!this._isAcceptedTargetType(targetType)) return;\n      const targetId = targetInfo.targetId;\n      if (this._targetIdToTargets.has(targetId)) return;\n      newSession.setTargetInfo(targetInfo);\n      const targetName = targetInfo.url || targetInfo.targetId;\n      lighthouse_logger_default.verbose(\"target-manager\", `target ${targetName} attached`);\n      const trueProtocolListener = this._getProtocolEventListener(targetType, newSession.id());\n      const protocolListener = trueProtocolListener;\n      cdpSession.on(\"*\", protocolListener);\n      cdpSession.on(\"sessionattached\", this._onSessionAttached);\n      const targetWithSession = {\n        target: targetInfo,\n        cdpSession,\n        session: newSession,\n        protocolListener\n      };\n      this._targetIdToTargets.set(targetId, targetWithSession);\n      await newSession.sendCommand(\"Network.enable\");\n      await newSession.sendCommand(\"Target.setAutoAttach\", {\n        autoAttach: true,\n        flatten: true,\n        waitForDebuggerOnStart: true\n      });\n    } catch (err) {\n      if (/Target closed/.test(err.message)) return;\n      if (/'Target.getTargetInfo' wasn't found/.test(err)) return;\n      if (targetType === \"worker\") {\n        lighthouse_logger_default.warn(\"target-manager\", `Issue attaching to worker target: ${err}`);\n        return;\n      }\n      throw err;\n    } finally {\n      await newSession.sendCommandAndIgnore(\"Runtime.runIfWaitingForDebugger\");\n    }\n  }\n  /**\n   * @param {LH.Crdp.Runtime.ExecutionContextCreatedEvent} event\n   */\n  _onExecutionContextCreated(event) {\n    if (event.context.name.match(/^__puppeteer_utility_world__/)) return;\n    if (event.context.name === \"lighthouse_isolated_context\") return;\n    this._executionContextIdToDescriptions.set(event.context.uniqueId, event.context);\n  }\n  /**\n   * @param {LH.Crdp.Runtime.ExecutionContextDestroyedEvent} event\n   */\n  _onExecutionContextDestroyed(event) {\n    this._executionContextIdToDescriptions.delete(event.executionContextUniqueId);\n  }\n  _onExecutionContextsCleared() {\n    this._executionContextIdToDescriptions.clear();\n  }\n  /**\n   * Returns a listener for all protocol events from session, and augments the\n   * event with the sessionId.\n   * @param {LH.Protocol.TargetType} targetType\n   * @param {string} sessionId\n   */\n  _getProtocolEventListener(targetType, sessionId) {\n    const onProtocolEvent = /* @__PURE__ */ __name((method, params) => {\n      const payload = (\n        /** @type {LH.Protocol.RawEventMessage} */\n        { method, params, targetType, sessionId }\n      );\n      this.emit(\"protocolevent\", payload);\n    }, \"onProtocolEvent\");\n    return onProtocolEvent;\n  }\n  /**\n   * @return {Promise<void>}\n   */\n  async enable() {\n    if (this._enabled) return;\n    this._enabled = true;\n    this._targetIdToTargets = /* @__PURE__ */ new Map();\n    this._executionContextIdToDescriptions = /* @__PURE__ */ new Map();\n    this._rootCdpSession.on(\"Page.frameNavigated\", this._onFrameNavigated);\n    this._rootCdpSession.on(\"Runtime.executionContextCreated\", this._onExecutionContextCreated);\n    this._rootCdpSession.on(\"Runtime.executionContextDestroyed\", this._onExecutionContextDestroyed);\n    this._rootCdpSession.on(\"Runtime.executionContextsCleared\", this._onExecutionContextsCleared);\n    await this._rootCdpSession.send(\"Page.enable\");\n    await this._rootCdpSession.send(\"Runtime.enable\");\n    this._mainFrameId = (await this._rootCdpSession.send(\"Page.getFrameTree\")).frameTree.frame.id;\n    await this._onSessionAttached(this._rootCdpSession);\n  }\n  /**\n   * @return {Promise<void>}\n   */\n  async disable() {\n    this._rootCdpSession.off(\"Page.frameNavigated\", this._onFrameNavigated);\n    this._rootCdpSession.off(\"Runtime.executionContextCreated\", this._onExecutionContextCreated);\n    this._rootCdpSession.off(\n      \"Runtime.executionContextDestroyed\",\n      this._onExecutionContextDestroyed\n    );\n    this._rootCdpSession.off(\"Runtime.executionContextsCleared\", this._onExecutionContextsCleared);\n    for (const { cdpSession, protocolListener } of this._targetIdToTargets.values()) {\n      cdpSession.off(\"*\", protocolListener);\n      cdpSession.off(\"sessionattached\", this._onSessionAttached);\n    }\n    await this._rootCdpSession.send(\"Page.disable\").catch((_) => {\n    });\n    await this._rootCdpSession.send(\"Runtime.disable\").catch((_) => {\n    });\n    this._enabled = false;\n    this._targetIdToTargets = /* @__PURE__ */ new Map();\n    this._executionContextIdToDescriptions = /* @__PURE__ */ new Map();\n    this._mainFrameId = \"\";\n  }\n};\n\n// core/gather/fetcher.js\ninit_process_global();\ninit_lh();\n/**\n * @license Copyright 2020 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\nvar Fetcher = class {\n  static {\n    __name(this, \"Fetcher\");\n  }\n  /**\n   * @param {LH.Gatherer.ProtocolSession} session\n   */\n  constructor(session) {\n    this.session = session;\n  }\n  /**\n   * Fetches any resource using the network directly.\n   *\n   * @param {string} url\n   * @param {{timeout: number}=} options timeout is in ms\n   * @return {Promise<FetchResponse>}\n   */\n  async fetchResource(url, options = { timeout: 2e3 }) {\n    if (global.isLightrider) {\n      return this._wrapWithTimeout(this._fetchWithFetchApi(url), options.timeout);\n    }\n    return this._fetchResourceOverProtocol(url, options);\n  }\n  /**\n   * @param {string} url\n   * @return {Promise<FetchResponse>}\n   */\n  async _fetchWithFetchApi(url) {\n    const response = await fetch(url);\n    let content = null;\n    try {\n      content = await response.text();\n    } catch {\n    }\n    return {\n      content,\n      status: response.status\n    };\n  }\n  /**\n   * @param {string} handle\n   * @param {{timeout: number}=} options,\n   * @return {Promise<string>}\n   */\n  async _readIOStream(handle, options = { timeout: 2e3 }) {\n    const startTime = Date.now();\n    let ioResponse;\n    let data31 = \"\";\n    while (!ioResponse || !ioResponse.eof) {\n      const elapsedTime = Date.now() - startTime;\n      if (elapsedTime > options.timeout) {\n        throw new Error(\"Waiting for the end of the IO stream exceeded the allotted time.\");\n      }\n      ioResponse = await this.session.sendCommand(\"IO.read\", { handle });\n      const responseData = ioResponse.base64Encoded ? Buffer.from(ioResponse.data, \"base64\").toString(\"utf-8\") : ioResponse.data;\n      data31 = data31.concat(responseData);\n    }\n    return data31;\n  }\n  /**\n   * @param {string} url\n   * @return {Promise<{stream: LH.Crdp.IO.StreamHandle|null, status: number|null}>}\n   */\n  async _loadNetworkResource(url) {\n    const frameTreeResponse = await this.session.sendCommand(\"Page.getFrameTree\");\n    const networkResponse = await this.session.sendCommand(\"Network.loadNetworkResource\", {\n      frameId: frameTreeResponse.frameTree.frame.id,\n      url,\n      options: {\n        disableCache: true,\n        includeCredentials: true\n      }\n    });\n    return {\n      stream: networkResponse.resource.success ? networkResponse.resource.stream || null : null,\n      status: networkResponse.resource.httpStatusCode || null\n    };\n  }\n  /**\n   * @param {string} url\n   * @param {{timeout: number}} options timeout is in ms\n   * @return {Promise<FetchResponse>}\n   */\n  async _fetchResourceOverProtocol(url, options) {\n    const startTime = Date.now();\n    const response = await this._wrapWithTimeout(this._loadNetworkResource(url), options.timeout);\n    const isOk = response.status && response.status >= 200 && response.status <= 299;\n    if (!response.stream || !isOk) return { status: response.status, content: null };\n    const timeout = options.timeout - (Date.now() - startTime);\n    const content = await this._readIOStream(response.stream, { timeout });\n    return { status: response.status, content };\n  }\n  /**\n   * @template T\n   * @param {Promise<T>} promise\n   * @param {number} ms\n   */\n  async _wrapWithTimeout(promise, ms) {\n    let timeoutHandle;\n    const timeoutPromise = new Promise((_, reject) => {\n      timeoutHandle = setTimeout(reject, ms, new Error(\"Timed out fetching resource\"));\n    });\n    const wrappedPromise = await Promise.race([promise, timeoutPromise]).finally(() => clearTimeout(timeoutHandle));\n    return wrappedPromise;\n  }\n};\n\n// core/gather/driver/network-monitor.js\ninit_process_global();\ninit_lighthouse_logger();\ninit_lh();\ninit_network_recorder();\ninit_network_request();\ninit_url_utils();\nimport { EventEmitter as EventEmitter5 } from \"events\";\n/**\n * @license\n * Copyright 2021 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\nvar NetworkMonitorEventEmitter = (\n  /** @type {NetworkMonitorEmitter} */\n  EventEmitter5\n);\nvar NetworkMonitor = class extends NetworkMonitorEventEmitter {\n  static {\n    __name(this, \"NetworkMonitor\");\n  }\n  /** @type {NetworkRecorder|undefined} */\n  _networkRecorder = void 0;\n  /** @type {Array<LH.Crdp.Page.Frame>} */\n  _frameNavigations = [];\n  /** @param {LH.Gatherer.Driver['targetManager']} targetManager */\n  constructor(targetManager) {\n    super();\n    this._targetManager = targetManager;\n    this._session = targetManager.rootSession();\n    this._onFrameNavigated = (event) => this._frameNavigations.push(event.frame);\n    this._onProtocolMessage = (event) => {\n      if (!this._networkRecorder) return;\n      this._networkRecorder.dispatch(event);\n    };\n  }\n  /**\n   * @return {Promise<void>}\n   */\n  async enable() {\n    if (this._networkRecorder) return;\n    this._frameNavigations = [];\n    this._networkRecorder = new NetworkRecorder();\n    const reEmit = /* @__PURE__ */ __name((event) => (r) => {\n      this.emit(event, r);\n      this._emitNetworkStatus();\n    }, \"reEmit\");\n    this._networkRecorder.on(\"requeststarted\", reEmit(\"requeststarted\"));\n    this._networkRecorder.on(\"requestfinished\", reEmit(\"requestfinished\"));\n    this._session.on(\"Page.frameNavigated\", this._onFrameNavigated);\n    this._targetManager.on(\"protocolevent\", this._onProtocolMessage);\n  }\n  /**\n   * @return {Promise<void>}\n   */\n  async disable() {\n    if (!this._networkRecorder) return;\n    this._session.off(\"Page.frameNavigated\", this._onFrameNavigated);\n    this._targetManager.off(\"protocolevent\", this._onProtocolMessage);\n    this._frameNavigations = [];\n    this._networkRecorder = void 0;\n  }\n  /** @return {Promise<{requestedUrl?: string, mainDocumentUrl?: string}>} */\n  async getNavigationUrls() {\n    const frameNavigations = this._frameNavigations;\n    if (!frameNavigations.length) return {};\n    const mainFrameNavigations2 = frameNavigations.filter((frame) => !frame.parentId);\n    if (!mainFrameNavigations2.length) lighthouse_logger_default.warn(\"NetworkMonitor\", \"No detected navigations\");\n    let requestedUrl = mainFrameNavigations2[0]?.url;\n    if (this._networkRecorder) {\n      const records = this._networkRecorder.getRawRecords();\n      let initialUrlRequest = records.find((record) => record.url === requestedUrl);\n      while (initialUrlRequest?.redirectSource) {\n        initialUrlRequest = initialUrlRequest.redirectSource;\n        requestedUrl = initialUrlRequest.url;\n      }\n    }\n    return {\n      requestedUrl,\n      mainDocumentUrl: mainFrameNavigations2[mainFrameNavigations2.length - 1]?.url\n    };\n  }\n  /**\n   * @return {Array<NetworkRequest>}\n   */\n  getInflightRequests() {\n    if (!this._networkRecorder) return [];\n    return this._networkRecorder.getRawRecords().filter((request) => !request.finished);\n  }\n  /**\n   * Returns whether the network is completely idle (i.e. there are 0 inflight network requests).\n   */\n  isIdle() {\n    return this._isIdlePeriod(0);\n  }\n  /**\n   * Returns whether any important resources for the page are in progress.\n   * Above-the-fold images and XHRs should be included.\n   * Tracking pixels, low priority images, and cross frame requests should be excluded.\n   * @return {boolean}\n   */\n  isCriticalIdle() {\n    if (!this._networkRecorder) return false;\n    const requests = this._networkRecorder.getRawRecords();\n    const rootFrameRequest = requests.find((r) => r.resourceType === \"Document\");\n    const rootFrameId = rootFrameRequest?.frameId;\n    return this._isIdlePeriod(\n      0,\n      // Return true if it should be a candidate for critical.\n      (request) => request.frameId === rootFrameId && // WebSocket and Server-sent Events are typically long-lived and shouldn't be considered critical.\n      request.resourceType !== \"WebSocket\" && request.resourceType !== \"EventSource\" && (request.priority === \"VeryHigh\" || request.priority === \"High\")\n    );\n  }\n  /**\n   * Returns whether the network is semi-idle (i.e. there are 2 or fewer inflight network requests).\n   */\n  is2Idle() {\n    return this._isIdlePeriod(2);\n  }\n  /**\n   * Returns whether the number of currently inflight requests is less than or\n   * equal to the number of allowed concurrent requests.\n   * @param {number} allowedRequests\n   * @param {(request: NetworkRequest) => boolean} [requestFilter]\n   * @return {boolean}\n   */\n  _isIdlePeriod(allowedRequests, requestFilter) {\n    if (!this._networkRecorder) return false;\n    const requests = this._networkRecorder.getRawRecords();\n    let inflightRequests = 0;\n    for (let i = 0; i < requests.length; i++) {\n      const request = requests[i];\n      if (request.finished) continue;\n      if (requestFilter?.(request) === false) continue;\n      if (NetworkRequest.isNonNetworkRequest(request)) continue;\n      inflightRequests++;\n    }\n    return inflightRequests <= allowedRequests;\n  }\n  /**\n   * Emits the appropriate network status event.\n   */\n  _emitNetworkStatus() {\n    const zeroQuiet = this.isIdle();\n    const twoQuiet = this.is2Idle();\n    const criticalQuiet = this.isCriticalIdle();\n    this.emit(zeroQuiet ? \"networkidle\" : \"networkbusy\");\n    this.emit(twoQuiet ? \"network-2-idle\" : \"network-2-busy\");\n    this.emit(criticalQuiet ? \"network-critical-idle\" : \"network-critical-busy\");\n    if (twoQuiet && zeroQuiet) lighthouse_logger_default.verbose(\"NetworkRecorder\", \"network fully-quiet\");\n    else if (twoQuiet && !zeroQuiet) lighthouse_logger_default.verbose(\"NetworkRecorder\", \"network semi-quiet\");\n    else lighthouse_logger_default.verbose(\"NetworkRecorder\", \"network busy\");\n  }\n  /**\n   * Finds all time periods where the number of inflight requests is less than or equal to the\n   * number of allowed concurrent requests.\n   * The time periods returned are in ms.\n   * @param {Array<LH.Artifacts.NetworkRequest>} requests\n   * @param {number} allowedConcurrentRequests\n   * @param {number=} endTime In ms\n   * @return {Array<{start: number, end: number}>}\n   */\n  static findNetworkQuietPeriods(requests, allowedConcurrentRequests, endTime = Infinity) {\n    let timeBoundaries = [];\n    requests.forEach((request) => {\n      if (url_utils_default.isNonNetworkProtocol(request.protocol)) return;\n      if (request.protocol === \"ws\" || request.protocol === \"wss\") return;\n      timeBoundaries.push({ time: request.networkRequestTime, isStart: true });\n      if (request.finished) {\n        timeBoundaries.push({ time: request.networkEndTime, isStart: false });\n      }\n    });\n    timeBoundaries = timeBoundaries.filter((boundary) => boundary.time <= endTime).sort((a, b) => a.time - b.time);\n    let numInflightRequests = 0;\n    let quietPeriodStart = 0;\n    const quietPeriods = [];\n    timeBoundaries.forEach((boundary) => {\n      if (boundary.isStart) {\n        if (numInflightRequests === allowedConcurrentRequests) {\n          quietPeriods.push({ start: quietPeriodStart, end: boundary.time });\n        }\n        numInflightRequests++;\n      } else {\n        numInflightRequests--;\n        if (numInflightRequests === allowedConcurrentRequests) {\n          quietPeriodStart = boundary.time;\n        }\n      }\n    });\n    if (numInflightRequests <= allowedConcurrentRequests) {\n      quietPeriods.push({ start: quietPeriodStart, end: endTime });\n    }\n    return quietPeriods.filter((period) => period.start !== period.end);\n  }\n};\n\n// core/gather/driver.js\n/**\n * @license\n * Copyright 2020 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\nvar throwNotConnectedFn = /* @__PURE__ */ __name(() => {\n  throw new Error(\"Session not connected\");\n}, \"throwNotConnectedFn\");\nvar throwingSession = {\n  setTargetInfo: throwNotConnectedFn,\n  hasNextProtocolTimeout: throwNotConnectedFn,\n  getNextProtocolTimeout: throwNotConnectedFn,\n  setNextProtocolTimeout: throwNotConnectedFn,\n  on: throwNotConnectedFn,\n  once: throwNotConnectedFn,\n  off: throwNotConnectedFn,\n  sendCommand: throwNotConnectedFn,\n  sendCommandAndIgnore: throwNotConnectedFn,\n  dispose: throwNotConnectedFn,\n  onCrashPromise: throwNotConnectedFn\n};\nvar Driver = class {\n  static {\n    __name(this, \"Driver\");\n  }\n  /**\n   * @param {LH.Puppeteer.Page} page\n   */\n  constructor(page) {\n    this._page = page;\n    this._targetManager = void 0;\n    this._networkMonitor = void 0;\n    this._executionContext = void 0;\n    this._fetcher = void 0;\n    this.defaultSession = throwingSession;\n  }\n  /** @return {LH.Gatherer.Driver['executionContext']} */\n  get executionContext() {\n    if (!this._executionContext) return throwNotConnectedFn();\n    return this._executionContext;\n  }\n  get fetcher() {\n    if (!this._fetcher) return throwNotConnectedFn();\n    return this._fetcher;\n  }\n  get targetManager() {\n    if (!this._targetManager) return throwNotConnectedFn();\n    return this._targetManager;\n  }\n  get networkMonitor() {\n    if (!this._networkMonitor) return throwNotConnectedFn();\n    return this._networkMonitor;\n  }\n  /** @return {Promise<string>} */\n  async url() {\n    return this._page.url();\n  }\n  /** @return {Promise<void>} */\n  async connect() {\n    if (this.defaultSession !== throwingSession) return;\n    const status = { msg: \"Connecting to browser\", id: \"lh:driver:connect\" };\n    lighthouse_logger_default.time(status);\n    const cdpSession = await this._page.target().createCDPSession();\n    this._targetManager = new TargetManager(cdpSession);\n    await this._targetManager.enable();\n    this._networkMonitor = new NetworkMonitor(this._targetManager);\n    await this._networkMonitor.enable();\n    this.defaultSession = this._targetManager.rootSession();\n    this._executionContext = new ExecutionContext(this.defaultSession);\n    this._fetcher = new Fetcher(this.defaultSession);\n    lighthouse_logger_default.timeEnd(status);\n  }\n  /** @return {Promise<void>} */\n  async disconnect() {\n    if (this.defaultSession === throwingSession) return;\n    await this._targetManager?.disable();\n    await this._networkMonitor?.disable();\n    await this.defaultSession.dispose();\n  }\n};\n\n// core/gather/runner-helpers.js\ninit_process_global();\ninit_lighthouse_logger();\n/**\n * @license\n * Copyright 2021 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\nfunction createDependencyError(dependency, error) {\n  const err = new Error(`Dependency \"${dependency.id}\" failed with exception: ${error.message}`);\n  err.expected = true;\n  return err;\n}\n__name(createDependencyError, \"createDependencyError\");\nfunction getEmptyArtifactState() {\n  return {\n    startInstrumentation: {},\n    startSensitiveInstrumentation: {},\n    stopSensitiveInstrumentation: {},\n    stopInstrumentation: {},\n    getArtifact: {}\n  };\n}\n__name(getEmptyArtifactState, \"getEmptyArtifactState\");\nvar phaseToPriorPhase = {\n  startInstrumentation: void 0,\n  startSensitiveInstrumentation: \"startInstrumentation\",\n  stopSensitiveInstrumentation: \"startSensitiveInstrumentation\",\n  stopInstrumentation: \"stopSensitiveInstrumentation\",\n  getArtifact: \"stopInstrumentation\"\n};\nasync function collectPhaseArtifacts(options) {\n  const {\n    driver,\n    page,\n    artifactDefinitions,\n    artifactState,\n    baseArtifacts,\n    phase,\n    gatherMode,\n    computedCache,\n    settings\n  } = options;\n  const priorPhase = phaseToPriorPhase[phase];\n  const priorPhaseArtifacts = priorPhase && artifactState[priorPhase] || {};\n  const isFinalPhase = phase === \"getArtifact\";\n  for (const artifactDefn of artifactDefinitions) {\n    lighthouse_logger_default.verbose(`artifacts:${phase}`, artifactDefn.id);\n    const gatherer = artifactDefn.gatherer.instance;\n    const priorArtifactPromise = priorPhaseArtifacts[artifactDefn.id] || Promise.resolve();\n    const artifactPromise = priorArtifactPromise.then(async () => {\n      const dependencies = isFinalPhase ? await collectArtifactDependencies(artifactDefn, artifactState.getArtifact) : (\n        /** @type {Dependencies} */\n        {}\n      );\n      const status = {\n        msg: `Getting artifact: ${artifactDefn.id}`,\n        id: `lh:gather:getArtifact:${artifactDefn.id}`\n      };\n      if (isFinalPhase) {\n        lighthouse_logger_default.time(status);\n      }\n      const artifact = await gatherer[phase]({\n        gatherMode,\n        driver,\n        page,\n        baseArtifacts,\n        dependencies,\n        computedCache,\n        settings\n      });\n      if (isFinalPhase) {\n        lighthouse_logger_default.timeEnd(status);\n      }\n      return artifact;\n    });\n    await artifactPromise.catch((err) => {\n      Sentry.captureException(err, {\n        tags: { gatherer: artifactDefn.id, phase },\n        level: \"error\"\n      });\n      lighthouse_logger_default.error(artifactDefn.id, err.message);\n    });\n    artifactState[phase][artifactDefn.id] = artifactPromise;\n  }\n}\n__name(collectPhaseArtifacts, \"collectPhaseArtifacts\");\nasync function collectArtifactDependencies(artifact, artifactsById) {\n  if (!artifact.dependencies) return (\n    /** @type {Dependencies} */\n    {}\n  );\n  const dependencyPromises = Object.entries(artifact.dependencies).map(\n    async ([dependencyName, dependency]) => {\n      const dependencyArtifact = artifactsById[dependency.id];\n      if (dependencyArtifact === void 0) throw new Error(`\"${dependency.id}\" did not run`);\n      if (dependencyArtifact instanceof Error) {\n        throw createDependencyError(dependency, dependencyArtifact);\n      }\n      const dependencyPromise = Promise.resolve().then(() => dependencyArtifact).catch((err) => Promise.reject(createDependencyError(dependency, err)));\n      return [dependencyName, await dependencyPromise];\n    }\n  );\n  return Object.fromEntries(await Promise.all(dependencyPromises));\n}\n__name(collectArtifactDependencies, \"collectArtifactDependencies\");\nasync function awaitArtifacts(artifactState) {\n  const artifacts = {};\n  for (const [id, promise] of Object.entries(artifactState.getArtifact)) {\n    const artifact = await promise.catch((err) => err);\n    if (artifact !== void 0) artifacts[id] = artifact;\n  }\n  return artifacts;\n}\n__name(awaitArtifacts, \"awaitArtifacts\");\n\n// core/gather/base-artifacts.js\ninit_process_global();\ninit_lighthouse_logger();\ninit_lodash();\n\n// core/gather/driver/environment.js\ninit_process_global();\ninit_lighthouse_logger();\ninit_page_functions();\ninit_i18n();\n/**\n * @license\n * Copyright 2021 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\nvar UIStrings119 = {\n  /**\n   * @description Warning that the host device where Lighthouse is running appears to have a slower\n   * CPU than the expected Lighthouse baseline.\n   */\n  warningSlowHostCpu: \"The tested device appears to have a slower CPU than  Lighthouse expects. This can negatively affect your performance score. Learn more about [calibrating an appropriate CPU slowdown multiplier](https://github.com/GoogleChrome/lighthouse/blob/main/docs/throttling.md#cpu-throttling).\"\n};\nvar SLOW_CPU_BENCHMARK_INDEX_THRESHOLD = 1e3;\nvar str_99 = createIcuMessageFn({ url: \"core/gather/driver/environment.js\" }.url, UIStrings119);\nasync function getBrowserVersion(session) {\n  const status = { msg: \"Getting browser version\", id: \"lh:gather:getVersion\" };\n  lighthouse_logger_default.time(status, \"verbose\");\n  const version = await session.sendCommand(\"Browser.getVersion\");\n  const match = version.product.match(/\\/(\\d+)/);\n  const milestone = match ? parseInt(match[1]) : 0;\n  lighthouse_logger_default.timeEnd(status);\n  return Object.assign(version, { milestone });\n}\n__name(getBrowserVersion, \"getBrowserVersion\");\nasync function getBenchmarkIndex(executionContext) {\n  const status = { msg: \"Benchmarking machine\", id: \"lh:gather:getBenchmarkIndex\" };\n  lighthouse_logger_default.time(status);\n  const indexVal = await executionContext.evaluate(pageFunctions.computeBenchmarkIndex, {\n    args: []\n  });\n  lighthouse_logger_default.timeEnd(status);\n  return indexVal;\n}\n__name(getBenchmarkIndex, \"getBenchmarkIndex\");\nasync function getDevicePixelRatio(executionContext) {\n  const status = { msg: \"Host device pixel ratio\", id: \"lh:gather:getDevicePixelRatio\" };\n  lighthouse_logger_default.time(status);\n  const indexVal = await executionContext.evaluate(() => devicePixelRatio, {\n    args: []\n  });\n  lighthouse_logger_default.timeEnd(status);\n  return indexVal;\n}\n__name(getDevicePixelRatio, \"getDevicePixelRatio\");\nfunction getSlowHostCpuWarning(context) {\n  const { settings, baseArtifacts } = context;\n  const { throttling: throttling3, throttlingMethod } = settings;\n  const defaultThrottling2 = defaultSettings.throttling;\n  if (settings.channel !== \"cli\") return;\n  const isThrottledMethod = throttlingMethod === \"simulate\" || throttlingMethod === \"devtools\";\n  const isDefaultMultiplier = throttling3.cpuSlowdownMultiplier === defaultThrottling2.cpuSlowdownMultiplier;\n  if (!isThrottledMethod || !isDefaultMultiplier) return;\n  if (baseArtifacts.BenchmarkIndex > SLOW_CPU_BENCHMARK_INDEX_THRESHOLD) return;\n  return str_99(UIStrings119.warningSlowHostCpu);\n}\n__name(getSlowHostCpuWarning, \"getSlowHostCpuWarning\");\nfunction getEnvironmentWarnings(context) {\n  return [\n    getSlowHostCpuWarning(context)\n  ].filter((s) => !!s);\n}\n__name(getEnvironmentWarnings, \"getEnvironmentWarnings\");\n\n// core/gather/base-artifacts.js\n/**\n * @license\n * Copyright 2021 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\nasync function getBaseArtifacts(resolvedConfig, driver, context) {\n  const BenchmarkIndex = await getBenchmarkIndex(driver.executionContext);\n  const { userAgent, product } = await getBrowserVersion(driver.defaultSession);\n  const HostDPR = await getDevicePixelRatio(driver.executionContext);\n  return {\n    // Meta artifacts.\n    fetchTime: (/* @__PURE__ */ new Date()).toJSON(),\n    Timing: [],\n    LighthouseRunWarnings: [],\n    settings: resolvedConfig.settings,\n    // Environment artifacts that can always be computed.\n    BenchmarkIndex,\n    HostDPR,\n    HostUserAgent: userAgent,\n    HostFormFactor: userAgent.includes(\"Android\") || userAgent.includes(\"Mobile\") ? \"mobile\" : \"desktop\",\n    HostProduct: product,\n    // Contextual artifacts whose collection changes based on gather mode.\n    URL: {\n      finalDisplayedUrl: \"\"\n    },\n    PageLoadError: null,\n    GatherContext: context\n  };\n}\n__name(getBaseArtifacts, \"getBaseArtifacts\");\nfunction deduplicateWarnings(warnings) {\n  const unique = [];\n  for (const warning of warnings) {\n    if (unique.some((existing) => isEqual_default(warning, existing))) continue;\n    unique.push(warning);\n  }\n  return unique;\n}\n__name(deduplicateWarnings, \"deduplicateWarnings\");\nfunction finalizeArtifacts(baseArtifacts, gathererArtifacts) {\n  baseArtifacts.LighthouseRunWarnings.push(\n    ...getEnvironmentWarnings({ settings: baseArtifacts.settings, baseArtifacts })\n  );\n  const artifacts = (\n    /** @type {LH.Artifacts} */\n    { ...baseArtifacts, ...gathererArtifacts }\n  );\n  artifacts.Timing = lighthouse_logger_default.getTimeEntries();\n  artifacts.LighthouseRunWarnings = deduplicateWarnings(baseArtifacts.LighthouseRunWarnings);\n  if (artifacts.PageLoadError && !artifacts.URL.finalDisplayedUrl) {\n    artifacts.URL.finalDisplayedUrl = artifacts.URL.requestedUrl || \"\";\n  }\n  if (!artifacts.URL.finalDisplayedUrl) throw new Error(\"Runner did not set finalDisplayedUrl\");\n  return artifacts;\n}\n__name(finalizeArtifacts, \"finalizeArtifacts\");\n\n// core/gather/snapshot-runner.js\n/**\n * @license\n * Copyright 2020 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\nasync function snapshotGather(page, options = {}) {\n  const { flags = {}, config: config3 } = options;\n  lighthouse_logger_default.setLevel(flags.logLevel || \"error\");\n  const { resolvedConfig } = await initializeConfig(\"snapshot\", config3, flags);\n  const driver = new Driver(page);\n  await driver.connect();\n  const computedCache = /* @__PURE__ */ new Map();\n  const url = await driver.url();\n  const runnerOptions = { resolvedConfig, computedCache };\n  const gatherFn = /* @__PURE__ */ __name(async () => {\n    const baseArtifacts = await getBaseArtifacts(resolvedConfig, driver, { gatherMode: \"snapshot\" });\n    baseArtifacts.URL = {\n      finalDisplayedUrl: url\n    };\n    const artifactDefinitions = resolvedConfig.artifacts || [];\n    const artifactState = getEmptyArtifactState();\n    await collectPhaseArtifacts({\n      phase: \"getArtifact\",\n      gatherMode: \"snapshot\",\n      driver,\n      page,\n      baseArtifacts,\n      artifactDefinitions,\n      artifactState,\n      computedCache,\n      settings: resolvedConfig.settings\n    });\n    await driver.disconnect();\n    const artifacts2 = await awaitArtifacts(artifactState);\n    return finalizeArtifacts(baseArtifacts, artifacts2);\n  }, \"gatherFn\");\n  const artifacts = await Runner.gather(gatherFn, runnerOptions);\n  return { artifacts, runnerOptions };\n}\n__name(snapshotGather, \"snapshotGather\");\n\n// core/gather/timespan-runner.js\ninit_process_global();\ninit_lighthouse_logger();\n\n// core/gather/driver/prepare.js\ninit_process_global();\ninit_lighthouse_logger();\n\n// core/gather/driver/storage.js\ninit_process_global();\ninit_lighthouse_logger();\ninit_i18n();\n/**\n * @license\n * Copyright 2021 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\nvar UIStrings120 = {\n  /**\n   * @description A warning that previously-saved data may have affected the measured performance and instructions on how to avoid the problem. \"locations\" will be a list of possible types of data storage locations, e.g. \"IndexedDB\",  \"Local Storage\", or \"Web SQL\".\n   * @example {IndexedDB, Local Storage} locations\n   */\n  warningData: `{locationCount, plural,\n    =1 {There may be stored data affecting loading performance in this location: {locations}. Audit this page in an incognito window to prevent those resources from affecting your scores.}\n    other {There may be stored data affecting loading performance in these locations: {locations}. Audit this page in an incognito window to prevent those resources from affecting your scores.}\n  }`,\n  /** A warning that the data in the browser cache may have affected the measured performance because the operation to clear the browser cache timed out. */\n  warningCacheTimeout: \"Clearing the browser cache timed out. Try auditing this page again and file a bug if the issue persists.\",\n  /** A warning that the data on the page's origin may have affected the measured performance because the operation to clear the origin data timed out. */\n  warningOriginDataTimeout: \"Clearing the origin data timed out. Try auditing this page again and file a bug if the issue persists.\"\n};\nvar str_100 = createIcuMessageFn({ url: \"core/gather/driver/storage.js\" }.url, UIStrings120);\nasync function clearDataForOrigin(session, url, clearStorageTypes) {\n  const status = { msg: \"Cleaning origin data\", id: \"lh:storage:clearDataForOrigin\" };\n  lighthouse_logger_default.time(status);\n  const warnings = [];\n  const origin = new URL(url).origin;\n  const typesToClear = clearStorageTypes.join(\",\");\n  session.setNextProtocolTimeout(5e3);\n  try {\n    await session.sendCommand(\"Storage.clearDataForOrigin\", {\n      origin,\n      storageTypes: typesToClear\n    });\n  } catch (err) {\n    if (\n      /** @type {LH.LighthouseError} */\n      err.code === \"PROTOCOL_TIMEOUT\"\n    ) {\n      lighthouse_logger_default.warn(\"Driver\", \"clearDataForOrigin timed out\");\n      warnings.push(str_100(UIStrings120.warningOriginDataTimeout));\n    } else {\n      throw err;\n    }\n  } finally {\n    lighthouse_logger_default.timeEnd(status);\n  }\n  return warnings;\n}\n__name(clearDataForOrigin, \"clearDataForOrigin\");\nasync function getImportantStorageWarning(session, url) {\n  const usageData = await session.sendCommand(\"Storage.getUsageAndQuota\", {\n    origin: url\n  });\n  const storageTypeNames = {\n    local_storage: \"Local Storage\",\n    indexeddb: \"IndexedDB\",\n    websql: \"Web SQL\"\n  };\n  const locations = usageData.usageBreakdown.filter((usage) => usage.usage).map((usage) => storageTypeNames[usage.storageType] || \"\").filter(Boolean);\n  if (locations.length) {\n    return str_100(UIStrings120.warningData, {\n      locations: locations.join(\", \"),\n      locationCount: locations.length\n    });\n  }\n}\n__name(getImportantStorageWarning, \"getImportantStorageWarning\");\nasync function clearBrowserCaches(session) {\n  const status = { msg: \"Cleaning browser cache\", id: \"lh:storage:clearBrowserCaches\" };\n  lighthouse_logger_default.time(status);\n  const warnings = [];\n  try {\n    await session.sendCommand(\"Network.clearBrowserCache\");\n    await session.sendCommand(\"Network.setCacheDisabled\", { cacheDisabled: true });\n    await session.sendCommand(\"Network.setCacheDisabled\", { cacheDisabled: false });\n  } catch (err) {\n    if (\n      /** @type {LH.LighthouseError} */\n      err.code === \"PROTOCOL_TIMEOUT\"\n    ) {\n      lighthouse_logger_default.warn(\"Driver\", \"clearBrowserCaches timed out\");\n      warnings.push(str_100(UIStrings120.warningCacheTimeout));\n    } else {\n      throw err;\n    }\n  } finally {\n    lighthouse_logger_default.timeEnd(status);\n  }\n  return warnings;\n}\n__name(clearBrowserCaches, \"clearBrowserCaches\");\n\n// core/lib/emulation.js\ninit_process_global();\n/**\n * @license\n * Copyright 2016 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\nvar NO_THROTTLING_METRICS = {\n  latency: 0,\n  downloadThroughput: 0,\n  uploadThroughput: 0,\n  offline: false\n};\nvar NO_CPU_THROTTLE_METRICS = {\n  rate: 1\n};\nfunction parseUseragentIntoMetadata(fullVersion, formFactor) {\n  const [version] = fullVersion.split(\".\", 1);\n  const brands = [\n    { brand: \"Chromium\", version },\n    { brand: \"Google Chrome\", version }\n  ];\n  const motoGPowerDetails = {\n    platform: \"Android\",\n    platformVersion: \"11.0\",\n    architecture: \"\",\n    model: \"moto g power (2022)\"\n  };\n  const macDesktopDetails = {\n    platform: \"macOS\",\n    platformVersion: \"10.15.7\",\n    architecture: \"x86\",\n    model: \"\"\n  };\n  const mobile = formFactor === \"mobile\";\n  return {\n    brands,\n    fullVersion,\n    // Since config users can supply a custom useragent, they likely are emulating something\n    // other than Moto G Power and MacOS Desktop.\n    // TODO: Determine how to thoughtfully expose this metadata/client-hints configurability.\n    ...mobile ? motoGPowerDetails : macDesktopDetails,\n    mobile\n  };\n}\n__name(parseUseragentIntoMetadata, \"parseUseragentIntoMetadata\");\nasync function matchHostUAVersion(session, userAgent) {\n  const { milestone } = await getBrowserVersion(session);\n  const tweakedUA = userAgent.replace(/(Chrome\\/)[\\d.]+/, `$1${milestone}.0.0.0`);\n  const fullVersion = `${milestone}.0.0.0`;\n  return { tweakedUA, fullVersion };\n}\n__name(matchHostUAVersion, \"matchHostUAVersion\");\nasync function emulate(session, settings) {\n  if (settings.emulatedUserAgent !== false) {\n    const userAgent = (\n      /** @type {string} */\n      settings.emulatedUserAgent\n    );\n    const { tweakedUA, fullVersion } = await matchHostUAVersion(session, userAgent);\n    await session.sendCommand(\"Network.setUserAgentOverride\", {\n      userAgent: tweakedUA,\n      userAgentMetadata: parseUseragentIntoMetadata(fullVersion, settings.formFactor)\n    });\n  }\n  if (settings.screenEmulation.disabled !== true) {\n    const { width, height, deviceScaleFactor, mobile } = settings.screenEmulation;\n    const params = { width, height, deviceScaleFactor, mobile };\n    await session.sendCommand(\"Emulation.setDeviceMetricsOverride\", params);\n    await session.sendCommand(\"Emulation.setTouchEmulationEnabled\", {\n      enabled: params.mobile\n    });\n  }\n}\n__name(emulate, \"emulate\");\nasync function throttle(session, settings) {\n  if (settings.throttlingMethod !== \"devtools\") return clearNetworkThrottling(session);\n  await Promise.all([\n    enableNetworkThrottling(session, settings.throttling),\n    enableCPUThrottling(session, settings.throttling)\n  ]);\n}\n__name(throttle, \"throttle\");\nasync function clearThrottling(session) {\n  await Promise.all([clearNetworkThrottling(session), clearCPUThrottling(session)]);\n}\n__name(clearThrottling, \"clearThrottling\");\nfunction enableNetworkThrottling(session, throttlingSettings) {\n  const conditions = {\n    offline: false,\n    latency: throttlingSettings.requestLatencyMs || 0,\n    downloadThroughput: throttlingSettings.downloadThroughputKbps || 0,\n    uploadThroughput: throttlingSettings.uploadThroughputKbps || 0\n  };\n  conditions.downloadThroughput = Math.floor(conditions.downloadThroughput * 1024 / 8);\n  conditions.uploadThroughput = Math.floor(conditions.uploadThroughput * 1024 / 8);\n  return session.sendCommand(\"Network.emulateNetworkConditions\", conditions);\n}\n__name(enableNetworkThrottling, \"enableNetworkThrottling\");\nfunction clearNetworkThrottling(session) {\n  return session.sendCommandAndIgnore(\"Network.emulateNetworkConditions\", NO_THROTTLING_METRICS);\n}\n__name(clearNetworkThrottling, \"clearNetworkThrottling\");\nfunction enableCPUThrottling(session, throttlingSettings) {\n  const rate = throttlingSettings.cpuSlowdownMultiplier;\n  return session.sendCommand(\"Emulation.setCPUThrottlingRate\", { rate });\n}\n__name(enableCPUThrottling, \"enableCPUThrottling\");\nfunction clearCPUThrottling(session) {\n  return session.sendCommandAndIgnore(\"Emulation.setCPUThrottlingRate\", NO_CPU_THROTTLE_METRICS);\n}\n__name(clearCPUThrottling, \"clearCPUThrottling\");\n\n// core/gather/driver/prepare.js\ninit_page_functions();\n/**\n * @license\n * Copyright 2021 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\nasync function enableAsyncStacks(session) {\n  const enable = /* @__PURE__ */ __name(async () => {\n    await session.sendCommand(\"Debugger.enable\");\n    await session.sendCommand(\"Debugger.setSkipAllPauses\", { skip: true });\n    await session.sendCommand(\"Debugger.setAsyncCallStackDepth\", { maxDepth: 8 });\n  }, \"enable\");\n  function onDebuggerPaused() {\n    session.sendCommand(\"Debugger.resume\");\n  }\n  __name(onDebuggerPaused, \"onDebuggerPaused\");\n  function onFrameNavigated(event) {\n    if (event.frame.parentId) return;\n    enable().catch((err) => lighthouse_logger_default.error(\"Driver\", err));\n  }\n  __name(onFrameNavigated, \"onFrameNavigated\");\n  session.on(\"Debugger.paused\", onDebuggerPaused);\n  session.on(\"Page.frameNavigated\", onFrameNavigated);\n  await enable();\n  return async () => {\n    await session.sendCommandAndIgnore(\"Debugger.disable\");\n    session.off(\"Debugger.paused\", onDebuggerPaused);\n    session.off(\"Page.frameNavigated\", onFrameNavigated);\n  };\n}\n__name(enableAsyncStacks, \"enableAsyncStacks\");\nasync function shimRequestIdleCallbackOnNewDocument(driver, settings) {\n  await driver.executionContext.evaluateOnNewDocument(pageFunctions.wrapRequestIdleCallback, {\n    args: [settings.throttling.cpuSlowdownMultiplier]\n  });\n}\n__name(shimRequestIdleCallbackOnNewDocument, \"shimRequestIdleCallbackOnNewDocument\");\nasync function dismissJavaScriptDialogs(session) {\n  session.on(\"Page.javascriptDialogOpening\", (data31) => {\n    lighthouse_logger_default.warn(\"Driver\", `${data31.type} dialog opened by the page automatically suppressed.`);\n    session.sendCommand(\"Page.handleJavaScriptDialog\", {\n      accept: true,\n      promptText: \"Lighthouse prompt response\"\n    }).catch((err) => lighthouse_logger_default.warn(\"Driver\", err));\n  });\n  await session.sendCommand(\"Page.enable\");\n}\n__name(dismissJavaScriptDialogs, \"dismissJavaScriptDialogs\");\nasync function resetStorageForUrl(session, url, clearStorageTypes) {\n  const warnings = [];\n  const clearDataWarnings = await clearDataForOrigin(session, url, clearStorageTypes);\n  warnings.push(...clearDataWarnings);\n  const clearCacheWarnings = await clearBrowserCaches(session);\n  warnings.push(...clearCacheWarnings);\n  const importantStorageWarning = await getImportantStorageWarning(session, url);\n  if (importantStorageWarning) warnings.push(importantStorageWarning);\n  return { warnings };\n}\n__name(resetStorageForUrl, \"resetStorageForUrl\");\nasync function prepareThrottlingAndNetwork(session, settings) {\n  const status = { msg: \"Preparing network conditions\", id: `lh:gather:prepareThrottlingAndNetwork` };\n  lighthouse_logger_default.time(status);\n  await throttle(session, settings);\n  const blockedUrls = settings.blockedUrlPatterns || [];\n  await session.sendCommand(\"Network.setBlockedURLs\", { urls: blockedUrls });\n  const headers = settings.extraHeaders;\n  if (headers) await session.sendCommand(\"Network.setExtraHTTPHeaders\", { headers });\n  lighthouse_logger_default.timeEnd(status);\n}\n__name(prepareThrottlingAndNetwork, \"prepareThrottlingAndNetwork\");\nasync function prepareDeviceEmulation(driver, settings) {\n  await driver.defaultSession.sendCommand(\"Network.enable\");\n  await emulate(driver.defaultSession, settings);\n}\n__name(prepareDeviceEmulation, \"prepareDeviceEmulation\");\nasync function warmUpIntlSegmenter(driver) {\n  await driver.executionContext.evaluate(pageFunctions.truncate, {\n    args: [\"aaa\", 2]\n  });\n}\n__name(warmUpIntlSegmenter, \"warmUpIntlSegmenter\");\nasync function prepareTargetForNavigationMode(driver, settings, requestor) {\n  const status = { msg: \"Preparing target for navigation mode\", id: \"lh:prepare:navigationMode\" };\n  lighthouse_logger_default.time(status);\n  const warnings = [];\n  await prepareDeviceEmulation(driver, settings);\n  await dismissJavaScriptDialogs(driver.defaultSession);\n  await driver.executionContext.cacheNativesOnNewDocument();\n  if (settings.throttlingMethod === \"simulate\") {\n    await shimRequestIdleCallbackOnNewDocument(driver, settings);\n  }\n  await warmUpIntlSegmenter(driver);\n  const shouldResetStorage = !settings.disableStorageReset && // Without prior knowledge of the destination, we cannot know which URL to clear storage for.\n  typeof requestor === \"string\";\n  if (shouldResetStorage) {\n    const { warnings: storageWarnings } = await resetStorageForUrl(\n      driver.defaultSession,\n      requestor,\n      settings.clearStorageTypes\n    );\n    warnings.push(...storageWarnings);\n  }\n  await prepareThrottlingAndNetwork(driver.defaultSession, settings);\n  lighthouse_logger_default.timeEnd(status);\n  return { warnings };\n}\n__name(prepareTargetForNavigationMode, \"prepareTargetForNavigationMode\");\n\n// core/gather/timespan-runner.js\ninit_i18n();\n/**\n * @license\n * Copyright 2021 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\nvar UIStrings121 = {\n  /** A warning that indicates page navigations should be audited using navigation mode, as opposed to timespan mode. \"navigation mode\" refers to a Lighthouse mode that analyzes a page navigation. \"timespan mode\" refers to a Lighthouse mode that analyzes user interactions over an arbitrary period of time. */\n  warningNavigationDetected: \"A page navigation was detected during the run. Using timespan mode to audit page navigations is not recommended. Use navigation mode to audit page navigations for better third-party attribution and main thread detection.\"\n};\nvar str_101 = createIcuMessageFn({ url: \"core/gather/timespan-runner.js\" }.url, UIStrings121);\n\n// core/gather/navigation-runner.js\ninit_process_global();\n\n// replace-modules:/Users/alexrudenko/src/lighthouse/node_modules/puppeteer-core/lib/cjs/puppeteer/puppeteer-core.js\ninit_process_global();\nvar puppeteer_core_default = {};\n\n// core/gather/navigation-runner.js\ninit_lighthouse_logger();\n\n// core/gather/driver/navigation.js\ninit_process_global();\ninit_lighthouse_logger();\n\n// core/gather/driver/wait-for-condition.js\ninit_process_global();\ninit_lighthouse_logger();\ninit_lh_error();\n/**\n * @license\n * Copyright 2020 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\nfunction waitForNothing() {\n  return { promise: Promise.resolve(), cancel() {\n  } };\n}\n__name(waitForNothing, \"waitForNothing\");\nfunction waitForFrameNavigated(session) {\n  let cancel = /* @__PURE__ */ __name(() => {\n    throw new Error(\"waitForFrameNavigated.cancel() called before it was defined\");\n  }, \"cancel\");\n  const promise = new Promise((resolve, reject) => {\n    session.once(\"Page.frameNavigated\", resolve);\n    cancel = /* @__PURE__ */ __name(() => {\n      session.off(\"Page.frameNavigated\", resolve);\n      reject(new Error(\"Wait for navigated cancelled\"));\n    }, \"cancel\");\n  });\n  return { promise, cancel };\n}\n__name(waitForFrameNavigated, \"waitForFrameNavigated\");\nfunction waitForFcp(session, pauseAfterFcpMs, maxWaitForFcpMs) {\n  let cancel = /* @__PURE__ */ __name(() => {\n    throw new Error(\"waitForFcp.cancel() called before it was defined\");\n  }, \"cancel\");\n  const promise = new Promise((resolve, reject) => {\n    const maxWaitTimeout = setTimeout(() => {\n      reject(new LighthouseError(LighthouseError.errors.NO_FCP));\n    }, maxWaitForFcpMs);\n    let loadTimeout;\n    const lifecycleListener = /* @__PURE__ */ __name((e) => {\n      if (e.name === \"firstContentfulPaint\") {\n        loadTimeout = setTimeout(() => {\n          resolve();\n          cancel();\n        }, pauseAfterFcpMs);\n      }\n    }, \"lifecycleListener\");\n    session.on(\"Page.lifecycleEvent\", lifecycleListener);\n    let canceled = false;\n    cancel = /* @__PURE__ */ __name(() => {\n      if (canceled) return;\n      canceled = true;\n      session.off(\"Page.lifecycleEvent\", lifecycleListener);\n      maxWaitTimeout && clearTimeout(maxWaitTimeout);\n      loadTimeout && clearTimeout(loadTimeout);\n      reject(new Error(\"Wait for FCP canceled\"));\n    }, \"cancel\");\n  });\n  return {\n    promise,\n    cancel\n  };\n}\n__name(waitForFcp, \"waitForFcp\");\nfunction waitForNetworkIdle(session, networkMonitor, networkQuietOptions) {\n  let hasDCLFired = false;\n  let idleTimeout;\n  let cancel = /* @__PURE__ */ __name(() => {\n    throw new Error(\"waitForNetworkIdle.cancel() called before it was defined\");\n  }, \"cancel\");\n  const { networkQuietThresholdMs, busyEvent, idleEvent, isIdle } = networkQuietOptions;\n  const promise = new Promise((resolve, reject) => {\n    const onIdle = /* @__PURE__ */ __name(() => {\n      networkMonitor.once(busyEvent, onBusy);\n      idleTimeout = setTimeout(() => {\n        cancel();\n        resolve();\n      }, networkQuietThresholdMs);\n    }, \"onIdle\");\n    const onBusy = /* @__PURE__ */ __name(() => {\n      networkMonitor.once(idleEvent, onIdle);\n      idleTimeout && clearTimeout(idleTimeout);\n    }, \"onBusy\");\n    const domContentLoadedListener = /* @__PURE__ */ __name(() => {\n      hasDCLFired = true;\n      if (isIdle(networkMonitor)) {\n        onIdle();\n      } else {\n        onBusy();\n      }\n    }, \"domContentLoadedListener\");\n    const logStatus = /* @__PURE__ */ __name(() => {\n      if (!hasDCLFired) {\n        lighthouse_logger_default.verbose(\"waitFor\", \"Waiting on DomContentLoaded\");\n        return;\n      }\n      const inflightRecords = networkMonitor.getInflightRequests();\n      if (lighthouse_logger_default.isVerbose() && inflightRecords.length < 20 && inflightRecords.length > 0) {\n        lighthouse_logger_default.verbose(\"waitFor\", `=== Waiting on ${inflightRecords.length} requests to finish`);\n        for (const record of inflightRecords) {\n          lighthouse_logger_default.verbose(\"waitFor\", `Waiting on ${record.url.slice(0, 120)} to finish`);\n        }\n      }\n    }, \"logStatus\");\n    networkMonitor.on(\"requeststarted\", logStatus);\n    networkMonitor.on(\"requestfinished\", logStatus);\n    networkMonitor.on(busyEvent, logStatus);\n    if (!networkQuietOptions.pretendDCLAlreadyFired) {\n      session.once(\"Page.domContentEventFired\", domContentLoadedListener);\n    } else {\n      domContentLoadedListener();\n    }\n    let canceled = false;\n    cancel = /* @__PURE__ */ __name(() => {\n      if (canceled) return;\n      canceled = true;\n      if (idleTimeout) clearTimeout(idleTimeout);\n      if (!networkQuietOptions.pretendDCLAlreadyFired) {\n        session.off(\"Page.domContentEventFired\", domContentLoadedListener);\n      }\n      networkMonitor.removeListener(busyEvent, onBusy);\n      networkMonitor.removeListener(idleEvent, onIdle);\n      networkMonitor.removeListener(\"requeststarted\", logStatus);\n      networkMonitor.removeListener(\"requestfinished\", logStatus);\n      networkMonitor.removeListener(busyEvent, logStatus);\n    }, \"cancel\");\n  });\n  return {\n    promise,\n    cancel\n  };\n}\n__name(waitForNetworkIdle, \"waitForNetworkIdle\");\nfunction waitForCPUIdle(session, waitForCPUQuiet) {\n  if (!waitForCPUQuiet) {\n    return {\n      promise: Promise.resolve(),\n      cancel: /* @__PURE__ */ __name(() => void 0, \"cancel\")\n    };\n  }\n  let lastTimeout;\n  let canceled = false;\n  async function checkForQuiet(executionContext2, resolve) {\n    if (canceled) return;\n    const timeSinceLongTask = await executionContext2.evaluate(\n      checkTimeSinceLastLongTaskInPage,\n      { args: [], useIsolation: true }\n    );\n    if (canceled) return;\n    if (typeof timeSinceLongTask === \"number\") {\n      if (timeSinceLongTask >= waitForCPUQuiet) {\n        lighthouse_logger_default.verbose(\"waitFor\", `CPU has been idle for ${timeSinceLongTask} ms`);\n        resolve();\n      } else {\n        lighthouse_logger_default.verbose(\"waitFor\", `CPU has been idle for ${timeSinceLongTask} ms`);\n        const timeToWait = waitForCPUQuiet - timeSinceLongTask;\n        lastTimeout = setTimeout(() => checkForQuiet(executionContext2, resolve), timeToWait);\n      }\n    }\n  }\n  __name(checkForQuiet, \"checkForQuiet\");\n  let cancel = /* @__PURE__ */ __name(() => {\n    throw new Error(\"waitForCPUIdle.cancel() called before it was defined\");\n  }, \"cancel\");\n  const executionContext = new ExecutionContext(session);\n  const promise = new Promise((resolve, reject) => {\n    executionContext.evaluate(registerPerformanceObserverInPage, { args: [], useIsolation: true }).then(() => checkForQuiet(executionContext, resolve)).catch(reject);\n    cancel = /* @__PURE__ */ __name(() => {\n      if (canceled) return;\n      canceled = true;\n      if (lastTimeout) clearTimeout(lastTimeout);\n      reject(new Error(\"Wait for CPU idle canceled\"));\n    }, \"cancel\");\n  });\n  return {\n    promise,\n    cancel\n  };\n}\n__name(waitForCPUIdle, \"waitForCPUIdle\");\nfunction registerPerformanceObserverInPage() {\n  if (window.____lastLongTask !== void 0) return;\n  window.____lastLongTask = performance.now();\n  const observer = new window.PerformanceObserver((entryList) => {\n    const entries = entryList.getEntries();\n    for (const entry of entries) {\n      if (entry.entryType === \"longtask\") {\n        const taskEnd = entry.startTime + entry.duration;\n        window.____lastLongTask = Math.max(window.____lastLongTask || 0, taskEnd);\n      }\n    }\n  });\n  observer.observe({ type: \"longtask\", buffered: true });\n}\n__name(registerPerformanceObserverInPage, \"registerPerformanceObserverInPage\");\nfunction checkTimeSinceLastLongTaskInPage() {\n  return new Promise((resolve) => {\n    const firstAttemptTs = performance.now();\n    const firstAttemptLastLongTaskTs = window.____lastLongTask || 0;\n    setTimeout(() => {\n      const secondAttemptLastLongTaskTs = window.____lastLongTask || 0;\n      const timeSinceLongTask = firstAttemptLastLongTaskTs === secondAttemptLastLongTaskTs ? (\n        // The time of the last long task hasn't changed, the information from our first attempt is accurate.\n        firstAttemptTs - firstAttemptLastLongTaskTs\n      ) : (\n        // The time of the last long task *did* change, we can't really trust the information we have.\n        0\n      );\n      resolve(timeSinceLongTask);\n    }, 150);\n  });\n}\n__name(checkTimeSinceLastLongTaskInPage, \"checkTimeSinceLastLongTaskInPage\");\nfunction waitForLoadEvent(session, pauseAfterLoadMs) {\n  let cancel = /* @__PURE__ */ __name(() => {\n    throw new Error(\"waitForLoadEvent.cancel() called before it was defined\");\n  }, \"cancel\");\n  const promise = new Promise((resolve, reject) => {\n    let loadTimeout;\n    const loadListener = /* @__PURE__ */ __name(function() {\n      loadTimeout = setTimeout(resolve, pauseAfterLoadMs);\n    }, \"loadListener\");\n    session.once(\"Page.loadEventFired\", loadListener);\n    let canceled = false;\n    cancel = /* @__PURE__ */ __name(() => {\n      if (canceled) return;\n      canceled = true;\n      session.off(\"Page.loadEventFired\", loadListener);\n      loadTimeout && clearTimeout(loadTimeout);\n    }, \"cancel\");\n  });\n  return {\n    promise,\n    cancel\n  };\n}\n__name(waitForLoadEvent, \"waitForLoadEvent\");\nasync function isPageHung(session) {\n  try {\n    session.setNextProtocolTimeout(1e3);\n    await session.sendCommand(\"Runtime.evaluate\", {\n      expression: '\"ping\"',\n      returnByValue: true,\n      timeout: 1e3\n    });\n    return false;\n  } catch (err) {\n    return true;\n  }\n}\n__name(isPageHung, \"isPageHung\");\nvar DEFAULT_WAIT_FUNCTIONS = { waitForFcp, waitForLoadEvent, waitForCPUIdle, waitForNetworkIdle };\nasync function waitForFullyLoaded(session, networkMonitor, options) {\n  const {\n    pauseAfterFcpMs,\n    pauseAfterLoadMs,\n    networkQuietThresholdMs,\n    cpuQuietThresholdMs,\n    maxWaitForLoadedMs,\n    maxWaitForFcpMs\n  } = options;\n  const { waitForFcp: waitForFcp2, waitForLoadEvent: waitForLoadEvent2, waitForNetworkIdle: waitForNetworkIdle2, waitForCPUIdle: waitForCPUIdle2 } = options._waitForTestOverrides || DEFAULT_WAIT_FUNCTIONS;\n  let maxTimeoutHandle;\n  const resolveOnFcp = maxWaitForFcpMs ? waitForFcp2(session, pauseAfterFcpMs, maxWaitForFcpMs) : waitForNothing();\n  const resolveOnLoadEvent = waitForLoadEvent2(session, pauseAfterLoadMs);\n  const resolveOnNetworkIdle = waitForNetworkIdle2(session, networkMonitor, {\n    networkQuietThresholdMs,\n    busyEvent: \"network-2-busy\",\n    idleEvent: \"network-2-idle\",\n    isIdle: /* @__PURE__ */ __name((recorder) => recorder.is2Idle(), \"isIdle\")\n  });\n  const resolveOnCriticalNetworkIdle = waitForNetworkIdle2(session, networkMonitor, {\n    networkQuietThresholdMs,\n    busyEvent: \"network-critical-busy\",\n    idleEvent: \"network-critical-idle\",\n    isIdle: /* @__PURE__ */ __name((recorder) => recorder.isCriticalIdle(), \"isIdle\")\n  });\n  let resolveOnCPUIdle = waitForNothing();\n  if (lighthouse_logger_default.isVerbose()) {\n    resolveOnFcp.promise.then(() => {\n      lighthouse_logger_default.verbose(\"waitFor\", \"resolveOnFcp fired\");\n    });\n    resolveOnLoadEvent.promise.then(() => {\n      lighthouse_logger_default.verbose(\"waitFor\", \"resolveOnLoadEvent fired\");\n    });\n    resolveOnNetworkIdle.promise.then(() => {\n      lighthouse_logger_default.verbose(\"waitFor\", \"resolveOnNetworkIdle fired\");\n    });\n    resolveOnCriticalNetworkIdle.promise.then(() => {\n      lighthouse_logger_default.verbose(\"waitFor\", \"resolveOnCriticalNetworkIdle fired\");\n    });\n  }\n  const loadPromise = Promise.all([\n    resolveOnFcp.promise,\n    resolveOnLoadEvent.promise,\n    resolveOnNetworkIdle.promise,\n    resolveOnCriticalNetworkIdle.promise\n  ]).then(() => {\n    resolveOnCPUIdle = waitForCPUIdle2(session, cpuQuietThresholdMs);\n    return resolveOnCPUIdle.promise;\n  }).then(() => {\n    const cleanupFn2 = /* @__PURE__ */ __name(async function() {\n      lighthouse_logger_default.verbose(\"waitFor\", \"loadEventFired and network considered idle\");\n      return { timedOut: false };\n    }, \"cleanupFn\");\n    return cleanupFn2;\n  }).catch((err) => {\n    return function() {\n      throw err;\n    };\n  });\n  const maxTimeoutPromise = new Promise((resolve, reject) => {\n    maxTimeoutHandle = setTimeout(resolve, maxWaitForLoadedMs);\n  }).then((_) => {\n    return async () => {\n      lighthouse_logger_default.warn(\"waitFor\", \"Timed out waiting for page load. Checking if page is hung...\");\n      if (await isPageHung(session)) {\n        lighthouse_logger_default.warn(\"waitFor\", \"Page appears to be hung, killing JavaScript...\");\n        void session.sendCommandAndIgnore(\"Emulation.setScriptExecutionDisabled\", { value: true });\n        void session.sendCommandAndIgnore(\"Runtime.terminateExecution\");\n        throw new LighthouseError(LighthouseError.errors.PAGE_HUNG);\n      }\n      const inflightRequestUrls = networkMonitor.getInflightRequests().map((request) => request.url);\n      if (inflightRequestUrls.length > 0) {\n        lighthouse_logger_default.warn(\n          \"waitFor\",\n          \"Remaining inflight requests URLs\",\n          inflightRequestUrls\n        );\n      }\n      return { timedOut: true };\n    };\n  });\n  const cleanupFn = await Promise.race([\n    loadPromise,\n    maxTimeoutPromise\n  ]);\n  maxTimeoutHandle && clearTimeout(maxTimeoutHandle);\n  resolveOnFcp.cancel();\n  resolveOnLoadEvent.cancel();\n  resolveOnNetworkIdle.cancel();\n  resolveOnCPUIdle.cancel();\n  return cleanupFn();\n}\n__name(waitForFullyLoaded, \"waitForFullyLoaded\");\nfunction waitForUserToContinue(driver) {\n  function createInPagePromise() {\n    let resolve = /* @__PURE__ */ __name(() => {\n    }, \"resolve\");\n    const promise = new Promise((r) => resolve = r);\n    console.log([\n      `You have enabled Lighthouse navigation debug mode.`,\n      `When you have finished inspecting the page, evaluate \"continueLighthouseRun()\"`,\n      `in the console to continue with the Lighthouse run.`\n    ].join(\" \"));\n    window.continueLighthouseRun = resolve;\n    return promise;\n  }\n  __name(createInPagePromise, \"createInPagePromise\");\n  driver.defaultSession.setNextProtocolTimeout(Infinity);\n  return driver.executionContext.evaluate(createInPagePromise, { args: [] });\n}\n__name(waitForUserToContinue, \"waitForUserToContinue\");\n\n// core/gather/driver/navigation.js\ninit_i18n();\ninit_url_utils();\n/**\n * @license\n * Copyright 2021 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\nvar UIStrings122 = {\n  /**\n   * @description Warning that the web page redirected during testing and that may have affected the load.\n   * @example {https://example.com/requested/page} requested\n   * @example {https://example.com/final/resolved/page} final\n   */\n  warningRedirected: `The page may not be loading as expected because your test URL ({requested}) was redirected to {final}. Try testing the second URL directly.`,\n  /**\n   * @description Warning that Lighthouse timed out while waiting for the page to load.\n   */\n  warningTimeout: \"The page loaded too slowly to finish within the time limit. Results may be incomplete.\"\n};\nvar str_102 = createIcuMessageFn({ url: \"core/gather/driver/navigation.js\" }.url, UIStrings122);\nvar DEFAULT_PAUSE_AFTER_FCP = 0;\nvar DEFAULT_PAUSE_AFTER_LOAD = 0;\nvar DEFAULT_NETWORK_QUIET_THRESHOLD = 5e3;\nvar DEFAULT_CPU_QUIET_THRESHOLD = 0;\nfunction resolveWaitForFullyLoadedOptions(options) {\n  let { pauseAfterFcpMs, pauseAfterLoadMs, networkQuietThresholdMs, cpuQuietThresholdMs } = options;\n  let maxWaitMs = options.maxWaitForLoad;\n  let maxFCPMs = options.maxWaitForFcp;\n  if (typeof pauseAfterFcpMs !== \"number\") pauseAfterFcpMs = DEFAULT_PAUSE_AFTER_FCP;\n  if (typeof pauseAfterLoadMs !== \"number\") pauseAfterLoadMs = DEFAULT_PAUSE_AFTER_LOAD;\n  if (typeof networkQuietThresholdMs !== \"number\") {\n    networkQuietThresholdMs = DEFAULT_NETWORK_QUIET_THRESHOLD;\n  }\n  if (typeof cpuQuietThresholdMs !== \"number\") cpuQuietThresholdMs = DEFAULT_CPU_QUIET_THRESHOLD;\n  if (typeof maxWaitMs !== \"number\") maxWaitMs = defaultSettings.maxWaitForLoad;\n  if (typeof maxFCPMs !== \"number\") maxFCPMs = defaultSettings.maxWaitForFcp;\n  if (!options.waitUntil.includes(\"fcp\")) maxFCPMs = void 0;\n  return {\n    pauseAfterFcpMs,\n    pauseAfterLoadMs,\n    networkQuietThresholdMs,\n    cpuQuietThresholdMs,\n    maxWaitForLoadedMs: maxWaitMs,\n    maxWaitForFcpMs: maxFCPMs\n  };\n}\n__name(resolveWaitForFullyLoadedOptions, \"resolveWaitForFullyLoadedOptions\");\nasync function gotoURL(driver, requestor, options) {\n  const status = typeof requestor === \"string\" ? { msg: `Navigating to ${requestor}`, id: \"lh:driver:navigate\" } : { msg: \"Navigating using a user defined function\", id: \"lh:driver:navigate\" };\n  lighthouse_logger_default.time(status);\n  const session = driver.defaultSession;\n  const networkMonitor = driver.networkMonitor;\n  await session.sendCommand(\"Page.enable\");\n  await session.sendCommand(\"Page.setLifecycleEventsEnabled\", { enabled: true });\n  let waitForNavigationTriggered;\n  if (typeof requestor === \"string\") {\n    session.setNextProtocolTimeout(Infinity);\n    waitForNavigationTriggered = session.sendCommand(\"Page.navigate\", { url: requestor });\n  } else {\n    waitForNavigationTriggered = requestor();\n  }\n  const waitForNavigated = options.waitUntil.includes(\"navigated\");\n  const waitForLoad = options.waitUntil.includes(\"load\");\n  const waitForFcp2 = options.waitUntil.includes(\"fcp\");\n  const waitConditionPromises = [];\n  if (waitForNavigated) {\n    const navigatedPromise = waitForFrameNavigated(session).promise;\n    waitConditionPromises.push(navigatedPromise.then(() => ({ timedOut: false })));\n  }\n  if (waitForLoad) {\n    const waitOptions = resolveWaitForFullyLoadedOptions(options);\n    waitConditionPromises.push(waitForFullyLoaded(session, networkMonitor, waitOptions));\n  } else if (waitForFcp2) {\n    throw new Error(\"Cannot wait for FCP without waiting for page load\");\n  }\n  const waitConditions = await Promise.race([\n    session.onCrashPromise(),\n    Promise.all(waitConditionPromises)\n  ]);\n  const timedOut = waitConditions.some((condition) => condition.timedOut);\n  const navigationUrls = await networkMonitor.getNavigationUrls();\n  let requestedUrl = navigationUrls.requestedUrl;\n  if (typeof requestor === \"string\") {\n    if (requestedUrl && !url_utils_default.equalWithExcludedFragments(requestor, requestedUrl)) {\n      lighthouse_logger_default.error(\n        \"Navigation\",\n        `Provided URL (${requestor}) did not match initial navigation URL (${requestedUrl})`\n      );\n    }\n    requestedUrl = requestor;\n  }\n  if (!requestedUrl) throw Error(\"No navigations detected when running user defined requestor.\");\n  const mainDocumentUrl = navigationUrls.mainDocumentUrl || requestedUrl;\n  await waitForNavigationTriggered;\n  if (options.debugNavigation) {\n    await waitForUserToContinue(driver);\n  }\n  lighthouse_logger_default.timeEnd(status);\n  return {\n    requestedUrl,\n    mainDocumentUrl,\n    warnings: getNavigationWarnings({ timedOut, mainDocumentUrl, requestedUrl })\n  };\n}\n__name(gotoURL, \"gotoURL\");\nfunction getNavigationWarnings(navigation2) {\n  const { requestedUrl, mainDocumentUrl } = navigation2;\n  const warnings = [];\n  if (navigation2.timedOut) warnings.push(str_102(UIStrings122.warningTimeout));\n  if (!url_utils_default.equalWithExcludedFragments(requestedUrl, mainDocumentUrl)) {\n    warnings.push(str_102(UIStrings122.warningRedirected, {\n      requested: requestedUrl,\n      final: mainDocumentUrl\n    }));\n  }\n  return warnings;\n}\n__name(getNavigationWarnings, \"getNavigationWarnings\");\n\n// core/gather/navigation-runner.js\ninit_format();\ninit_lh_error();\ninit_url_utils();\n\n// core/lib/navigation-error.js\ninit_process_global();\ninit_lantern2();\ninit_lh_error();\ninit_network_request();\ninit_i18n();\n/**\n * @license\n * Copyright 2021 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\nvar UIStrings123 = {\n  /**\n   * Warning shown in report when the page under test is an XHTML document, which Lighthouse does not directly support\n   * so we display a warning.\n   */\n  warningXhtml: \"The page MIME type is XHTML: Lighthouse does not explicitly support this document type\",\n  /**\n   * @description Warning shown in report when the page under test returns an error code, which Lighthouse is not able to reliably load so we display a warning.\n   * @example {404} errorCode\n   */\n  warningStatusCode: \"Lighthouse was unable to reliably load the page you requested. Make sure you are testing the correct URL and that the server is properly responding to all requests. (Status code: {errorCode})\"\n};\nvar str_103 = createIcuMessageFn({ url: \"core/lib/navigation-error.js\" }.url, UIStrings123);\nvar HTML_MIME_TYPE = \"text/html\";\nvar XHTML_MIME_TYPE = \"application/xhtml+xml\";\nfunction getNetworkError(mainRecord, context) {\n  if (!mainRecord) {\n    return new LighthouseError(LighthouseError.errors.NO_DOCUMENT_REQUEST);\n  } else if (mainRecord.failed) {\n    const netErr = mainRecord.localizedFailDescription;\n    if (netErr === \"net::ERR_NAME_NOT_RESOLVED\" || netErr === \"net::ERR_NAME_RESOLUTION_FAILED\" || netErr.startsWith(\"net::ERR_DNS_\")) {\n      return new LighthouseError(LighthouseError.errors.DNS_FAILURE);\n    } else {\n      return new LighthouseError(\n        LighthouseError.errors.FAILED_DOCUMENT_REQUEST,\n        { errorDetails: netErr }\n      );\n    }\n  } else if (mainRecord.hasErrorStatusCode()) {\n    if (context.ignoreStatusCode) {\n      context.warnings.push(str_103(UIStrings123.warningStatusCode, { errorCode: mainRecord.statusCode }));\n    } else {\n      return new LighthouseError(LighthouseError.errors.ERRORED_DOCUMENT_REQUEST, {\n        statusCode: `${mainRecord.statusCode}`\n      });\n    }\n  }\n}\n__name(getNetworkError, \"getNetworkError\");\nfunction getInterstitialError(mainRecord, networkRecords) {\n  if (!mainRecord) return void 0;\n  const interstitialRequest = networkRecords.find(\n    (record) => record.documentURL.startsWith(\"chrome-error://\")\n  );\n  if (!interstitialRequest) return void 0;\n  if (!mainRecord.failed) return void 0;\n  if (mainRecord.localizedFailDescription.startsWith(\"net::ERR_CERT\")) {\n    return new LighthouseError(LighthouseError.errors.INSECURE_DOCUMENT_REQUEST, {\n      securityMessages: mainRecord.localizedFailDescription\n    });\n  }\n  return new LighthouseError(LighthouseError.errors.CHROME_INTERSTITIAL_ERROR);\n}\n__name(getInterstitialError, \"getInterstitialError\");\nfunction getNonHtmlError(finalRecord) {\n  if (!finalRecord) return void 0;\n  if (!finalRecord.mimeType || finalRecord.statusCode === -1) return void 0;\n  if (finalRecord.mimeType !== HTML_MIME_TYPE && finalRecord.mimeType !== XHTML_MIME_TYPE) {\n    return new LighthouseError(LighthouseError.errors.NOT_HTML, {\n      mimeType: finalRecord.mimeType\n    });\n  }\n  return void 0;\n}\n__name(getNonHtmlError, \"getNonHtmlError\");\nfunction getPageLoadError(navigationError, context) {\n  const { url, networkRecords } = context;\n  let mainRecord = core_exports.NetworkAnalyzer.findResourceForUrl(networkRecords, url);\n  if (!mainRecord) {\n    const documentRequests = networkRecords.filter(\n      (record) => record.resourceType === NetworkRequest.TYPES.Document\n    );\n    if (documentRequests.length) {\n      mainRecord = documentRequests.reduce((min, r) => {\n        return r.networkRequestTime < min.networkRequestTime ? r : min;\n      });\n    }\n  }\n  let finalRecord;\n  if (mainRecord) {\n    finalRecord = core_exports.NetworkAnalyzer.resolveRedirects(mainRecord);\n  } else {\n    return navigationError;\n  }\n  if (finalRecord?.mimeType === XHTML_MIME_TYPE) {\n    context.warnings.push(str_103(UIStrings123.warningXhtml));\n  }\n  const networkError = getNetworkError(mainRecord, context);\n  const interstitialError = getInterstitialError(mainRecord, networkRecords);\n  const nonHtmlError = getNonHtmlError(finalRecord);\n  if (interstitialError) return interstitialError;\n  if (networkError) return networkError;\n  if (nonHtmlError) return nonHtmlError;\n  return navigationError;\n}\n__name(getPageLoadError, \"getPageLoadError\");\n\n// core/gather/navigation-runner.js\ninit_trace();\ninit_devtools_log();\ninit_network_records();\n/**\n * @license\n * Copyright 2021 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\nvar DEFAULT_HOSTNAME = \"127.0.0.1\";\nvar DEFAULT_PORT = 9222;\nasync function _setup({ driver, resolvedConfig, requestor }) {\n  await driver.connect();\n  if (typeof requestor === \"string\" && !resolvedConfig.settings.skipAboutBlank) {\n    await driver._networkMonitor?.disable();\n    await gotoURL(driver, resolvedConfig.settings.blankPage, { waitUntil: [\"navigated\"] });\n    await driver._networkMonitor?.enable();\n  }\n  const baseArtifacts = await getBaseArtifacts(resolvedConfig, driver, { gatherMode: \"navigation\" });\n  const { warnings } = await prepareTargetForNavigationMode(driver, resolvedConfig.settings, requestor);\n  baseArtifacts.LighthouseRunWarnings.push(...warnings);\n  return { baseArtifacts };\n}\n__name(_setup, \"_setup\");\nasync function _cleanupNavigation({ driver }) {\n  await clearThrottling(driver.defaultSession);\n}\n__name(_cleanupNavigation, \"_cleanupNavigation\");\nasync function _navigate(navigationContext) {\n  const { driver, resolvedConfig, requestor } = navigationContext;\n  try {\n    const { requestedUrl, mainDocumentUrl, warnings } = await gotoURL(driver, requestor, {\n      ...resolvedConfig.settings,\n      waitUntil: resolvedConfig.settings.pauseAfterFcpMs ? [\"fcp\", \"load\"] : [\"load\"]\n    });\n    navigationContext.baseArtifacts.LighthouseRunWarnings.push(...warnings);\n    return { requestedUrl, mainDocumentUrl, navigationError: void 0 };\n  } catch (err) {\n    if (!(err instanceof LighthouseError)) throw err;\n    if (err.code !== \"NO_FCP\" && err.code !== \"PAGE_HUNG\" && err.code !== \"TARGET_CRASHED\") {\n      throw err;\n    }\n    if (typeof requestor !== \"string\") throw err;\n    return {\n      requestedUrl: requestor,\n      mainDocumentUrl: requestor,\n      navigationError: err\n    };\n  }\n}\n__name(_navigate, \"_navigate\");\nasync function _collectDebugData(navigationContext, phaseState) {\n  let devtoolsLog;\n  let trace;\n  for (const definition of phaseState.artifactDefinitions) {\n    const { instance } = definition.gatherer;\n    if (instance instanceof devtools_log_default) {\n      devtoolsLog = instance.getDebugData();\n    } else if (instance instanceof trace_default) {\n      trace = instance.getDebugData();\n    }\n  }\n  const records = devtoolsLog && await NetworkRecordsComputed.request(devtoolsLog, navigationContext);\n  return { devtoolsLog, records, trace };\n}\n__name(_collectDebugData, \"_collectDebugData\");\nasync function _computeNavigationResult(navigationContext, phaseState, navigateResult) {\n  const { navigationError, requestedUrl, mainDocumentUrl } = navigateResult;\n  const debugData = await _collectDebugData(navigationContext, phaseState);\n  const pageLoadError = debugData.records ? getPageLoadError(navigationError, {\n    url: mainDocumentUrl,\n    ignoreStatusCode: navigationContext.resolvedConfig.settings.ignoreStatusCode,\n    networkRecords: debugData.records,\n    warnings: navigationContext.baseArtifacts.LighthouseRunWarnings\n  }) : navigationError;\n  if (pageLoadError) {\n    const locale = navigationContext.resolvedConfig.settings.locale;\n    const localizedMessage = getFormatted(pageLoadError.friendlyMessage, locale);\n    lighthouse_logger_default.error(\"NavigationRunner\", localizedMessage, requestedUrl);\n    const artifacts = {};\n    if (debugData.devtoolsLog) {\n      artifacts.DevtoolsLogError = debugData.devtoolsLog;\n    }\n    if (debugData.trace) {\n      artifacts.TraceError = debugData.trace;\n    }\n    navigationContext.baseArtifacts.LighthouseRunWarnings.push(pageLoadError.friendlyMessage);\n    navigationContext.baseArtifacts.PageLoadError = pageLoadError;\n    return artifacts;\n  } else {\n    await collectPhaseArtifacts({ phase: \"getArtifact\", ...phaseState });\n    return await awaitArtifacts(phaseState.artifactState);\n  }\n}\n__name(_computeNavigationResult, \"_computeNavigationResult\");\nasync function _navigation(navigationContext) {\n  if (!navigationContext.resolvedConfig.artifacts) {\n    throw new Error(\"No artifacts were defined on the config\");\n  }\n  const artifactState = getEmptyArtifactState();\n  const phaseState = {\n    url: await navigationContext.driver.url(),\n    gatherMode: (\n      /** @type {const} */\n      \"navigation\"\n    ),\n    driver: navigationContext.driver,\n    page: navigationContext.page,\n    computedCache: navigationContext.computedCache,\n    artifactDefinitions: navigationContext.resolvedConfig.artifacts,\n    artifactState,\n    baseArtifacts: navigationContext.baseArtifacts,\n    settings: navigationContext.resolvedConfig.settings\n  };\n  const disableAsyncStacks = await enableAsyncStacks(navigationContext.driver.defaultSession);\n  await collectPhaseArtifacts({ phase: \"startInstrumentation\", ...phaseState });\n  await collectPhaseArtifacts({ phase: \"startSensitiveInstrumentation\", ...phaseState });\n  const navigateResult = await _navigate(navigationContext);\n  if (!Object.values(phaseState.baseArtifacts.URL).every(Boolean)) {\n    phaseState.baseArtifacts.URL = {\n      requestedUrl: navigateResult.requestedUrl,\n      mainDocumentUrl: navigateResult.mainDocumentUrl,\n      finalDisplayedUrl: await navigationContext.driver.url()\n    };\n  }\n  phaseState.url = navigateResult.mainDocumentUrl;\n  await collectPhaseArtifacts({ phase: \"stopSensitiveInstrumentation\", ...phaseState });\n  await collectPhaseArtifacts({ phase: \"stopInstrumentation\", ...phaseState });\n  await disableAsyncStacks();\n  await _cleanupNavigation(navigationContext);\n  return _computeNavigationResult(navigationContext, phaseState, navigateResult);\n}\n__name(_navigation, \"_navigation\");\nasync function _cleanup({ requestedUrl, driver, resolvedConfig, lhBrowser, lhPage }) {\n  const didResetStorage = !resolvedConfig.settings.disableStorageReset && requestedUrl;\n  if (didResetStorage) {\n    await clearDataForOrigin(\n      driver.defaultSession,\n      requestedUrl,\n      resolvedConfig.settings.clearStorageTypes\n    );\n  }\n  await driver.disconnect();\n  await lhPage?.close();\n  await lhBrowser?.disconnect();\n}\n__name(_cleanup, \"_cleanup\");\nasync function navigationGather(page, requestor, options = {}) {\n  const { flags = {}, config: config3 } = options;\n  lighthouse_logger_default.setLevel(flags.logLevel || \"error\");\n  const { resolvedConfig } = await initializeConfig(\"navigation\", config3, flags);\n  const computedCache = /* @__PURE__ */ new Map();\n  const isCallback = typeof requestor === \"function\";\n  const runnerOptions = { resolvedConfig, computedCache };\n  const gatherFn = /* @__PURE__ */ __name(async () => {\n    const normalizedRequestor = isCallback ? requestor : url_utils_default.normalizeUrl(requestor);\n    let lhBrowser = void 0;\n    let lhPage = void 0;\n    if (!page) {\n      const { hostname = DEFAULT_HOSTNAME, port = DEFAULT_PORT } = flags;\n      lhBrowser = await puppeteer_core_default.connect({ browserURL: `http://${hostname}:${port}`, defaultViewport: null });\n      lhPage = await lhBrowser.newPage();\n      page = lhPage;\n    }\n    const driver = new Driver(page);\n    const context = {\n      driver,\n      lhBrowser,\n      lhPage,\n      page,\n      resolvedConfig,\n      requestor: normalizedRequestor,\n      computedCache\n    };\n    const { baseArtifacts } = await _setup(context);\n    const artifacts2 = await _navigation({ ...context, baseArtifacts });\n    await _cleanup(context);\n    return finalizeArtifacts(baseArtifacts, artifacts2);\n  }, \"gatherFn\");\n  const artifacts = await Runner.gather(gatherFn, runnerOptions);\n  return { artifacts, runnerOptions };\n}\n__name(navigationGather, \"navigationGather\");\n\n// core/user-flow.js\ninit_format();\ninit_i18n();\ninit_lh();\n/**\n * @license\n * Copyright 2021 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\nvar UIStrings124 = {\n  /**\n   * @description Default name for a user flow on the given url. \"User flow\" refers to the series of page navigations and user interactions being tested on the page. \"url\" is a trimmed version of a url that only includes the domain name.\n   * @example {example.com} url\n   */\n  defaultFlowName: \"User flow ({url})\",\n  /**\n   * @description Default name for a Lighthouse report that analyzes a page navigation. \"url\" is a trimmed version of a url that only includes the domain name and path.\n   * @example {example.com/page} url\n   */\n  defaultNavigationName: \"Navigation report ({url})\",\n  /**\n   * @description Default name for a Lighthouse report that analyzes user interactions over a period of time. \"url\" is a trimmed version of a url that only includes the domain name and path.\n   * @example {example.com/page} url\n   */\n  defaultTimespanName: \"Timespan report ({url})\",\n  /**\n   * @description Default name for a Lighthouse report that analyzes the page state at a point in time. \"url\" is a trimmed version of a url that only includes the domain name and path.\n   * @example {example.com/page} url\n   */\n  defaultSnapshotName: \"Snapshot report ({url})\"\n};\nvar str_104 = createIcuMessageFn({ url: \"core/user-flow.js\" }.url, UIStrings124);\n\n// core/index.js\ninit_lh();\ninit_audit();\ninit_base_gatherer();\ninit_network_records();\n\n// core/config/desktop-config.js\ninit_process_global();\ninit_lh();\n/**\n * @license\n * Copyright 2020 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\nvar config2 = {\n  extends: \"lighthouse:default\",\n  settings: {\n    formFactor: \"desktop\",\n    throttling: throttling2.desktopDense4G,\n    screenEmulation: screenEmulationMetrics.desktop,\n    emulatedUserAgent: userAgents.desktop\n  }\n};\n\n// core/index.js\ninit_lh();\n/**\n * @license\n * Copyright 2016 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\nasync function navigation(page, requestor, options) {\n  const gatherResult = await navigationGather(page, requestor, options);\n  return Runner.audit(gatherResult.artifacts, gatherResult.runnerOptions);\n}\n__name(navigation, \"navigation\");\nasync function snapshot(page, options) {\n  const gatherResult = await snapshotGather(page, options);\n  return Runner.audit(gatherResult.artifacts, gatherResult.runnerOptions);\n}\n__name(snapshot, \"snapshot\");\nfunction generateReport(result, format = \"html\") {\n  const reportOutput = ReportGenerator.generateReport(result, format);\n  if (Array.isArray(reportOutput)) {\n    return reportOutput[0];\n  } else {\n    return reportOutput;\n  }\n}\n__name(generateReport, \"generateReport\");\nvar traceCategories = trace_default.getDefaultTraceCategories();\n\n// clients/devtools-mcp/devtools-mcp-entry.js\n/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\nexport {\n  generateReport,\n  navigation,\n  snapshot\n};\n//# sourceMappingURL=lighthouse-devtools-mcp-bundle.js.map\n"
  },
  {
    "path": "src/tools/ToolDefinition.ts",
    "content": "/**\n * @license\n * Copyright 2025 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport type {ParsedArguments} from '../bin/chrome-devtools-mcp-cli-options.js';\nimport type {McpPage} from '../McpPage.js';\nimport {zod} from '../third_party/index.js';\nimport type {\n  Dialog,\n  ElementHandle,\n  Page,\n  ScreenRecorder,\n  Viewport,\n} from '../third_party/index.js';\nimport type {InsightName, TraceResult} from '../trace-processing/parse.js';\nimport type {\n  TextSnapshotNode,\n  GeolocationOptions,\n  ExtensionServiceWorker,\n} from '../types.js';\nimport type {InstalledExtension} from '../utils/ExtensionRegistry.js';\nimport type {PaginationOptions} from '../utils/types.js';\n\nimport type {ToolCategory} from './categories.js';\n\nexport interface BaseToolDefinition<\n  Schema extends zod.ZodRawShape = zod.ZodRawShape,\n> {\n  name: string;\n  description: string;\n  annotations: {\n    title?: string;\n    category: ToolCategory;\n    /**\n     * If true, the tool does not modify its environment.\n     */\n    readOnlyHint: boolean;\n    conditions?: string[];\n  };\n  schema: Schema;\n}\n\nexport interface ToolDefinition<\n  Schema extends zod.ZodRawShape = zod.ZodRawShape,\n> extends BaseToolDefinition<Schema> {\n  schema: Schema;\n  handler: (\n    request: Request<Schema>,\n    response: Response,\n    context: Context,\n  ) => Promise<void>;\n}\n\nexport interface Request<Schema extends zod.ZodRawShape> {\n  params: zod.objectOutputType<Schema, zod.ZodTypeAny>;\n}\n\nexport interface ImageContentData {\n  data: string;\n  mimeType: string;\n}\n\nexport interface SnapshotParams {\n  verbose?: boolean;\n  filePath?: string;\n}\n\nexport interface LighthouseData {\n  summary: {\n    mode: string;\n    device: string;\n    url?: string;\n    scores: Array<{\n      id: string;\n      title: string;\n      score: number | null;\n    }>;\n    audits: {\n      failed: number;\n      passed: number;\n    };\n    timing: {\n      total: number;\n    };\n  };\n  reports: string[];\n}\n\nexport interface DevToolsData {\n  cdpRequestId?: string;\n  cdpBackendNodeId?: number;\n}\n\nexport interface Response {\n  appendResponseLine(value: string): void;\n  setIncludePages(value: boolean): void;\n  setIncludeNetworkRequests(\n    value: boolean,\n    options?: PaginationOptions & {\n      resourceTypes?: string[];\n      includePreservedRequests?: boolean;\n      networkRequestIdInDevToolsUI?: number;\n    },\n  ): void;\n  setIncludeConsoleData(\n    value: boolean,\n    options?: PaginationOptions & {\n      types?: string[];\n      includePreservedMessages?: boolean;\n    },\n  ): void;\n  includeSnapshot(params?: SnapshotParams): void;\n  attachImage(value: ImageContentData): void;\n  attachNetworkRequest(\n    reqid: number,\n    options?: {requestFilePath?: string; responseFilePath?: string},\n  ): void;\n  attachConsoleMessage(msgid: number): void;\n  // Allows re-using DevTools data queried by some tools.\n  attachDevToolsData(data: DevToolsData): void;\n  setTabId(tabId: string): void;\n  attachTraceSummary(trace: TraceResult): void;\n  attachTraceInsight(\n    trace: TraceResult,\n    insightSetId: string,\n    insightName: InsightName,\n  ): void;\n  setListExtensions(): void;\n  attachLighthouseResult(result: LighthouseData): void;\n}\n\n/**\n * Only add methods required by tools/*.\n */\nexport type Context = Readonly<{\n  isRunningPerformanceTrace(): boolean;\n  setIsRunningPerformanceTrace(x: boolean): void;\n  isCruxEnabled(): boolean;\n  recordedTraces(): TraceResult[];\n  storeTraceRecording(result: TraceResult): void;\n  getPageById(pageId: number): ContextPage;\n  newPage(\n    background?: boolean,\n    isolatedContextName?: string,\n  ): Promise<ContextPage>;\n  closePage(pageId: number): Promise<void>;\n  selectPage(page: ContextPage): void;\n  restoreEmulation(page: ContextPage): Promise<void>;\n  emulate(\n    options: {\n      networkConditions?: string;\n      cpuThrottlingRate?: number;\n      geolocation?: GeolocationOptions;\n      userAgent?: string;\n      colorScheme?: 'dark' | 'light' | 'auto';\n      viewport?: Viewport;\n    },\n    targetPage?: Page,\n  ): Promise<void>;\n  saveTemporaryFile(\n    data: Uint8Array<ArrayBufferLike>,\n    filename: string,\n  ): Promise<{filepath: string}>;\n  saveFile(\n    data: Uint8Array<ArrayBufferLike>,\n    filename: string,\n  ): Promise<{filename: string}>;\n  waitForEventsAfterAction(\n    action: () => Promise<unknown>,\n    options?: {timeout?: number},\n  ): Promise<void>;\n  waitForTextOnPage(\n    text: string[],\n    timeout?: number,\n    page?: Page,\n  ): Promise<Element>;\n  getDevToolsData(page: ContextPage): Promise<DevToolsData>;\n  /**\n   * Returns a reqid for a cdpRequestId.\n   */\n  resolveCdpRequestId(\n    page: ContextPage,\n    cdpRequestId: string,\n  ): number | undefined;\n  getScreenRecorder(): {recorder: ScreenRecorder; filePath: string} | null;\n  setScreenRecorder(\n    data: {recorder: ScreenRecorder; filePath: string} | null,\n  ): void;\n  installExtension(path: string): Promise<string>;\n  uninstallExtension(id: string): Promise<void>;\n  triggerExtensionAction(id: string): Promise<void>;\n  listExtensions(): InstalledExtension[];\n  getExtension(id: string): InstalledExtension | undefined;\n  getSelectedMcpPage(): McpPage;\n  getExtensionServiceWorkers(): ExtensionServiceWorker[];\n  getExtensionServiceWorkerId(\n    extensionServiceWorker: ExtensionServiceWorker,\n  ): string | undefined;\n}>;\n\nexport type ContextPage = Readonly<{\n  readonly pptrPage: Page;\n  getAXNodeByUid(uid: string): TextSnapshotNode | undefined;\n  getElementByUid(uid: string): Promise<ElementHandle<Element>>;\n\n  getDialog(): Dialog | undefined;\n  clearDialog(): void;\n}>;\n\nexport function defineTool<Schema extends zod.ZodRawShape>(\n  definition: ToolDefinition<Schema>,\n): ToolDefinition<Schema>;\n\nexport function defineTool<\n  Schema extends zod.ZodRawShape,\n  Args extends ParsedArguments = ParsedArguments,\n>(\n  definition: (args?: Args) => ToolDefinition<Schema>,\n): (args?: Args) => ToolDefinition<Schema>;\n\nexport function defineTool<\n  Schema extends zod.ZodRawShape,\n  Args extends ParsedArguments = ParsedArguments,\n>(\n  definition:\n    | ToolDefinition<Schema>\n    | ((args?: Args) => ToolDefinition<Schema>),\n) {\n  if (typeof definition === 'function') {\n    const factory = definition;\n    return (args: Args) => {\n      return factory(args);\n    };\n  }\n  return definition;\n}\n\ninterface PageToolDefinition<\n  Schema extends zod.ZodRawShape = zod.ZodRawShape,\n> extends BaseToolDefinition<Schema> {\n  handler: (\n    request: Request<Schema> & {page: ContextPage},\n    response: Response,\n    context: Context,\n  ) => Promise<void>;\n}\n\nexport type DefinedPageTool<Schema extends zod.ZodRawShape = zod.ZodRawShape> =\n  PageToolDefinition<Schema> & {\n    pageScoped: true;\n    handler: (\n      request: Request<Schema> & {page: ContextPage},\n      response: Response,\n      context: Context,\n    ) => Promise<void>;\n  };\n\nexport function definePageTool<Schema extends zod.ZodRawShape>(\n  definition: PageToolDefinition<Schema>,\n): DefinedPageTool<Schema>;\n\nexport function definePageTool<\n  Schema extends zod.ZodRawShape,\n  Args extends ParsedArguments = ParsedArguments,\n>(\n  definition: (args?: Args) => PageToolDefinition<Schema>,\n): (args?: Args) => DefinedPageTool<Schema>;\n\nexport function definePageTool<\n  Schema extends zod.ZodRawShape,\n  Args extends ParsedArguments = ParsedArguments,\n>(\n  definition:\n    | PageToolDefinition<Schema>\n    | ((args?: Args) => PageToolDefinition<Schema>),\n): DefinedPageTool<Schema> | ((args?: Args) => DefinedPageTool<Schema>) {\n  if (typeof definition === 'function') {\n    return (args?: Args): DefinedPageTool<Schema> => {\n      const tool = definition(args);\n      return {\n        ...tool,\n        pageScoped: true,\n      };\n    };\n  }\n\n  return {\n    ...definition,\n    pageScoped: true,\n  } as DefinedPageTool<Schema>;\n}\n\nexport const CLOSE_PAGE_ERROR =\n  'The last open page cannot be closed. It is fine to keep it open.';\n\nexport const pageIdSchema = {\n  pageId: zod.number().optional().describe('Targets a specific page by ID.'),\n};\n\nexport const timeoutSchema = {\n  timeout: zod\n    .number()\n    .int()\n    .optional()\n    .describe(\n      `Maximum wait time in milliseconds. If set to 0, the default timeout will be used.`,\n    )\n    .transform(value => {\n      return value && value <= 0 ? undefined : value;\n    }),\n};\n\nexport function viewportTransform(arg: string | undefined):\n  | {\n      width: number;\n      height: number;\n      deviceScaleFactor?: number;\n      isMobile?: boolean;\n      isLandscape?: boolean;\n      hasTouch?: boolean;\n    }\n  | undefined {\n  if (!arg) {\n    return undefined;\n  }\n  const [dimensions, ...tags] = arg.split(',');\n  const isMobile = tags.includes('mobile');\n  const hasTouch = tags.includes('touch');\n  const isLandscape = tags.includes('landscape');\n  const [width, height, dpr] = dimensions.split('x').map(Number) as [\n    number,\n    number,\n    number | undefined,\n  ];\n  return {\n    width,\n    height,\n    deviceScaleFactor: dpr,\n    isMobile: isMobile,\n    isLandscape: isLandscape,\n    hasTouch: hasTouch,\n  };\n}\n\nexport function geolocationTransform(arg: string | undefined) {\n  if (!arg) {\n    return undefined;\n  }\n  const [latitude, longitude] = arg.split('x').map(Number) as [number, number];\n  return {\n    latitude,\n    longitude,\n  };\n}\n"
  },
  {
    "path": "src/tools/categories.ts",
    "content": "/**\n * @license\n * Copyright 2025 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nexport enum ToolCategory {\n  INPUT = 'input',\n  NAVIGATION = 'navigation',\n  EMULATION = 'emulation',\n  PERFORMANCE = 'performance',\n  NETWORK = 'network',\n  DEBUGGING = 'debugging',\n  EXTENSIONS = 'extensions',\n}\n\nexport const labels = {\n  [ToolCategory.INPUT]: 'Input automation',\n  [ToolCategory.NAVIGATION]: 'Navigation automation',\n  [ToolCategory.EMULATION]: 'Emulation',\n  [ToolCategory.PERFORMANCE]: 'Performance',\n  [ToolCategory.NETWORK]: 'Network',\n  [ToolCategory.DEBUGGING]: 'Debugging',\n  [ToolCategory.EXTENSIONS]: 'Extensions',\n};\n"
  },
  {
    "path": "src/tools/console.ts",
    "content": "/**\n * @license\n * Copyright 2025 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport {zod} from '../third_party/index.js';\nimport type {ConsoleMessageType} from '../third_party/index.js';\n\nimport {ToolCategory} from './categories.js';\nimport {definePageTool} from './ToolDefinition.js';\ntype ConsoleResponseType = ConsoleMessageType | 'issue';\n\nconst FILTERABLE_MESSAGE_TYPES: [\n  ConsoleResponseType,\n  ...ConsoleResponseType[],\n] = [\n  'log',\n  'debug',\n  'info',\n  'error',\n  'warn',\n  'dir',\n  'dirxml',\n  'table',\n  'trace',\n  'clear',\n  'startGroup',\n  'startGroupCollapsed',\n  'endGroup',\n  'assert',\n  'profile',\n  'profileEnd',\n  'count',\n  'timeEnd',\n  'verbose',\n  'issue',\n];\n\nexport const listConsoleMessages = definePageTool({\n  name: 'list_console_messages',\n  description:\n    'List all console messages for the currently selected page since the last navigation.',\n  annotations: {\n    category: ToolCategory.DEBUGGING,\n    readOnlyHint: true,\n  },\n  schema: {\n    pageSize: zod\n      .number()\n      .int()\n      .positive()\n      .optional()\n      .describe(\n        'Maximum number of messages to return. When omitted, returns all requests.',\n      ),\n    pageIdx: zod\n      .number()\n      .int()\n      .min(0)\n      .optional()\n      .describe(\n        'Page number to return (0-based). When omitted, returns the first page.',\n      ),\n    types: zod\n      .array(zod.enum(FILTERABLE_MESSAGE_TYPES))\n      .optional()\n      .describe(\n        'Filter messages to only return messages of the specified resource types. When omitted or empty, returns all messages.',\n      ),\n    includePreservedMessages: zod\n      .boolean()\n      .default(false)\n      .optional()\n      .describe(\n        'Set to true to return the preserved messages over the last 3 navigations.',\n      ),\n  },\n  handler: async (request, response) => {\n    response.setIncludeConsoleData(true, {\n      pageSize: request.params.pageSize,\n      pageIdx: request.params.pageIdx,\n      types: request.params.types,\n      includePreservedMessages: request.params.includePreservedMessages,\n    });\n  },\n});\n\nexport const getConsoleMessage = definePageTool({\n  name: 'get_console_message',\n  description: `Gets a console message by its ID. You can get all messages by calling ${listConsoleMessages.name}.`,\n  annotations: {\n    category: ToolCategory.DEBUGGING,\n    readOnlyHint: true,\n  },\n  schema: {\n    msgid: zod\n      .number()\n      .describe(\n        'The msgid of a console message on the page from the listed console messages',\n      ),\n  },\n  handler: async (request, response) => {\n    response.attachConsoleMessage(request.params.msgid);\n  },\n});\n"
  },
  {
    "path": "src/tools/emulation.ts",
    "content": "/**\n * @license\n * Copyright 2025 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n *\n */\n\nimport {zod, PredefinedNetworkConditions} from '../third_party/index.js';\n\nimport {ToolCategory} from './categories.js';\nimport {\n  definePageTool,\n  geolocationTransform,\n  viewportTransform,\n} from './ToolDefinition.js';\n\nconst throttlingOptions: [string, ...string[]] = [\n  'Offline',\n  ...Object.keys(PredefinedNetworkConditions),\n];\n\nexport const emulate = definePageTool({\n  name: 'emulate',\n  description: `Emulates various features on the selected page.`,\n  annotations: {\n    category: ToolCategory.EMULATION,\n    readOnlyHint: false,\n  },\n  schema: {\n    networkConditions: zod\n      .enum(throttlingOptions)\n      .optional()\n      .describe(`Throttle network. Omit to disable throttling.`),\n    cpuThrottlingRate: zod\n      .number()\n      .min(1)\n      .max(20)\n      .optional()\n      .describe(\n        'Represents the CPU slowdown factor. Omit or set the rate to 1 to disable throttling',\n      ),\n    geolocation: zod\n      .string()\n      .optional()\n      .transform(geolocationTransform)\n      .describe(\n        'Geolocation (`<latitude>x<longitude>`) to emulate. Latitude between -90 and 90. Longitude between -180 and 180. Omit clear the geolocation override.',\n      ),\n    userAgent: zod\n      .string()\n      .optional()\n      .describe(\n        'User agent to emulate. Set to empty string to clear the user agent override.',\n      ),\n    colorScheme: zod\n      .enum(['dark', 'light', 'auto'])\n      .optional()\n      .describe(\n        'Emulate the dark or the light mode. Set to \"auto\" to reset to the default.',\n      ),\n    viewport: zod\n      .string()\n      .optional()\n      .transform(viewportTransform)\n      .describe(\n        `Emulate device viewports '<width>x<height>x<devicePixelRatio>[,mobile][,touch][,landscape]'. 'touch' and 'mobile' to emulate mobile devices. 'landscape' to emulate landscape mode.`,\n      ),\n  },\n  handler: async (request, _response, context) => {\n    const page = request.page;\n    await context.emulate(request.params, page.pptrPage);\n  },\n});\n"
  },
  {
    "path": "src/tools/extensions.ts",
    "content": "/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport {zod} from '../third_party/index.js';\n\nimport {ToolCategory} from './categories.js';\nimport {defineTool} from './ToolDefinition.js';\n\nconst EXTENSIONS_CONDITION = 'experimentalExtensionSupport';\n\nexport const installExtension = defineTool({\n  name: 'install_extension',\n  description: 'Installs a Chrome extension from the given path.',\n  annotations: {\n    category: ToolCategory.EXTENSIONS,\n    readOnlyHint: false,\n    conditions: [EXTENSIONS_CONDITION],\n  },\n  schema: {\n    path: zod\n      .string()\n      .describe('Absolute path to the unpacked extension folder.'),\n  },\n  handler: async (request, response, context) => {\n    const {path} = request.params;\n    const id = await context.installExtension(path);\n    response.appendResponseLine(`Extension installed. Id: ${id}`);\n  },\n});\n\nexport const uninstallExtension = defineTool({\n  name: 'uninstall_extension',\n  description: 'Uninstalls a Chrome extension by its ID.',\n  annotations: {\n    category: ToolCategory.EXTENSIONS,\n    readOnlyHint: false,\n    conditions: [EXTENSIONS_CONDITION],\n  },\n  schema: {\n    id: zod.string().describe('ID of the extension to uninstall.'),\n  },\n  handler: async (request, response, context) => {\n    const {id} = request.params;\n    await context.uninstallExtension(id);\n    response.appendResponseLine(`Extension uninstalled. Id: ${id}`);\n  },\n});\n\nexport const listExtensions = defineTool({\n  name: 'list_extensions',\n  description:\n    'Lists all extensions via this server, including their name, ID, version, and enabled status.',\n  annotations: {\n    category: ToolCategory.EXTENSIONS,\n    readOnlyHint: true,\n    conditions: [EXTENSIONS_CONDITION],\n  },\n  schema: {},\n  handler: async (_request, response, _context) => {\n    response.setListExtensions();\n  },\n});\n\nexport const reloadExtension = defineTool({\n  name: 'reload_extension',\n  description: 'Reloads an unpacked Chrome extension by its ID.',\n  annotations: {\n    category: ToolCategory.EXTENSIONS,\n    readOnlyHint: false,\n    conditions: [EXTENSIONS_CONDITION],\n  },\n  schema: {\n    id: zod.string().describe('ID of the extension to reload.'),\n  },\n  handler: async (request, response, context) => {\n    const {id} = request.params;\n    const extension = context.getExtension(id);\n    if (!extension) {\n      throw new Error(`Extension with ID ${id} not found.`);\n    }\n    await context.installExtension(extension.path);\n    response.appendResponseLine('Extension reloaded.');\n  },\n});\n\nexport const triggerExtensionAction = defineTool({\n  name: 'trigger_extension_action',\n  description: 'Triggers an action in a Chrome extension.',\n  annotations: {\n    category: ToolCategory.EXTENSIONS,\n    readOnlyHint: false,\n    conditions: [EXTENSIONS_CONDITION],\n  },\n  schema: {\n    id: zod.string().describe('ID of the extension.'),\n  },\n  handler: async (request, response, context) => {\n    const {id} = request.params;\n    await context.triggerExtensionAction(id);\n    response.appendResponseLine(`Extension action triggered. Id: ${id}`);\n  },\n});\n"
  },
  {
    "path": "src/tools/input.ts",
    "content": "/**\n * @license\n * Copyright 2025 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport {logger} from '../logger.js';\nimport type {McpContext, TextSnapshotNode} from '../McpContext.js';\nimport {zod} from '../third_party/index.js';\nimport type {ElementHandle, KeyInput} from '../third_party/index.js';\nimport {parseKey} from '../utils/keyboard.js';\n\nimport {ToolCategory} from './categories.js';\nimport type {ContextPage} from './ToolDefinition.js';\nimport {definePageTool} from './ToolDefinition.js';\n\nconst dblClickSchema = zod\n  .boolean()\n  .optional()\n  .describe('Set to true for double clicks. Default is false.');\n\nconst includeSnapshotSchema = zod\n  .boolean()\n  .optional()\n  .describe('Whether to include a snapshot in the response. Default is false.');\n\nconst submitKeySchema = zod\n  .string()\n  .optional()\n  .describe(\n    'Optional key to press after typing. E.g., \"Enter\", \"Tab\", \"Escape\"',\n  );\n\nfunction handleActionError(error: unknown, uid: string) {\n  logger('failed to act using a locator', error);\n  throw new Error(\n    `Failed to interact with the element with uid ${uid}. The element did not become interactive within the configured timeout.`,\n    {\n      cause: error,\n    },\n  );\n}\n\nexport const click = definePageTool({\n  name: 'click',\n  description: `Clicks on the provided element`,\n  annotations: {\n    category: ToolCategory.INPUT,\n    readOnlyHint: false,\n  },\n  schema: {\n    uid: zod\n      .string()\n      .describe(\n        'The uid of an element on the page from the page content snapshot',\n      ),\n    dblClick: dblClickSchema,\n    includeSnapshot: includeSnapshotSchema,\n  },\n  handler: async (request, response, context) => {\n    const uid = request.params.uid;\n    const handle = await request.page.getElementByUid(uid);\n    try {\n      await context.waitForEventsAfterAction(async () => {\n        await handle.asLocator().click({\n          count: request.params.dblClick ? 2 : 1,\n        });\n      });\n      response.appendResponseLine(\n        request.params.dblClick\n          ? `Successfully double clicked on the element`\n          : `Successfully clicked on the element`,\n      );\n      if (request.params.includeSnapshot) {\n        response.includeSnapshot();\n      }\n    } catch (error) {\n      handleActionError(error, uid);\n    } finally {\n      void handle.dispose();\n    }\n  },\n});\n\nexport const clickAt = definePageTool({\n  name: 'click_at',\n  description: `Clicks at the provided coordinates`,\n  annotations: {\n    category: ToolCategory.INPUT,\n    readOnlyHint: false,\n    conditions: ['computerVision'],\n  },\n  schema: {\n    x: zod.number().describe('The x coordinate'),\n    y: zod.number().describe('The y coordinate'),\n    dblClick: dblClickSchema,\n    includeSnapshot: includeSnapshotSchema,\n  },\n  handler: async (request, response, context) => {\n    const page = request.page;\n    await context.waitForEventsAfterAction(async () => {\n      await page.pptrPage.mouse.click(request.params.x, request.params.y, {\n        clickCount: request.params.dblClick ? 2 : 1,\n      });\n    });\n    response.appendResponseLine(\n      request.params.dblClick\n        ? `Successfully double clicked at the coordinates`\n        : `Successfully clicked at the coordinates`,\n    );\n    if (request.params.includeSnapshot) {\n      response.includeSnapshot();\n    }\n  },\n});\n\nexport const hover = definePageTool({\n  name: 'hover',\n  description: `Hover over the provided element`,\n  annotations: {\n    category: ToolCategory.INPUT,\n    readOnlyHint: false,\n  },\n  schema: {\n    uid: zod\n      .string()\n      .describe(\n        'The uid of an element on the page from the page content snapshot',\n      ),\n    includeSnapshot: includeSnapshotSchema,\n  },\n  handler: async (request, response, context) => {\n    const uid = request.params.uid;\n    const handle = await request.page.getElementByUid(uid);\n    try {\n      await context.waitForEventsAfterAction(async () => {\n        await handle.asLocator().hover();\n      });\n      response.appendResponseLine(`Successfully hovered over the element`);\n      if (request.params.includeSnapshot) {\n        response.includeSnapshot();\n      }\n    } catch (error) {\n      handleActionError(error, uid);\n    } finally {\n      void handle.dispose();\n    }\n  },\n});\n\n// The AXNode for an option doesn't contain its `value`. We set text content of the option as value.\n// If the form is a combobox, we need to find the correct option by its text value.\n// To do that, loop through the children while checking which child's text matches the requested value (requested value is actually the text content).\n// When the correct option is found, use the element handle to get the real value.\nasync function selectOption(\n  handle: ElementHandle,\n  aXNode: TextSnapshotNode,\n  value: string,\n) {\n  let optionFound = false;\n  for (const child of aXNode.children) {\n    if (child.role === 'option' && child.name === value && child.value) {\n      optionFound = true;\n      const childHandle = await child.elementHandle();\n      if (childHandle) {\n        try {\n          const childValueHandle = await childHandle.getProperty('value');\n          try {\n            const childValue = await childValueHandle.jsonValue();\n            if (childValue) {\n              await handle.asLocator().fill(childValue.toString());\n            }\n          } finally {\n            void childValueHandle.dispose();\n          }\n          break;\n        } finally {\n          void childHandle.dispose();\n        }\n      }\n    }\n  }\n  if (!optionFound) {\n    throw new Error(`Could not find option with text \"${value}\"`);\n  }\n}\n\nfunction hasOptionChildren(aXNode: TextSnapshotNode) {\n  return aXNode.children.some(child => child.role === 'option');\n}\n\nasync function fillFormElement(\n  uid: string,\n  value: string,\n  context: McpContext,\n  page: ContextPage,\n) {\n  const handle = await page.getElementByUid(uid);\n  try {\n    const aXNode = context.getAXNodeByUid(uid);\n    // We assume that combobox needs to be handled as select if it has\n    // role='combobox' and option children.\n    if (aXNode && aXNode.role === 'combobox' && hasOptionChildren(aXNode)) {\n      await selectOption(handle, aXNode, value);\n    } else {\n      // Increase timeout for longer input values.\n      const timeoutPerChar = 10; // ms\n      const fillTimeout =\n        page.pptrPage.getDefaultTimeout() + value.length * timeoutPerChar;\n      await handle.asLocator().setTimeout(fillTimeout).fill(value);\n    }\n  } catch (error) {\n    handleActionError(error, uid);\n  } finally {\n    void handle.dispose();\n  }\n}\n\nexport const fill = definePageTool({\n  name: 'fill',\n  description: `Type text into a input, text area or select an option from a <select> element.`,\n  annotations: {\n    category: ToolCategory.INPUT,\n    readOnlyHint: false,\n  },\n  schema: {\n    uid: zod\n      .string()\n      .describe(\n        'The uid of an element on the page from the page content snapshot',\n      ),\n    value: zod.string().describe('The value to fill in'),\n    includeSnapshot: includeSnapshotSchema,\n  },\n  handler: async (request, response, context) => {\n    const page = request.page;\n    await context.waitForEventsAfterAction(async () => {\n      await fillFormElement(\n        request.params.uid,\n        request.params.value,\n        context as McpContext,\n        page,\n      );\n    });\n    response.appendResponseLine(`Successfully filled out the element`);\n    if (request.params.includeSnapshot) {\n      response.includeSnapshot();\n    }\n  },\n});\n\nexport const typeText = definePageTool({\n  name: 'type_text',\n  description: `Type text using keyboard into a previously focused input`,\n  annotations: {\n    category: ToolCategory.INPUT,\n    readOnlyHint: false,\n  },\n  schema: {\n    text: zod.string().describe('The text to type'),\n    submitKey: submitKeySchema,\n  },\n  handler: async (request, response, context) => {\n    const page = request.page;\n    await context.waitForEventsAfterAction(async () => {\n      await page.pptrPage.keyboard.type(request.params.text);\n      if (request.params.submitKey) {\n        await page.pptrPage.keyboard.press(\n          request.params.submitKey as KeyInput,\n        );\n      }\n    });\n    response.appendResponseLine(\n      `Typed text \"${request.params.text}${request.params.submitKey ? ` + ${request.params.submitKey}` : ''}\"`,\n    );\n  },\n});\n\nexport const drag = definePageTool({\n  name: 'drag',\n  description: `Drag an element onto another element`,\n  annotations: {\n    category: ToolCategory.INPUT,\n    readOnlyHint: false,\n  },\n  schema: {\n    from_uid: zod.string().describe('The uid of the element to drag'),\n    to_uid: zod.string().describe('The uid of the element to drop into'),\n    includeSnapshot: includeSnapshotSchema,\n  },\n  handler: async (request, response, context) => {\n    const fromHandle = await request.page.getElementByUid(\n      request.params.from_uid,\n    );\n    const toHandle = await request.page.getElementByUid(request.params.to_uid);\n    try {\n      await context.waitForEventsAfterAction(async () => {\n        await fromHandle.drag(toHandle);\n        await new Promise(resolve => setTimeout(resolve, 50));\n        await toHandle.drop(fromHandle);\n      });\n      response.appendResponseLine(`Successfully dragged an element`);\n      if (request.params.includeSnapshot) {\n        response.includeSnapshot();\n      }\n    } finally {\n      void fromHandle.dispose();\n      void toHandle.dispose();\n    }\n  },\n});\n\nexport const fillForm = definePageTool({\n  name: 'fill_form',\n  description: `Fill out multiple form elements at once`,\n  annotations: {\n    category: ToolCategory.INPUT,\n    readOnlyHint: false,\n  },\n  schema: {\n    elements: zod\n      .array(\n        zod.object({\n          uid: zod.string().describe('The uid of the element to fill out'),\n          value: zod.string().describe('Value for the element'),\n        }),\n      )\n      .describe('Elements from snapshot to fill out.'),\n    includeSnapshot: includeSnapshotSchema,\n  },\n  handler: async (request, response, context) => {\n    const page = request.page;\n    for (const element of request.params.elements) {\n      await context.waitForEventsAfterAction(async () => {\n        await fillFormElement(\n          element.uid,\n          element.value,\n          context as McpContext,\n          page,\n        );\n      });\n    }\n    response.appendResponseLine(`Successfully filled out the form`);\n    if (request.params.includeSnapshot) {\n      response.includeSnapshot();\n    }\n  },\n});\n\nexport const uploadFile = definePageTool({\n  name: 'upload_file',\n  description: 'Upload a file through a provided element.',\n  annotations: {\n    category: ToolCategory.INPUT,\n    readOnlyHint: false,\n  },\n  schema: {\n    uid: zod\n      .string()\n      .describe(\n        'The uid of the file input element or an element that will open file chooser on the page from the page content snapshot',\n      ),\n    filePath: zod.string().describe('The local path of the file to upload'),\n    includeSnapshot: includeSnapshotSchema,\n  },\n  handler: async (request, response) => {\n    const {uid, filePath} = request.params;\n    const handle = (await request.page.getElementByUid(\n      uid,\n    )) as ElementHandle<HTMLInputElement>;\n    try {\n      try {\n        await handle.uploadFile(filePath);\n      } catch {\n        // Some sites use a proxy element to trigger file upload instead of\n        // a type=file element. In this case, we want to default to\n        // Page.waitForFileChooser() and upload the file this way.\n        try {\n          const [fileChooser] = await Promise.all([\n            request.page.pptrPage.waitForFileChooser({timeout: 3000}),\n            handle.asLocator().click(),\n          ]);\n          await fileChooser.accept([filePath]);\n        } catch {\n          throw new Error(\n            `Failed to upload file. The element could not accept the file directly, and clicking it did not trigger a file chooser.`,\n          );\n        }\n      }\n      if (request.params.includeSnapshot) {\n        response.includeSnapshot();\n      }\n      response.appendResponseLine(`File uploaded from ${filePath}.`);\n    } finally {\n      void handle.dispose();\n    }\n  },\n});\n\nexport const pressKey = definePageTool({\n  name: 'press_key',\n  description: `Press a key or key combination. Use this when other input methods like fill() cannot be used (e.g., keyboard shortcuts, navigation keys, or special key combinations).`,\n  annotations: {\n    category: ToolCategory.INPUT,\n    readOnlyHint: false,\n  },\n  schema: {\n    key: zod\n      .string()\n      .describe(\n        'A key or a combination (e.g., \"Enter\", \"Control+A\", \"Control++\", \"Control+Shift+R\"). Modifiers: Control, Shift, Alt, Meta',\n      ),\n    includeSnapshot: includeSnapshotSchema,\n  },\n  handler: async (request, response, context) => {\n    const page = request.page;\n    const tokens = parseKey(request.params.key);\n    const [key, ...modifiers] = tokens;\n\n    await context.waitForEventsAfterAction(async () => {\n      for (const modifier of modifiers) {\n        await page.pptrPage.keyboard.down(modifier);\n      }\n      await page.pptrPage.keyboard.press(key);\n      for (const modifier of modifiers.toReversed()) {\n        await page.pptrPage.keyboard.up(modifier);\n      }\n    });\n\n    response.appendResponseLine(\n      `Successfully pressed key: ${request.params.key}`,\n    );\n    if (request.params.includeSnapshot) {\n      response.includeSnapshot();\n    }\n  },\n});\n"
  },
  {
    "path": "src/tools/lighthouse.ts",
    "content": "/**\n * @license\n * Copyright 2025 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport path from 'node:path';\n\nimport {\n  snapshot,\n  navigation,\n  generateReport,\n  zod,\n  type Flags,\n  type RunnerResult,\n  type OutputMode,\n} from '../third_party/index.js';\n\nimport {ToolCategory} from './categories.js';\nimport {startTrace} from './performance.js';\nimport {definePageTool} from './ToolDefinition.js';\n\nexport const lighthouseAudit = definePageTool({\n  name: 'lighthouse_audit',\n  description: `Get Lighthouse score and reports for accessibility, SEO and best practices. This excludes performance. For performance audits, run ${startTrace.name}`,\n  annotations: {\n    category: ToolCategory.DEBUGGING,\n    readOnlyHint: true,\n  },\n  schema: {\n    mode: zod\n      .enum(['navigation', 'snapshot'])\n      .default('navigation')\n      .describe(\n        '\"navigation\" reloads & audits. \"snapshot\" analyzes current state.',\n      ),\n    device: zod\n      .enum(['desktop', 'mobile'])\n      .default('desktop')\n      .describe('Device to emulate.'),\n    outputDirPath: zod\n      .string()\n      .optional()\n      .describe('Directory for reports. If omitted, uses temporary files.'),\n  },\n  handler: async (request, response, context) => {\n    const page = request.page;\n    const categories = ['accessibility', 'seo', 'best-practices'];\n    const formats = ['json', 'html'] as OutputMode[];\n    const {\n      mode = 'navigation',\n      device = 'desktop',\n      outputDirPath,\n    } = request.params;\n\n    const flags: Flags = {\n      onlyCategories: categories,\n      output: formats,\n      // Default 30 second timeout for page load.\n      maxWaitForLoad: 30_000,\n    };\n\n    if (device === 'desktop') {\n      flags.formFactor = 'desktop';\n      flags.screenEmulation = {\n        mobile: false,\n        width: 1350,\n        height: 940,\n        deviceScaleFactor: 1,\n        disabled: false,\n      };\n    } else {\n      flags.formFactor = 'mobile';\n      flags.screenEmulation = {\n        mobile: true,\n        width: 412,\n        height: 823,\n        deviceScaleFactor: 1.75,\n        disabled: false,\n      };\n    }\n\n    let result: RunnerResult | undefined;\n    try {\n      if (mode === 'navigation') {\n        result = await navigation(page.pptrPage, page.pptrPage.url(), {\n          flags,\n        });\n      } else {\n        result = await snapshot(page.pptrPage, {\n          flags,\n        });\n      }\n\n      if (!result) {\n        throw new Error('Lighthouse audit failed.');\n      }\n    } finally {\n      await context.restoreEmulation(page);\n    }\n\n    const lhr = result.lhr;\n    const reportPaths: string[] = [];\n\n    const encoder = new TextEncoder();\n    for (const format of formats) {\n      const report = generateReport(lhr, format);\n      const data = encoder.encode(report);\n      if (outputDirPath) {\n        const reportPath = path.join(outputDirPath, `report.${format}`);\n        const {filename} = await context.saveFile(data, reportPath);\n        reportPaths.push(filename);\n      } else {\n        const {filepath} = await context.saveTemporaryFile(\n          data,\n          `report.${format}`,\n        );\n        reportPaths.push(filepath);\n      }\n    }\n\n    const categoryScores = Object.values(lhr.categories).map(c => ({\n      id: c.id,\n      title: c.title,\n      score: c.score,\n    }));\n\n    const failedAudits = Object.values(lhr.audits).filter(\n      a => a.score !== null && a.score < 1,\n    ).length;\n\n    const passedAudits = Object.values(lhr.audits).filter(\n      a => a.score === 1,\n    ).length;\n\n    const output = {\n      summary: {\n        mode,\n        device,\n        url: lhr.mainDocumentUrl,\n        scores: categoryScores,\n        audits: {\n          failed: failedAudits,\n          passed: passedAudits,\n        },\n        timing: {\n          total: lhr.timing.total,\n        },\n      },\n      reports: reportPaths,\n    };\n\n    response.attachLighthouseResult(output);\n  },\n});\n"
  },
  {
    "path": "src/tools/memory.ts",
    "content": "/**\n * @license\n * Copyright 2025 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport {zod} from '../third_party/index.js';\n\nimport {ToolCategory} from './categories.js';\nimport {definePageTool} from './ToolDefinition.js';\n\nexport const takeMemorySnapshot = definePageTool({\n  name: 'take_memory_snapshot',\n  description: `Capture a memory heapsnapshot of the currently selected page to memory leak debugging`,\n  annotations: {\n    category: ToolCategory.PERFORMANCE,\n    readOnlyHint: true,\n  },\n  schema: {\n    filePath: zod\n      .string()\n      .describe('A path to a .heapsnapshot file to save the heapsnapshot to.'),\n  },\n  handler: async (request, response, _context) => {\n    const page = request.page;\n\n    await page.pptrPage.captureHeapSnapshot({\n      path: request.params.filePath,\n    });\n\n    response.appendResponseLine(\n      `Heap snapshot saved to ${request.params.filePath}`,\n    );\n  },\n});\n"
  },
  {
    "path": "src/tools/network.ts",
    "content": "/**\n * @license\n * Copyright 2025 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport {zod} from '../third_party/index.js';\nimport type {ResourceType} from '../third_party/index.js';\n\nimport {ToolCategory} from './categories.js';\nimport {definePageTool} from './ToolDefinition.js';\n\nconst FILTERABLE_RESOURCE_TYPES: readonly [ResourceType, ...ResourceType[]] = [\n  'document',\n  'stylesheet',\n  'image',\n  'media',\n  'font',\n  'script',\n  'texttrack',\n  'xhr',\n  'fetch',\n  'prefetch',\n  'eventsource',\n  'websocket',\n  'manifest',\n  'signedexchange',\n  'ping',\n  'cspviolationreport',\n  'preflight',\n  'fedcm',\n  'other',\n];\n\nexport const listNetworkRequests = definePageTool({\n  name: 'list_network_requests',\n  description: `List all requests for the currently selected page since the last navigation.`,\n  annotations: {\n    category: ToolCategory.NETWORK,\n    readOnlyHint: true,\n  },\n  schema: {\n    pageSize: zod\n      .number()\n      .int()\n      .positive()\n      .optional()\n      .describe(\n        'Maximum number of requests to return. When omitted, returns all requests.',\n      ),\n    pageIdx: zod\n      .number()\n      .int()\n      .min(0)\n      .optional()\n      .describe(\n        'Page number to return (0-based). When omitted, returns the first page.',\n      ),\n    resourceTypes: zod\n      .array(zod.enum(FILTERABLE_RESOURCE_TYPES))\n      .optional()\n      .describe(\n        'Filter requests to only return requests of the specified resource types. When omitted or empty, returns all requests.',\n      ),\n    includePreservedRequests: zod\n      .boolean()\n      .default(false)\n      .optional()\n      .describe(\n        'Set to true to return the preserved requests over the last 3 navigations.',\n      ),\n  },\n  handler: async (request, response, context) => {\n    const data = await context.getDevToolsData(request.page);\n    response.attachDevToolsData(data);\n    const reqid = data?.cdpRequestId\n      ? context.resolveCdpRequestId(request.page, data.cdpRequestId)\n      : undefined;\n    response.setIncludeNetworkRequests(true, {\n      pageSize: request.params.pageSize,\n      pageIdx: request.params.pageIdx,\n      resourceTypes: request.params.resourceTypes,\n      includePreservedRequests: request.params.includePreservedRequests,\n      networkRequestIdInDevToolsUI: reqid,\n    });\n  },\n});\n\nexport const getNetworkRequest = definePageTool({\n  name: 'get_network_request',\n  description: `Gets a network request by an optional reqid, if omitted returns the currently selected request in the DevTools Network panel.`,\n  annotations: {\n    category: ToolCategory.NETWORK,\n    readOnlyHint: false,\n  },\n  schema: {\n    reqid: zod\n      .number()\n      .optional()\n      .describe(\n        'The reqid of the network request. If omitted returns the currently selected request in the DevTools Network panel.',\n      ),\n    requestFilePath: zod\n      .string()\n      .optional()\n      .describe(\n        'The absolute or relative path to save the request body to. If omitted, the body is returned inline.',\n      ),\n    responseFilePath: zod\n      .string()\n      .optional()\n      .describe(\n        'The absolute or relative path to save the response body to. If omitted, the body is returned inline.',\n      ),\n  },\n  handler: async (request, response, context) => {\n    if (request.params.reqid) {\n      response.attachNetworkRequest(request.params.reqid, {\n        requestFilePath: request.params.requestFilePath,\n        responseFilePath: request.params.responseFilePath,\n      });\n    } else {\n      const data = await context.getDevToolsData(request.page);\n      response.attachDevToolsData(data);\n      const reqid = data?.cdpRequestId\n        ? context.resolveCdpRequestId(request.page, data.cdpRequestId)\n        : undefined;\n      if (reqid) {\n        response.attachNetworkRequest(reqid, {\n          requestFilePath: request.params.requestFilePath,\n          responseFilePath: request.params.responseFilePath,\n        });\n      } else {\n        response.appendResponseLine(\n          `Nothing is currently selected in the DevTools Network panel.`,\n        );\n      }\n    }\n  },\n});\n"
  },
  {
    "path": "src/tools/pages.ts",
    "content": "/**\n * @license\n * Copyright 2025 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport {logger} from '../logger.js';\nimport type {CdpPage, Dialog} from '../third_party/index.js';\nimport {zod} from '../third_party/index.js';\n\nimport {ToolCategory} from './categories.js';\nimport {\n  CLOSE_PAGE_ERROR,\n  definePageTool,\n  defineTool,\n  timeoutSchema,\n} from './ToolDefinition.js';\n\nexport const listPages = definePageTool(args => {\n  return {\n    name: 'list_pages',\n    description: `Get a list of pages ${args?.categoryExtensions ? 'including extension service workers' : ''} open in the browser.`,\n    annotations: {\n      category: ToolCategory.NAVIGATION,\n      readOnlyHint: true,\n    },\n    schema: {},\n    handler: async (_request, response) => {\n      response.setIncludePages(true);\n    },\n  };\n});\n\nexport const selectPage = defineTool({\n  name: 'select_page',\n  description: `Select a page as a context for future tool calls.`,\n  annotations: {\n    category: ToolCategory.NAVIGATION,\n    readOnlyHint: true,\n  },\n  schema: {\n    pageId: zod\n      .number()\n      .describe(\n        `The ID of the page to select. Call ${listPages().name} to get available pages.`,\n      ),\n    bringToFront: zod\n      .boolean()\n      .optional()\n      .describe('Whether to focus the page and bring it to the top.'),\n  },\n  handler: async (request, response, context) => {\n    const page = context.getPageById(request.params.pageId);\n    context.selectPage(page);\n    response.setIncludePages(true);\n    if (request.params.bringToFront) {\n      await page.pptrPage.bringToFront();\n    }\n  },\n});\n\nexport const closePage = defineTool({\n  name: 'close_page',\n  description: `Closes the page by its index. The last open page cannot be closed.`,\n  annotations: {\n    category: ToolCategory.NAVIGATION,\n    readOnlyHint: false,\n  },\n  schema: {\n    pageId: zod\n      .number()\n      .describe('The ID of the page to close. Call list_pages to list pages.'),\n  },\n  handler: async (request, response, context) => {\n    try {\n      await context.closePage(request.params.pageId);\n    } catch (err) {\n      if (err.message === CLOSE_PAGE_ERROR) {\n        response.appendResponseLine(err.message);\n      } else {\n        throw err;\n      }\n    }\n    response.setIncludePages(true);\n  },\n});\n\nexport const newPage = defineTool({\n  name: 'new_page',\n  description: `Open a new tab and load a URL. Use project URL if not specified otherwise.`,\n  annotations: {\n    category: ToolCategory.NAVIGATION,\n    readOnlyHint: false,\n  },\n  schema: {\n    url: zod.string().describe('URL to load in a new page.'),\n    background: zod\n      .boolean()\n      .optional()\n      .describe(\n        'Whether to open the page in the background without bringing it to the front. Default is false (foreground).',\n      ),\n    isolatedContext: zod\n      .string()\n      .optional()\n      .describe(\n        'If specified, the page is created in an isolated browser context with the given name. ' +\n          'Pages in the same browser context share cookies and storage. ' +\n          'Pages in different browser contexts are fully isolated.',\n      ),\n    ...timeoutSchema,\n  },\n  handler: async (request, response, context) => {\n    const page = await context.newPage(\n      request.params.background,\n      request.params.isolatedContext,\n    );\n\n    await context.waitForEventsAfterAction(\n      async () => {\n        await page.pptrPage.goto(request.params.url, {\n          timeout: request.params.timeout,\n        });\n      },\n      {timeout: request.params.timeout},\n    );\n\n    response.setIncludePages(true);\n  },\n});\n\nexport const navigatePage = definePageTool({\n  name: 'navigate_page',\n  description: `Go to a URL, or back, forward, or reload. Use project URL if not specified otherwise.`,\n  annotations: {\n    category: ToolCategory.NAVIGATION,\n    readOnlyHint: false,\n  },\n  schema: {\n    type: zod\n      .enum(['url', 'back', 'forward', 'reload'])\n      .optional()\n      .describe(\n        'Navigate the page by URL, back or forward in history, or reload.',\n      ),\n    url: zod.string().optional().describe('Target URL (only type=url)'),\n    ignoreCache: zod\n      .boolean()\n      .optional()\n      .describe('Whether to ignore cache on reload.'),\n    handleBeforeUnload: zod\n      .enum(['accept', 'decline'])\n      .optional()\n      .describe(\n        'Whether to auto accept or beforeunload dialogs triggered by this navigation. Default is accept.',\n      ),\n    initScript: zod\n      .string()\n      .optional()\n      .describe(\n        'A JavaScript script to be executed on each new document before any other scripts for the next navigation.',\n      ),\n    ...timeoutSchema,\n  },\n  handler: async (request, response, context) => {\n    const page = request.page;\n    const options = {\n      timeout: request.params.timeout,\n    };\n\n    if (!request.params.type && !request.params.url) {\n      throw new Error('Either URL or a type is required.');\n    }\n\n    if (!request.params.type) {\n      request.params.type = 'url';\n    }\n\n    const handleBeforeUnload = request.params.handleBeforeUnload ?? 'accept';\n    const dialogHandler = (dialog: Dialog) => {\n      if (dialog.type() === 'beforeunload') {\n        if (handleBeforeUnload === 'accept') {\n          response.appendResponseLine(`Accepted a beforeunload dialog.`);\n          void dialog.accept();\n        } else {\n          response.appendResponseLine(`Declined a beforeunload dialog.`);\n          void dialog.dismiss();\n        }\n        // We are not going to report the dialog like regular dialogs.\n        page.clearDialog();\n      }\n    };\n\n    let initScriptId: string | undefined;\n    if (request.params.initScript) {\n      const {identifier} = await page.pptrPage.evaluateOnNewDocument(\n        request.params.initScript,\n      );\n      initScriptId = identifier;\n    }\n\n    page.pptrPage.on('dialog', dialogHandler);\n\n    try {\n      await context.waitForEventsAfterAction(\n        async () => {\n          switch (request.params.type) {\n            case 'url':\n              if (!request.params.url) {\n                throw new Error(\n                  'A URL is required for navigation of type=url.',\n                );\n              }\n              try {\n                await page.pptrPage.goto(request.params.url, options);\n                response.appendResponseLine(\n                  `Successfully navigated to ${request.params.url}.`,\n                );\n              } catch (error) {\n                response.appendResponseLine(\n                  `Unable to navigate in the  selected page: ${error.message}.`,\n                );\n              }\n              break;\n            case 'back':\n              try {\n                await page.pptrPage.goBack(options);\n                response.appendResponseLine(\n                  `Successfully navigated back to ${page.pptrPage.url()}.`,\n                );\n              } catch (error) {\n                response.appendResponseLine(\n                  `Unable to navigate back in the selected page: ${error.message}.`,\n                );\n              }\n              break;\n            case 'forward':\n              try {\n                await page.pptrPage.goForward(options);\n                response.appendResponseLine(\n                  `Successfully navigated forward to ${page.pptrPage.url()}.`,\n                );\n              } catch (error) {\n                response.appendResponseLine(\n                  `Unable to navigate forward in the selected page: ${error.message}.`,\n                );\n              }\n              break;\n            case 'reload':\n              try {\n                await page.pptrPage.reload({\n                  ...options,\n                  ignoreCache: request.params.ignoreCache,\n                });\n                response.appendResponseLine(`Successfully reloaded the page.`);\n              } catch (error) {\n                response.appendResponseLine(\n                  `Unable to reload the selected page: ${error.message}.`,\n                );\n              }\n              break;\n          }\n        },\n        {timeout: request.params.timeout},\n      );\n    } finally {\n      page.pptrPage.off('dialog', dialogHandler);\n      if (initScriptId) {\n        await page.pptrPage\n          .removeScriptToEvaluateOnNewDocument(initScriptId)\n          .catch(error => {\n            logger(`Failed to remove init script`, error);\n          });\n      }\n    }\n\n    response.setIncludePages(true);\n  },\n});\n\nexport const resizePage = definePageTool({\n  name: 'resize_page',\n  description: `Resizes the selected page's window so that the page has specified dimension`,\n  annotations: {\n    category: ToolCategory.EMULATION,\n    readOnlyHint: false,\n  },\n  schema: {\n    width: zod.number().describe('Page width'),\n    height: zod.number().describe('Page height'),\n  },\n  handler: async (request, response, _context) => {\n    const page = request.page;\n\n    try {\n      const browser = page.pptrPage.browser();\n      const windowId = await page.pptrPage.windowId();\n\n      const bounds = await browser.getWindowBounds(windowId);\n\n      if (bounds.windowState === 'fullscreen') {\n        // Have to call this twice on Ubuntu when the window is in fullscreen mode.\n        await browser.setWindowBounds(windowId, {windowState: 'normal'});\n        await browser.setWindowBounds(windowId, {windowState: 'normal'});\n      } else if (bounds.windowState !== 'normal') {\n        await browser.setWindowBounds(windowId, {windowState: 'normal'});\n      }\n    } catch {\n      // Window APIs are not supported on all platforms\n    }\n    await page.pptrPage.resize({\n      contentWidth: request.params.width,\n      contentHeight: request.params.height,\n    });\n\n    response.setIncludePages(true);\n  },\n});\n\nexport const handleDialog = definePageTool({\n  name: 'handle_dialog',\n  description: `If a browser dialog was opened, use this command to handle it`,\n  annotations: {\n    category: ToolCategory.INPUT,\n    readOnlyHint: false,\n  },\n  schema: {\n    action: zod\n      .enum(['accept', 'dismiss'])\n      .describe('Whether to dismiss or accept the dialog'),\n    promptText: zod\n      .string()\n      .optional()\n      .describe('Optional prompt text to enter into the dialog.'),\n  },\n  handler: async (request, response, _context) => {\n    const page = request.page;\n    const dialog = page.getDialog();\n    if (!dialog) {\n      throw new Error('No open dialog found');\n    }\n\n    switch (request.params.action) {\n      case 'accept': {\n        try {\n          await dialog.accept(request.params.promptText);\n        } catch (err) {\n          // Likely already handled by the user outside of MCP.\n          logger(err);\n        }\n        response.appendResponseLine('Successfully accepted the dialog');\n        break;\n      }\n      case 'dismiss': {\n        try {\n          await dialog.dismiss();\n        } catch (err) {\n          // Likely already handled.\n          logger(err);\n        }\n        response.appendResponseLine('Successfully dismissed the dialog');\n        break;\n      }\n    }\n\n    page.clearDialog();\n    response.setIncludePages(true);\n  },\n});\n\nexport const getTabId = definePageTool({\n  name: 'get_tab_id',\n  description: `Get the tab ID of the page`,\n  annotations: {\n    category: ToolCategory.NAVIGATION,\n    readOnlyHint: true,\n    conditions: ['experimentalInteropTools'],\n  },\n  schema: {\n    pageId: zod\n      .number()\n      .describe(\n        `The ID of the page to get the tab ID for. Call ${listPages().name} to get available pages.`,\n      ),\n  },\n  handler: async (request, response, context) => {\n    const page = context.getPageById(request.params.pageId);\n    const tabId = (page.pptrPage as unknown as CdpPage)._tabId;\n    response.setTabId(tabId);\n  },\n});\n"
  },
  {
    "path": "src/tools/performance.ts",
    "content": "/**\n * @license\n * Copyright 2025 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport zlib from 'node:zlib';\n\nimport {logger} from '../logger.js';\nimport {zod, DevTools} from '../third_party/index.js';\nimport type {Page} from '../third_party/index.js';\nimport type {InsightName, TraceResult} from '../trace-processing/parse.js';\nimport {\n  parseRawTraceBuffer,\n  traceResultIsSuccess,\n} from '../trace-processing/parse.js';\n\nimport {ToolCategory} from './categories.js';\nimport type {Context, Response} from './ToolDefinition.js';\nimport {definePageTool} from './ToolDefinition.js';\n\nconst filePathSchema = zod\n  .string()\n  .optional()\n  .describe(\n    'The absolute file path, or a file path relative to the current working directory, to save the raw trace data. For example, trace.json.gz (compressed) or trace.json (uncompressed).',\n  );\n\nexport const startTrace = definePageTool({\n  name: 'performance_start_trace',\n  description: `Start a performance trace on the selected webpage. Use to find frontend performance issues, Core Web Vitals (LCP, INP, CLS), and improve page load speed.`,\n  annotations: {\n    category: ToolCategory.PERFORMANCE,\n    readOnlyHint: false,\n  },\n  schema: {\n    reload: zod\n      .boolean()\n      .default(true)\n      .describe(\n        'Determines if, once tracing has started, the current selected page should be automatically reloaded. Navigate the page to the right URL using the navigate_page tool BEFORE starting the trace if reload or autoStop is set to true.',\n      ),\n    autoStop: zod\n      .boolean()\n      .default(true)\n      .describe(\n        'Determines if the trace recording should be automatically stopped.',\n      ),\n    filePath: filePathSchema,\n  },\n  handler: async (request, response, context) => {\n    if (context.isRunningPerformanceTrace()) {\n      response.appendResponseLine(\n        'Error: a performance trace is already running. Use performance_stop_trace to stop it. Only one trace can be running at any given time.',\n      );\n      return;\n    }\n    context.setIsRunningPerformanceTrace(true);\n\n    const page = request.page;\n    const pageUrlForTracing = page.pptrPage.url();\n\n    if (request.params.reload) {\n      // Before starting the recording, navigate to about:blank to clear out any state.\n      await page.pptrPage.goto('about:blank', {\n        waitUntil: ['networkidle0'],\n      });\n    }\n\n    // Keep in sync with the categories arrays in:\n    // https://source.chromium.org/chromium/chromium/src/+/main:third_party/devtools-frontend/src/front_end/panels/timeline/TimelineController.ts\n    // https://github.com/GoogleChrome/lighthouse/blob/master/lighthouse-core/gather/gatherers/trace.js\n    const categories = [\n      '-*',\n      'blink.console',\n      'blink.user_timing',\n      'devtools.timeline',\n      'disabled-by-default-devtools.screenshot',\n      'disabled-by-default-devtools.timeline',\n      'disabled-by-default-devtools.timeline.invalidationTracking',\n      'disabled-by-default-devtools.timeline.frame',\n      'disabled-by-default-devtools.timeline.stack',\n      'disabled-by-default-v8.cpu_profiler',\n      'disabled-by-default-v8.cpu_profiler.hires',\n      'latencyInfo',\n      'loading',\n      'disabled-by-default-lighthouse',\n      'v8.execute',\n      'v8',\n    ];\n    await page.pptrPage.tracing.start({\n      categories,\n    });\n\n    if (request.params.reload) {\n      await page.pptrPage.goto(pageUrlForTracing, {\n        waitUntil: ['load'],\n      });\n    }\n\n    if (request.params.autoStop) {\n      await new Promise(resolve => setTimeout(resolve, 5_000));\n      await stopTracingAndAppendOutput(\n        page.pptrPage,\n        response,\n        context,\n        request.params.filePath,\n      );\n    } else {\n      response.appendResponseLine(\n        `The performance trace is being recorded. Use performance_stop_trace to stop it.`,\n      );\n    }\n  },\n});\n\nexport const stopTrace = definePageTool({\n  name: 'performance_stop_trace',\n  description:\n    'Stop the active performance trace recording on the selected webpage.',\n  annotations: {\n    category: ToolCategory.PERFORMANCE,\n    readOnlyHint: false,\n  },\n  schema: {\n    filePath: filePathSchema,\n  },\n  handler: async (request, response, context) => {\n    if (!context.isRunningPerformanceTrace()) {\n      return;\n    }\n    const page = request.page;\n    await stopTracingAndAppendOutput(\n      page.pptrPage,\n      response,\n      context,\n      request.params.filePath,\n    );\n  },\n});\n\nexport const analyzeInsight = definePageTool({\n  name: 'performance_analyze_insight',\n  description:\n    'Provides more detailed information on a specific Performance Insight of an insight set that was highlighted in the results of a trace recording.',\n  annotations: {\n    category: ToolCategory.PERFORMANCE,\n    readOnlyHint: true,\n  },\n  schema: {\n    insightSetId: zod\n      .string()\n      .describe(\n        'The id for the specific insight set. Only use the ids given in the \"Available insight sets\" list.',\n      ),\n    insightName: zod\n      .string()\n      .describe(\n        'The name of the Insight you want more information on. For example: \"DocumentLatency\" or \"LCPBreakdown\"',\n      ),\n  },\n  handler: async (request, response, context) => {\n    const lastRecording = context.recordedTraces().at(-1);\n    if (!lastRecording) {\n      response.appendResponseLine(\n        'No recorded traces found. Record a performance trace so you have Insights to analyze.',\n      );\n      return;\n    }\n\n    response.attachTraceInsight(\n      lastRecording,\n      request.params.insightSetId,\n      request.params.insightName as InsightName,\n    );\n  },\n});\n\nasync function stopTracingAndAppendOutput(\n  page: Page,\n  response: Response,\n  context: Context,\n  filePath?: string,\n): Promise<void> {\n  try {\n    const traceEventsBuffer = await page.tracing.stop();\n    if (filePath && traceEventsBuffer) {\n      let dataToWrite: Uint8Array = traceEventsBuffer;\n      if (filePath.endsWith('.gz')) {\n        dataToWrite = await new Promise((resolve, reject) => {\n          zlib.gzip(traceEventsBuffer, (error, result) => {\n            if (error) {\n              reject(error);\n            } else {\n              resolve(result);\n            }\n          });\n        });\n      }\n      const file = await context.saveFile(dataToWrite, filePath);\n      response.appendResponseLine(\n        `The raw trace data was saved to ${file.filename}.`,\n      );\n    }\n    const result = await parseRawTraceBuffer(traceEventsBuffer);\n    response.appendResponseLine('The performance trace has been stopped.');\n    if (traceResultIsSuccess(result)) {\n      if (context.isCruxEnabled()) {\n        await populateCruxData(result);\n      }\n      context.storeTraceRecording(result);\n      response.attachTraceSummary(result);\n    } else {\n      throw new Error(\n        `There was an unexpected error parsing the trace: ${result.error}`,\n      );\n    }\n  } finally {\n    context.setIsRunningPerformanceTrace(false);\n  }\n}\n\n/** We tell CrUXManager to fetch data so it's available when DevTools.PerformanceTraceFormatter is invoked */\nasync function populateCruxData(result: TraceResult): Promise<void> {\n  logger('populateCruxData called');\n  const cruxManager = DevTools.CrUXManager.instance();\n  // go/jtfbx. Yes, we're aware this API key is public. ;)\n  cruxManager.setEndpointForTesting(\n    'https://chromeuxreport.googleapis.com/v1/records:queryRecord?key=AIzaSyBn5gimNjhiEyA_euicSKko6IlD3HdgUfk',\n  );\n  const cruxSetting =\n    DevTools.Common.Settings.Settings.instance().createSetting('field-data', {\n      enabled: true,\n    });\n  cruxSetting.set({enabled: true});\n\n  // Gather URLs to fetch CrUX data for\n  const urls = [...(result.parsedTrace.insights?.values() ?? [])].map(c =>\n    c.url.toString(),\n  );\n  urls.push(result.parsedTrace.data.Meta.mainFrameURL);\n  const urlSet = new Set(urls);\n\n  if (urlSet.size === 0) {\n    logger('No URLs found for CrUX data');\n    return;\n  }\n\n  logger(\n    `Fetching CrUX data for ${urlSet.size} URLs: ${Array.from(urlSet).join(', ')}`,\n  );\n  const cruxData = await Promise.all(\n    Array.from(urlSet).map(async url => {\n      const data = await cruxManager.getFieldDataForPage(url);\n      logger(`CrUX data for ${url}: ${data ? 'found' : 'not found'}`);\n      return data;\n    }),\n  );\n\n  result.parsedTrace.metadata.cruxFieldData = cruxData;\n}\n"
  },
  {
    "path": "src/tools/screencast.ts",
    "content": "/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport fs from 'node:fs/promises';\nimport os from 'node:os';\nimport path from 'node:path';\n\nimport {zod} from '../third_party/index.js';\nimport type {ScreenRecorder} from '../third_party/index.js';\n\nimport {ToolCategory} from './categories.js';\nimport {definePageTool} from './ToolDefinition.js';\n\nasync function generateTempFilePath(): Promise<string> {\n  const dir = await fs.mkdtemp(path.join(os.tmpdir(), 'chrome-devtools-mcp-'));\n  return path.join(dir, `screencast.mp4`);\n}\n\nexport const startScreencast = definePageTool({\n  name: 'screencast_start',\n  description:\n    'Starts recording a screencast (video) of the selected page in mp4 format.',\n  annotations: {\n    category: ToolCategory.DEBUGGING,\n    readOnlyHint: false,\n\n    conditions: ['screencast'],\n  },\n  schema: {\n    path: zod\n      .string()\n      .optional()\n      .describe(\n        'Output path. Uses mkdtemp to generate a unique path if not provided.',\n      ),\n  },\n  handler: async (request, response, context) => {\n    if (context.getScreenRecorder() !== null) {\n      response.appendResponseLine(\n        'Error: a screencast recording is already in progress. Use screencast_stop to stop it before starting a new one.',\n      );\n      return;\n    }\n\n    const filePath = request.params.path ?? (await generateTempFilePath());\n    const resolvedPath = path.resolve(filePath);\n\n    const page = request.page;\n\n    let recorder: ScreenRecorder;\n    try {\n      recorder = await page.pptrPage.screencast({\n        path: resolvedPath as `${string}.mp4`,\n        format: 'mp4' as const,\n      });\n    } catch (err) {\n      const message = err instanceof Error ? err.message : String(err);\n      if (message.includes('ENOENT') && message.includes('ffmpeg')) {\n        throw new Error(\n          'ffmpeg is required for screencast recording but was not found. ' +\n            'Install ffmpeg (https://ffmpeg.org/) and ensure it is available in your PATH.',\n        );\n      }\n      throw err;\n    }\n\n    context.setScreenRecorder({recorder, filePath: resolvedPath});\n\n    response.appendResponseLine(\n      `Screencast recording started. The recording will be saved to ${resolvedPath}. Use ${stopScreencast.name} to stop recording.`,\n    );\n  },\n});\n\nexport const stopScreencast = definePageTool({\n  name: 'screencast_stop',\n  description: 'Stops the active screencast recording on the selected page.',\n  annotations: {\n    category: ToolCategory.DEBUGGING,\n    readOnlyHint: false,\n    conditions: ['screencast'],\n  },\n  schema: {},\n  handler: async (_request, response, context) => {\n    const data = context.getScreenRecorder();\n    if (!data) {\n      return;\n    }\n    try {\n      await data.recorder.stop();\n      response.appendResponseLine(\n        `The screencast recording has been stopped and saved to ${data.filePath}.`,\n      );\n    } finally {\n      context.setScreenRecorder(null);\n    }\n  },\n});\n"
  },
  {
    "path": "src/tools/screenshot.ts",
    "content": "/**\n * @license\n * Copyright 2025 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport {zod} from '../third_party/index.js';\nimport type {ElementHandle, Page} from '../third_party/index.js';\n\nimport {ToolCategory} from './categories.js';\nimport {definePageTool} from './ToolDefinition.js';\n\nexport const screenshot = definePageTool({\n  name: 'take_screenshot',\n  description: `Take a screenshot of the page or element.`,\n  annotations: {\n    category: ToolCategory.DEBUGGING,\n    // Not read-only due to filePath param.\n    readOnlyHint: false,\n  },\n  schema: {\n    format: zod\n      .enum(['png', 'jpeg', 'webp'])\n      .default('png')\n      .describe('Type of format to save the screenshot as. Default is \"png\"'),\n    quality: zod\n      .number()\n      .min(0)\n      .max(100)\n      .optional()\n      .describe(\n        'Compression quality for JPEG and WebP formats (0-100). Higher values mean better quality but larger file sizes. Ignored for PNG format.',\n      ),\n    uid: zod\n      .string()\n      .optional()\n      .describe(\n        'The uid of an element on the page from the page content snapshot. If omitted takes a pages screenshot.',\n      ),\n    fullPage: zod\n      .boolean()\n      .optional()\n      .describe(\n        'If set to true takes a screenshot of the full page instead of the currently visible viewport. Incompatible with uid.',\n      ),\n    filePath: zod\n      .string()\n      .optional()\n      .describe(\n        'The absolute path, or a path relative to the current working directory, to save the screenshot to instead of attaching it to the response.',\n      ),\n  },\n  handler: async (request, response, context) => {\n    if (request.params.uid && request.params.fullPage) {\n      throw new Error('Providing both \"uid\" and \"fullPage\" is not allowed.');\n    }\n\n    let pageOrHandle: Page | ElementHandle;\n    if (request.params.uid) {\n      pageOrHandle = await request.page.getElementByUid(request.params.uid);\n    } else {\n      pageOrHandle = request.page.pptrPage;\n    }\n\n    const format = request.params.format;\n    const quality = format === 'png' ? undefined : request.params.quality;\n\n    const screenshot = await pageOrHandle.screenshot({\n      type: format,\n      fullPage: request.params.fullPage,\n      quality,\n      optimizeForSpeed: true, // Bonus: optimize encoding for speed\n    });\n\n    if (request.params.uid) {\n      response.appendResponseLine(\n        `Took a screenshot of node with uid \"${request.params.uid}\".`,\n      );\n    } else if (request.params.fullPage) {\n      response.appendResponseLine(\n        'Took a screenshot of the full current page.',\n      );\n    } else {\n      response.appendResponseLine(\n        \"Took a screenshot of the current page's viewport.\",\n      );\n    }\n\n    if (request.params.filePath) {\n      const file = await context.saveFile(screenshot, request.params.filePath);\n      response.appendResponseLine(`Saved screenshot to ${file.filename}.`);\n    } else if (screenshot.length >= 2_000_000) {\n      const {filepath} = await context.saveTemporaryFile(\n        screenshot,\n        `screenshot.${request.params.format}`,\n      );\n      response.appendResponseLine(`Saved screenshot to ${filepath}.`);\n    } else {\n      response.attachImage({\n        mimeType: `image/${request.params.format}`,\n        data: Buffer.from(screenshot).toString('base64'),\n      });\n    }\n  },\n});\n"
  },
  {
    "path": "src/tools/script.ts",
    "content": "/**\n * @license\n * Copyright 2025 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport {zod} from '../third_party/index.js';\nimport type {Frame, JSHandle, Page, WebWorker} from '../third_party/index.js';\nimport type {ExtensionServiceWorker} from '../types.js';\n\nimport {ToolCategory} from './categories.js';\nimport type {Context, Response} from './ToolDefinition.js';\nimport {defineTool, pageIdSchema} from './ToolDefinition.js';\n\nexport type Evaluatable = Page | Frame | WebWorker;\n\nexport const evaluateScript = defineTool(cliArgs => {\n  return {\n    name: 'evaluate_script',\n    description: `Evaluate a JavaScript function inside the currently selected page. Returns the response as JSON,\nso returned values have to be JSON-serializable.`,\n    annotations: {\n      category: ToolCategory.DEBUGGING,\n      readOnlyHint: false,\n    },\n    schema: {\n      function: zod.string().describe(\n        `A JavaScript function declaration to be executed by the tool in the currently selected page.\nExample without arguments: \\`() => {\n  return document.title\n}\\` or \\`async () => {\n  return await fetch(\"example.com\")\n}\\`.\nExample with arguments: \\`(el) => {\n  return el.innerText;\n}\\`\n`,\n      ),\n      args: zod\n        .array(\n          zod\n            .string()\n            .describe(\n              'The uid of an element on the page from the page content snapshot',\n            ),\n        )\n        .optional()\n        .describe(`An optional list of arguments to pass to the function.`),\n      ...(cliArgs?.experimentalPageIdRouting ? pageIdSchema : {}),\n      ...(cliArgs?.categoryExtensions\n        ? {\n            serviceWorkerId: zod\n              .string()\n              .optional()\n              .describe(\n                `An optional service worker id to evaluate the script in.`,\n              ),\n          }\n        : {}),\n    },\n    handler: async (request, response, context) => {\n      const {\n        serviceWorkerId,\n        args: uidArgs,\n        function: fnString,\n        pageId,\n      } = request.params;\n\n      if (cliArgs?.categoryExtensions && serviceWorkerId) {\n        if (uidArgs && uidArgs.length > 0) {\n          throw new Error(\n            'args (element uids) cannot be used when evaluating in a service worker.',\n          );\n        }\n        if (pageId) {\n          throw new Error('specify either a pageId or a serviceWorkerId.');\n        }\n\n        const worker = await getWebWorker(context, serviceWorkerId);\n        await performEvaluation(worker, fnString, [], response, context);\n        return;\n      }\n\n      const mcpPage = cliArgs?.experimentalPageIdRouting\n        ? context.getPageById(request.params.pageId)\n        : context.getSelectedMcpPage();\n      const page: Page = mcpPage.pptrPage;\n\n      const args: Array<JSHandle<unknown>> = [];\n      try {\n        const frames = new Set<Frame>();\n        for (const uid of uidArgs ?? []) {\n          const handle = await mcpPage.getElementByUid(uid);\n          frames.add(handle.frame);\n          args.push(handle);\n        }\n\n        const evaluatable = await getPageOrFrame(page, frames);\n\n        await performEvaluation(evaluatable, fnString, args, response, context);\n      } finally {\n        void Promise.allSettled(args.map(arg => arg.dispose()));\n      }\n    },\n  };\n});\n\nconst performEvaluation = async (\n  evaluatable: Evaluatable,\n  fnString: string,\n  args: Array<JSHandle<unknown>>,\n  response: Response,\n  context: Context,\n) => {\n  const fn = await evaluatable.evaluateHandle(`(${fnString})`);\n  try {\n    await context.waitForEventsAfterAction(async () => {\n      const result = await evaluatable.evaluate(\n        async (fn, ...args) => {\n          // @ts-expect-error no types for function fn\n          return JSON.stringify(await fn(...args));\n        },\n        fn,\n        ...args,\n      );\n      response.appendResponseLine('Script ran on page and returned:');\n      response.appendResponseLine('```json');\n      response.appendResponseLine(`${result}`);\n      response.appendResponseLine('```');\n    });\n  } finally {\n    void fn.dispose();\n  }\n};\n\nconst getPageOrFrame = async (\n  page: Page,\n  frames: Set<Frame>,\n): Promise<Page | Frame> => {\n  let pageOrFrame: Page | Frame;\n  // We can't evaluate the element handle across frames\n  if (frames.size > 1) {\n    throw new Error(\n      \"Elements from different frames can't be evaluated together.\",\n    );\n  } else {\n    pageOrFrame = [...frames.values()][0] ?? page;\n  }\n\n  return pageOrFrame;\n};\n\nconst getWebWorker = async (\n  context: Context,\n  serviceWorkerId: string,\n): Promise<WebWorker> => {\n  const serviceWorkers = context.getExtensionServiceWorkers();\n\n  const serviceWorker = serviceWorkers.find(\n    (sw: ExtensionServiceWorker) =>\n      context.getExtensionServiceWorkerId(sw) === serviceWorkerId,\n  );\n\n  if (serviceWorker && serviceWorker.target) {\n    const worker = await serviceWorker.target.worker();\n\n    if (!worker) {\n      throw new Error('Service worker target not found.');\n    }\n\n    return worker;\n  } else {\n    throw new Error('Service worker not found.');\n  }\n};\n"
  },
  {
    "path": "src/tools/slim/tools.ts",
    "content": "/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport type {Dialog} from '../../third_party/index.js';\nimport {zod} from '../../third_party/index.js';\nimport {ToolCategory} from '../categories.js';\nimport {definePageTool} from '../ToolDefinition.js';\n\nexport const screenshot = definePageTool({\n  name: 'screenshot',\n  description: `Takes a screenshot`,\n  annotations: {\n    category: ToolCategory.DEBUGGING,\n    // Not read-only due to filePath param.\n    readOnlyHint: false,\n  },\n  schema: {},\n  handler: async (request, response, context) => {\n    const page = request.page;\n    const screenshot = await page.pptrPage.screenshot({\n      type: 'png',\n      optimizeForSpeed: true,\n    });\n    const {filepath} = await context.saveTemporaryFile(\n      screenshot,\n      `screenshot.png`,\n    );\n    response.appendResponseLine(filepath);\n  },\n});\n\nexport const navigate = definePageTool({\n  name: 'navigate',\n  description: `Loads a URL`,\n  annotations: {\n    category: ToolCategory.NAVIGATION,\n    readOnlyHint: false,\n  },\n  schema: {\n    url: zod.string().describe('URL to navigate to'),\n  },\n  handler: async (request, response) => {\n    const page = request.page;\n\n    const options = {\n      timeout: 30_000,\n    };\n\n    const dialogHandler = (dialog: Dialog) => {\n      if (dialog.type() === 'beforeunload') {\n        response.appendResponseLine(`Accepted a beforeunload dialog.`);\n        void dialog.accept();\n        // We are not going to report the dialog like regular dialogs.\n        page.clearDialog();\n      }\n    };\n\n    page.pptrPage.on('dialog', dialogHandler);\n\n    try {\n      await page.pptrPage.goto(request.params.url, options);\n      response.appendResponseLine(`Navigated to ${page.pptrPage.url()}.`);\n    } finally {\n      page.pptrPage.off('dialog', dialogHandler);\n    }\n  },\n});\n\nexport const evaluate = definePageTool({\n  name: 'evaluate',\n  description: `Evaluates a JavaScript script`,\n  annotations: {\n    category: ToolCategory.DEBUGGING,\n    readOnlyHint: false,\n  },\n  schema: {\n    script: zod.string().describe(`JS script to run on the page`),\n  },\n  handler: async (request, response) => {\n    const page = request.page;\n    try {\n      const result = await page.pptrPage.evaluate(request.params.script);\n      response.appendResponseLine(JSON.stringify(result));\n    } catch (err) {\n      response.appendResponseLine(String(err.message));\n    }\n  },\n});\n"
  },
  {
    "path": "src/tools/snapshot.ts",
    "content": "/**\n * @license\n * Copyright 2025 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport {zod} from '../third_party/index.js';\n\nimport {ToolCategory} from './categories.js';\nimport {definePageTool, timeoutSchema} from './ToolDefinition.js';\n\nexport const takeSnapshot = definePageTool({\n  name: 'take_snapshot',\n  description: `Take a text snapshot of the currently selected page based on the a11y tree. The snapshot lists page elements along with a unique\nidentifier (uid). Always use the latest snapshot. Prefer taking a snapshot over taking a screenshot. The snapshot indicates the element selected\nin the DevTools Elements panel (if any).`,\n  annotations: {\n    category: ToolCategory.DEBUGGING,\n    // Not read-only due to filePath param.\n    readOnlyHint: false,\n  },\n  schema: {\n    verbose: zod\n      .boolean()\n      .optional()\n      .describe(\n        'Whether to include all possible information available in the full a11y tree. Default is false.',\n      ),\n    filePath: zod\n      .string()\n      .optional()\n      .describe(\n        'The absolute path, or a path relative to the current working directory, to save the snapshot to instead of attaching it to the response.',\n      ),\n  },\n  handler: async (request, response) => {\n    response.includeSnapshot({\n      verbose: request.params.verbose ?? false,\n      filePath: request.params.filePath,\n    });\n  },\n});\n\nexport const waitFor = definePageTool({\n  name: 'wait_for',\n  description: `Wait for the specified text to appear on the selected page.`,\n  annotations: {\n    category: ToolCategory.NAVIGATION,\n    readOnlyHint: true,\n  },\n  schema: {\n    text: zod\n      .array(zod.string())\n      .min(1)\n      .describe(\n        'Non-empty list of texts. Resolves when any value appears on the page.',\n      ),\n    ...timeoutSchema,\n  },\n  handler: async (request, response, context) => {\n    const page = request.page;\n    await context.waitForTextOnPage(\n      request.params.text,\n      request.params.timeout,\n      page.pptrPage,\n    );\n\n    response.appendResponseLine(\n      `Element matching one of ${JSON.stringify(request.params.text)} found.`,\n    );\n\n    response.includeSnapshot();\n  },\n});\n"
  },
  {
    "path": "src/tools/tools.ts",
    "content": "/**\n * @license\n * Copyright 2025 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport type {ParsedArguments} from '../bin/chrome-devtools-mcp-cli-options.js';\n\nimport * as consoleTools from './console.js';\nimport * as emulationTools from './emulation.js';\nimport * as extensionTools from './extensions.js';\nimport * as inputTools from './input.js';\nimport * as lighthouseTools from './lighthouse.js';\nimport * as memoryTools from './memory.js';\nimport * as networkTools from './network.js';\nimport * as pagesTools from './pages.js';\nimport * as performanceTools from './performance.js';\nimport * as screencastTools from './screencast.js';\nimport * as screenshotTools from './screenshot.js';\nimport * as scriptTools from './script.js';\nimport * as slimTools from './slim/tools.js';\nimport * as snapshotTools from './snapshot.js';\nimport type {ToolDefinition} from './ToolDefinition.js';\n\nexport const createTools = (args: ParsedArguments) => {\n  const rawTools = args.slim\n    ? Object.values(slimTools)\n    : [\n        ...Object.values(consoleTools),\n        ...Object.values(emulationTools),\n        ...Object.values(extensionTools),\n        ...Object.values(inputTools),\n        ...Object.values(lighthouseTools),\n        ...Object.values(memoryTools),\n        ...Object.values(networkTools),\n        ...Object.values(pagesTools),\n        ...Object.values(performanceTools),\n        ...Object.values(screencastTools),\n        ...Object.values(screenshotTools),\n        ...Object.values(scriptTools),\n        ...Object.values(snapshotTools),\n      ];\n\n  const tools = [];\n  for (const tool of rawTools) {\n    if (typeof tool === 'function') {\n      tools.push(tool(args) as unknown as ToolDefinition);\n    } else {\n      tools.push(tool as ToolDefinition);\n    }\n  }\n\n  tools.sort((a, b) => {\n    return a.name.localeCompare(b.name);\n  });\n\n  return tools;\n};\n"
  },
  {
    "path": "src/trace-processing/parse.ts",
    "content": "/**\n * @license\n * Copyright 2025 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport {logger} from '../logger.js';\nimport {DevTools} from '../third_party/index.js';\n\nconst engine = DevTools.TraceEngine.TraceModel.Model.createWithAllHandlers();\n\nexport interface TraceResult {\n  parsedTrace: DevTools.TraceEngine.TraceModel.ParsedTrace;\n  insights: DevTools.TraceEngine.Insights.Types.TraceInsightSets | null;\n}\n\nexport function traceResultIsSuccess(\n  x: TraceResult | TraceParseError,\n): x is TraceResult {\n  return 'parsedTrace' in x;\n}\n\nexport interface TraceParseError {\n  error: string;\n}\n\nexport async function parseRawTraceBuffer(\n  buffer: Uint8Array<ArrayBufferLike> | undefined,\n): Promise<TraceResult | TraceParseError> {\n  engine.resetProcessor();\n  if (!buffer) {\n    return {\n      error: 'No buffer was provided.',\n    };\n  }\n  const asString = new TextDecoder().decode(buffer);\n  if (!asString) {\n    return {\n      error: 'Decoding the trace buffer returned an empty string.',\n    };\n  }\n  try {\n    const data = JSON.parse(asString) as\n      | {\n          traceEvents: DevTools.TraceEngine.Types.Events.Event[];\n        }\n      | DevTools.TraceEngine.Types.Events.Event[];\n\n    const events = Array.isArray(data) ? data : data.traceEvents;\n    await engine.parse(events);\n    const parsedTrace = engine.parsedTrace();\n    if (!parsedTrace) {\n      return {\n        error: 'No parsed trace was returned from the trace engine.',\n      };\n    }\n\n    const insights = parsedTrace?.insights ?? null;\n\n    return {\n      parsedTrace,\n      insights,\n    };\n  } catch (e) {\n    const errorText = e instanceof Error ? e.message : JSON.stringify(e);\n    logger(`Unexpected error parsing trace: ${errorText}`);\n    return {\n      error: errorText,\n    };\n  }\n}\n\nconst extraFormatDescriptions = `Information on performance traces may contain main thread activity represented as call frames and network requests.\n\n${DevTools.PerformanceTraceFormatter.callFrameDataFormatDescription}\n\n${DevTools.PerformanceTraceFormatter.networkDataFormatDescription}`;\n\nexport function getTraceSummary(result: TraceResult): string {\n  const focus = DevTools.AgentFocus.fromParsedTrace(result.parsedTrace);\n  const formatter = new DevTools.PerformanceTraceFormatter(focus);\n  const summaryText = formatter.formatTraceSummary();\n  return `## Summary of Performance trace findings:\n${summaryText}\n\n## Details on call tree & network request formats:\n${extraFormatDescriptions}`;\n}\n\nexport type InsightName =\n  keyof DevTools.TraceEngine.Insights.Types.InsightModels;\nexport type InsightOutput = {output: string} | {error: string};\n\nexport function getInsightOutput(\n  result: TraceResult,\n  insightSetId: string,\n  insightName: InsightName,\n): InsightOutput {\n  if (!result.insights) {\n    return {\n      error: 'No Performance insights are available for this trace.',\n    };\n  }\n\n  const insightSet = result.insights.get(insightSetId);\n  if (!insightSet) {\n    return {\n      error:\n        'No Performance Insights for the given insight set id. Only use ids given in the \"Available insight sets\" list.',\n    };\n  }\n\n  const matchingInsight =\n    insightName in insightSet.model ? insightSet.model[insightName] : null;\n  if (!matchingInsight) {\n    return {\n      error: `No Insight with the name ${insightName} found. Double check the name you provided is accurate and try again.`,\n    };\n  }\n\n  const formatter = new DevTools.PerformanceInsightFormatter(\n    DevTools.AgentFocus.fromParsedTrace(result.parsedTrace),\n    matchingInsight,\n  );\n  return {output: formatter.formatInsight()};\n}\n"
  },
  {
    "path": "src/types.ts",
    "content": "/**\n * @license\n * Copyright 2025 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport type {SerializedAXNode, Viewport, Target} from './third_party/index.js';\n\nexport interface ExtensionServiceWorker {\n  url: string;\n  target: Target;\n  id: string;\n}\n\nexport interface TextSnapshotNode extends SerializedAXNode {\n  id: string;\n  backendNodeId?: number;\n  loaderId?: string;\n  children: TextSnapshotNode[];\n}\n\nexport interface GeolocationOptions {\n  latitude: number;\n  longitude: number;\n}\n\nexport interface TextSnapshot {\n  root: TextSnapshotNode;\n  idToNode: Map<string, TextSnapshotNode>;\n  snapshotId: string;\n  selectedElementUid?: string;\n  // It might happen that there is a selected element, but it is not part of the\n  // snapshot. This flag indicates if there is any selected element.\n  hasSelectedElement: boolean;\n  verbose: boolean;\n}\n\nexport interface EmulationSettings {\n  networkConditions?: string;\n  cpuThrottlingRate?: number;\n  geolocation?: GeolocationOptions;\n  userAgent?: string;\n  colorScheme?: 'dark' | 'light';\n  viewport?: Viewport;\n}\n"
  },
  {
    "path": "src/utils/ExtensionRegistry.ts",
    "content": "/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport fs from 'node:fs/promises';\nimport path from 'node:path';\n\nexport interface InstalledExtension {\n  id: string;\n  name: string;\n  version: string;\n  isEnabled: boolean;\n  path: string;\n}\n\nexport class ExtensionRegistry {\n  #extensions = new Map<string, InstalledExtension>();\n\n  async registerExtension(\n    id: string,\n    extensionPath: string,\n  ): Promise<InstalledExtension> {\n    const manifestPath = path.join(extensionPath, 'manifest.json');\n    const manifestContent = await fs.readFile(manifestPath, 'utf-8');\n    const manifest = JSON.parse(manifestContent);\n    const name = manifest.name ?? 'Unknown';\n    const version = manifest.version ?? 'Unknown';\n\n    const extension = {\n      id,\n      name,\n      version,\n      isEnabled: true,\n      path: extensionPath,\n    };\n    this.#extensions.set(extension.id, extension);\n    return extension;\n  }\n\n  remove(id: string): void {\n    this.#extensions.delete(id);\n  }\n\n  list(): InstalledExtension[] {\n    return Array.from(this.#extensions.values());\n  }\n\n  getById(id: string): InstalledExtension | undefined {\n    return this.#extensions.get(id);\n  }\n}\n"
  },
  {
    "path": "src/utils/files.ts",
    "content": "/**\n * @license\n * Copyright 2025 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport fs from 'node:fs/promises';\nimport os from 'node:os';\nimport path from 'node:path';\n\nexport async function saveTemporaryFile(\n  data: Uint8Array<ArrayBufferLike>,\n  filename: string,\n): Promise<{filepath: string}> {\n  try {\n    const dir = await fs.mkdtemp(\n      path.join(os.tmpdir(), 'chrome-devtools-mcp-'),\n    );\n\n    const filepath = path.join(dir, filename);\n    await fs.writeFile(filepath, data);\n    return {filepath};\n  } catch (err) {\n    throw new Error('Could not save a file', {cause: err});\n  }\n}\n"
  },
  {
    "path": "src/utils/keyboard.ts",
    "content": "/**\n * @license\n * Copyright 2025 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport type {KeyInput} from '../third_party/index.js';\n\n// See the KeyInput type for the list of supported keys.\nconst validKeys = new Set([\n  '0',\n  '1',\n  '2',\n  '3',\n  '4',\n  '5',\n  '6',\n  '7',\n  '8',\n  '9',\n  'Power',\n  'Eject',\n  'Abort',\n  'Help',\n  'Backspace',\n  'Tab',\n  'Numpad5',\n  'NumpadEnter',\n  'Enter',\n  '\\r',\n  '\\n',\n  'ShiftLeft',\n  'ShiftRight',\n  'ControlLeft',\n  'ControlRight',\n  'AltLeft',\n  'AltRight',\n  'Pause',\n  'CapsLock',\n  'Escape',\n  'Convert',\n  'NonConvert',\n  'Space',\n  'Numpad9',\n  'PageUp',\n  'Numpad3',\n  'PageDown',\n  'End',\n  'Numpad1',\n  'Home',\n  'Numpad7',\n  'ArrowLeft',\n  'Numpad4',\n  'Numpad8',\n  'ArrowUp',\n  'ArrowRight',\n  'Numpad6',\n  'Numpad2',\n  'ArrowDown',\n  'Select',\n  'Open',\n  'PrintScreen',\n  'Insert',\n  'Numpad0',\n  'Delete',\n  'NumpadDecimal',\n  'Digit0',\n  'Digit1',\n  'Digit2',\n  'Digit3',\n  'Digit4',\n  'Digit5',\n  'Digit6',\n  'Digit7',\n  'Digit8',\n  'Digit9',\n  'KeyA',\n  'KeyB',\n  'KeyC',\n  'KeyD',\n  'KeyE',\n  'KeyF',\n  'KeyG',\n  'KeyH',\n  'KeyI',\n  'KeyJ',\n  'KeyK',\n  'KeyL',\n  'KeyM',\n  'KeyN',\n  'KeyO',\n  'KeyP',\n  'KeyQ',\n  'KeyR',\n  'KeyS',\n  'KeyT',\n  'KeyU',\n  'KeyV',\n  'KeyW',\n  'KeyX',\n  'KeyY',\n  'KeyZ',\n  'MetaLeft',\n  'MetaRight',\n  'ContextMenu',\n  'NumpadMultiply',\n  'NumpadAdd',\n  'NumpadSubtract',\n  'NumpadDivide',\n  'F1',\n  'F2',\n  'F3',\n  'F4',\n  'F5',\n  'F6',\n  'F7',\n  'F8',\n  'F9',\n  'F10',\n  'F11',\n  'F12',\n  'F13',\n  'F14',\n  'F15',\n  'F16',\n  'F17',\n  'F18',\n  'F19',\n  'F20',\n  'F21',\n  'F22',\n  'F23',\n  'F24',\n  'NumLock',\n  'ScrollLock',\n  'AudioVolumeMute',\n  'AudioVolumeDown',\n  'AudioVolumeUp',\n  'MediaTrackNext',\n  'MediaTrackPrevious',\n  'MediaStop',\n  'MediaPlayPause',\n  'Semicolon',\n  'Equal',\n  'NumpadEqual',\n  'Comma',\n  'Minus',\n  'Period',\n  'Slash',\n  'Backquote',\n  'BracketLeft',\n  'Backslash',\n  'BracketRight',\n  'Quote',\n  'AltGraph',\n  'Props',\n  'Cancel',\n  'Clear',\n  'Shift',\n  'Control',\n  'Alt',\n  'Accept',\n  'ModeChange',\n  ' ',\n  'Print',\n  'Execute',\n  '\\u0000',\n  'a',\n  'b',\n  'c',\n  'd',\n  'e',\n  'f',\n  'g',\n  'h',\n  'i',\n  'j',\n  'k',\n  'l',\n  'm',\n  'n',\n  'o',\n  'p',\n  'q',\n  'r',\n  's',\n  't',\n  'u',\n  'v',\n  'w',\n  'x',\n  'y',\n  'z',\n  'Meta',\n  '*',\n  '+',\n  '-',\n  '/',\n  ';',\n  '=',\n  ',',\n  '.',\n  '`',\n  '[',\n  '\\\\',\n  ']',\n  \"'\",\n  'Attn',\n  'CrSel',\n  'ExSel',\n  'EraseEof',\n  'Play',\n  'ZoomOut',\n  ')',\n  '!',\n  '@',\n  '#',\n  '$',\n  '%',\n  '^',\n  '&',\n  '(',\n  'A',\n  'B',\n  'C',\n  'D',\n  'E',\n  'F',\n  'G',\n  'H',\n  'I',\n  'J',\n  'K',\n  'L',\n  'M',\n  'N',\n  'O',\n  'P',\n  'Q',\n  'R',\n  'S',\n  'T',\n  'U',\n  'V',\n  'W',\n  'X',\n  'Y',\n  'Z',\n  ':',\n  '<',\n  '_',\n  '>',\n  '?',\n  '~',\n  '{',\n  '|',\n  '}',\n  '\"',\n  'SoftLeft',\n  'SoftRight',\n  'Camera',\n  'Call',\n  'EndCall',\n  'VolumeDown',\n  'VolumeUp',\n]);\n\nfunction throwIfInvalidKey(key: string): KeyInput {\n  if (validKeys.has(key)) {\n    return key as KeyInput;\n  }\n  throw new Error(\n    `${key} is invalid. Valid keys are: ${Array.from(validKeys.values()).join(',')}.`,\n  );\n}\n\n/**\n * Returns the primary key, followed by modifiers in original order.\n */\nexport function parseKey(keyInput: string): [KeyInput, ...KeyInput[]] {\n  let key = '';\n  const result: KeyInput[] = [];\n  for (const ch of keyInput) {\n    // Handle cases like Shift++.\n    if (ch === '+' && key) {\n      result.push(throwIfInvalidKey(key));\n      key = '';\n    } else {\n      key += ch;\n    }\n  }\n  if (key) {\n    result.push(throwIfInvalidKey(key));\n  }\n\n  if (result.length === 0) {\n    throw new Error(`Key ${keyInput} could not be parsed.`);\n  }\n\n  if (new Set(result).size !== result.length) {\n    throw new Error(`Key ${keyInput} contains duplicate keys.`);\n  }\n\n  return [result.at(-1), ...result.slice(0, -1)] as [KeyInput, ...KeyInput[]];\n}\n"
  },
  {
    "path": "src/utils/pagination.ts",
    "content": "/**\n * @license\n * Copyright 2025 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport type {PaginationOptions} from './types.js';\n\nexport interface PaginationResult<Item> {\n  items: readonly Item[];\n  currentPage: number;\n  totalPages: number;\n  hasNextPage: boolean;\n  hasPreviousPage: boolean;\n  startIndex: number;\n  endIndex: number;\n  invalidPage: boolean;\n}\n\nconst DEFAULT_PAGE_SIZE = 20;\n\nexport function paginate<Item>(\n  items: readonly Item[],\n  options?: PaginationOptions,\n): PaginationResult<Item> {\n  const total = items.length;\n\n  if (!options || noPaginationOptions(options)) {\n    return {\n      items,\n      currentPage: 0,\n      totalPages: 1,\n      hasNextPage: false,\n      hasPreviousPage: false,\n      startIndex: 0,\n      endIndex: total,\n      invalidPage: false,\n    };\n  }\n\n  const pageSize = options.pageSize ?? DEFAULT_PAGE_SIZE;\n  const totalPages = Math.max(1, Math.ceil(total / pageSize));\n  const {currentPage, invalidPage} = resolvePageIndex(\n    options.pageIdx,\n    totalPages,\n  );\n\n  const startIndex = currentPage * pageSize;\n  const pageItems = items.slice(startIndex, startIndex + pageSize);\n  const endIndex = startIndex + pageItems.length;\n\n  return {\n    items: pageItems,\n    currentPage,\n    totalPages,\n    hasNextPage: currentPage < totalPages - 1,\n    hasPreviousPage: currentPage > 0,\n    startIndex,\n    endIndex,\n    invalidPage,\n  };\n}\n\nfunction noPaginationOptions(options: PaginationOptions): boolean {\n  return options.pageSize === undefined && options.pageIdx === undefined;\n}\n\nfunction resolvePageIndex(\n  pageIdx: number | undefined,\n  totalPages: number,\n): {\n  currentPage: number;\n  invalidPage: boolean;\n} {\n  if (pageIdx === undefined) {\n    return {currentPage: 0, invalidPage: false};\n  }\n\n  if (pageIdx < 0 || pageIdx >= totalPages) {\n    return {currentPage: 0, invalidPage: true};\n  }\n\n  return {currentPage: pageIdx, invalidPage: false};\n}\n"
  },
  {
    "path": "src/utils/string.ts",
    "content": "/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\n/**\n * Converts a given string to snake_case.\n * This function handles camelCase, PascalCase, and acronyms, including transitions between letters and numbers.\n * It uses Unicode-aware regular expressions (`\\p{L}`, `\\p{N}`, `\\p{Lu}`, `\\p{Ll}` with the `u` flag)\n * to correctly process letters and numbers from various languages.\n *\n * @param text The input string to convert to snake_case.\n * @returns The snake_case version of the input string.\n */\nexport function toSnakeCase(text: string): string {\n  if (!text) {\n    return '';\n  }\n  // First, handle case-based transformations to insert underscores correctly.\n  // 1. Add underscore between a letter and a number.\n  //    e.g., \"version2\" -> \"version_2\"\n  // 2. Add underscore between an uppercase letter sequence and a following uppercase+lowercase sequence.\n  //    e.g., \"APIFlags\" -> \"API_Flags\"\n  // 3. Add underscore between a lowercase/number and an uppercase letter.\n  //    e.g., \"lastName\" -> \"last_Name\", \"version_2Update\" -> \"version_2_Update\"\n  // 4. Replace sequences of non-alphanumeric with a single underscore\n  // 5. Remove any leading or trailing underscores.\n  const result = text\n    .replace(/(\\p{L})(\\p{N})/gu, '$1_$2') // 1\n    .replace(/(\\p{Lu}+)(\\p{Lu}\\p{Ll})/gu, '$1_$2') // 2\n    .replace(/(\\p{Ll}|\\p{N})(\\p{Lu})/gu, '$1_$2') // 3\n    .toLowerCase()\n    .replace(/[^\\p{L}\\p{N}]+/gu, '_') // 4\n    .replace(/^_|_$/g, ''); // 5\n\n  return result;\n}\n"
  },
  {
    "path": "src/utils/types.ts",
    "content": "/**\n * @license\n * Copyright 2025 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nexport interface PaginationOptions {\n  pageSize?: number;\n  pageIdx?: number;\n}\n"
  },
  {
    "path": "src/version.ts",
    "content": "/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\n// If moved update release-please config\n// x-release-please-start-version\nexport const VERSION = '0.20.2';\n// x-release-please-end\n"
  },
  {
    "path": "tests/DevtoolsUtils.test.ts",
    "content": "/**\n * @license\n * Copyright 2025 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport assert from 'node:assert';\nimport {afterEach, describe, it} from 'node:test';\n\nimport sinon from 'sinon';\n\nimport {\n  extractUrlLikeFromDevToolsTitle,\n  urlsEqual,\n  UniverseManager,\n} from '../src/DevtoolsUtils.js';\nimport {DevTools} from '../src/third_party/index.js';\nimport type {Browser, Target} from '../src/third_party/index.js';\n\nimport {\n  getMockBrowser,\n  getMockPage,\n  mockListener,\n  withBrowser,\n} from './utils.js';\n\ndescribe('extractUrlFromDevToolsTitle', () => {\n  it('deals with no trailing /', () => {\n    assert.strictEqual(\n      extractUrlLikeFromDevToolsTitle('DevTools - example.com'),\n      'example.com',\n    );\n  });\n  it('deals with a trailing /', () => {\n    assert.strictEqual(\n      extractUrlLikeFromDevToolsTitle('DevTools - example.com/'),\n      'example.com/',\n    );\n  });\n  it('deals with www', () => {\n    assert.strictEqual(\n      extractUrlLikeFromDevToolsTitle('DevTools - www.example.com/'),\n      'www.example.com/',\n    );\n  });\n  it('deals with complex url', () => {\n    assert.strictEqual(\n      extractUrlLikeFromDevToolsTitle(\n        'DevTools - www.example.com/path.html?a=b#3',\n      ),\n      'www.example.com/path.html?a=b#3',\n    );\n  });\n});\n\ndescribe('urlsEqual', () => {\n  it('ignores trailing slashes', () => {\n    assert.strictEqual(\n      urlsEqual('https://google.com/', 'https://google.com'),\n      true,\n    );\n  });\n\n  it('ignores www', () => {\n    assert.strictEqual(\n      urlsEqual('https://google.com/', 'https://www.google.com'),\n      true,\n    );\n  });\n\n  it('ignores protocols', () => {\n    assert.strictEqual(\n      urlsEqual('https://google.com/', 'http://www.google.com'),\n      true,\n    );\n  });\n\n  it('does not ignore other subdomains', () => {\n    assert.strictEqual(\n      urlsEqual('https://google.com/', 'https://photos.google.com'),\n      false,\n    );\n  });\n\n  it('ignores hash', () => {\n    assert.strictEqual(\n      urlsEqual('https://google.com/#', 'http://www.google.com'),\n      true,\n    );\n    assert.strictEqual(\n      urlsEqual('https://google.com/#21', 'http://www.google.com#12'),\n      true,\n    );\n  });\n});\n\ndescribe('UniverseManager', () => {\n  afterEach(() => {\n    sinon.restore();\n  });\n\n  it('calls the factory for existing pages', async () => {\n    const browser = getMockBrowser();\n    const factory = sinon.stub().resolves({});\n    const manager = new UniverseManager(browser, factory);\n    await manager.init(await browser.pages());\n\n    const page = (await browser.pages())[0];\n    sinon.assert.calledOnceWithExactly(factory, page);\n  });\n\n  it('calls the factory only once for the same page', async () => {\n    const browser = {\n      ...mockListener(),\n    } as unknown as Browser;\n    // eslint-disable-next-line @typescript-eslint/no-empty-function\n    const factory = sinon.stub().returns(new Promise(() => {})); // Don't resolve.\n    const manager = new UniverseManager(browser, factory);\n    await manager.init([]);\n\n    sinon.assert.notCalled(factory);\n\n    const page = getMockPage();\n    browser.emit('targetcreated', {\n      page: () => Promise.resolve(page),\n    } as Target);\n    browser.emit('targetcreated', {\n      page: () => Promise.resolve(page),\n    } as Target);\n\n    await new Promise(r => setTimeout(r, 0)); // One event loop tick for the micro task queue to run.\n\n    sinon.assert.calledOnceWithExactly(factory, page);\n  });\n\n  it('works with a real browser', async () => {\n    await withBrowser(async (browser, page) => {\n      const manager = new UniverseManager(browser);\n      await manager.init([page]);\n\n      assert.notStrictEqual(manager.get(page), null);\n    });\n  });\n\n  it('ignores pauses', async () => {\n    await withBrowser(async (browser, page) => {\n      const manager = new UniverseManager(browser);\n      await manager.init([page]);\n      const targetUniverse = manager.get(page);\n      assert.ok(targetUniverse);\n      const model = targetUniverse.target.model(DevTools.DebuggerModel);\n      assert.ok(model);\n\n      const pausedSpy = sinon.stub();\n      model.addEventListener('DebuggerPaused' as any, pausedSpy); // eslint-disable-line\n\n      const result = await page.evaluate('debugger; 1 + 1');\n      assert.strictEqual(result, 2);\n\n      sinon.assert.notCalled(pausedSpy);\n    });\n  });\n});\n"
  },
  {
    "path": "tests/McpContext.test.js.snapshot",
    "content": "exports[`McpContext > should include detailed network request in structured content 1`] = `\n{\n  \"networkRequest\": {\n    \"requestId\": 456,\n    \"method\": \"GET\",\n    \"url\": \"http://example.com/detail\",\n    \"status\": \"pending\",\n    \"requestHeaders\": {\n      \"content-size\": \"10\"\n    }\n  }\n}\n`;\n\nexports[`McpContext > should include file paths in structured content when saving to file 1`] = `\n{\n  \"networkRequest\": {\n    \"requestBody\": \"/tmp/req.txt\",\n    \"responseBody\": \"/tmp/res.txt\"\n  }\n}\n`;\n\nexports[`McpContext > should include network requests in structured content 1`] = `\n{\n  \"pagination\": {\n    \"currentPage\": 0,\n    \"totalPages\": 1,\n    \"hasNextPage\": false,\n    \"hasPreviousPage\": false,\n    \"startIndex\": 0,\n    \"endIndex\": 1,\n    \"invalidPage\": false\n  },\n  \"networkRequests\": [\n    {\n      \"requestId\": 123,\n      \"method\": \"GET\",\n      \"url\": \"http://example.com/api\",\n      \"status\": \"pending\",\n      \"selectedInDevToolsUI\": false\n    }\n  ]\n}\n`;\n"
  },
  {
    "path": "tests/McpContext.test.ts",
    "content": "/**\n * @license\n * Copyright 2025 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport assert from 'node:assert';\nimport {afterEach, describe, it} from 'node:test';\n\nimport sinon from 'sinon';\n\nimport {NetworkFormatter} from '../src/formatters/NetworkFormatter.js';\nimport type {HTTPResponse} from '../src/third_party/index.js';\nimport type {TraceResult} from '../src/trace-processing/parse.js';\n\nimport {getMockRequest, html, withMcpContext} from './utils.js';\n\ndescribe('McpContext', () => {\n  afterEach(() => {\n    sinon.restore();\n  });\n\n  it('list pages', async () => {\n    await withMcpContext(async (_response, context) => {\n      const page = context.getSelectedMcpPage();\n      await page.pptrPage.setContent(\n        html`<button>Click me</button>\n          <input\n            type=\"text\"\n            value=\"Input\"\n          />`,\n      );\n      await context.createTextSnapshot(context.getSelectedMcpPage());\n      assert.ok(await page.getElementByUid('1_1'));\n      await context.createTextSnapshot(context.getSelectedMcpPage());\n      await page.getElementByUid('1_1');\n    });\n  });\n\n  it('can store and retrieve the latest performance trace', async () => {\n    await withMcpContext(async (_response, context) => {\n      const fakeTrace1 = {} as unknown as TraceResult;\n      const fakeTrace2 = {} as unknown as TraceResult;\n      context.storeTraceRecording(fakeTrace1);\n      context.storeTraceRecording(fakeTrace2);\n      assert.deepEqual(context.recordedTraces(), [fakeTrace2]);\n    });\n  });\n\n  it('should update default timeout when cpu throttling changes', async () => {\n    await withMcpContext(async (_response, context) => {\n      const page = await context.newPage();\n      const timeoutBefore = page.pptrPage.getDefaultTimeout();\n      await context.emulate({cpuThrottlingRate: 2});\n      const timeoutAfter = page.pptrPage.getDefaultTimeout();\n      assert(timeoutBefore < timeoutAfter, 'Timeout was less then expected');\n    });\n  });\n\n  it('should update default timeout when network conditions changes', async () => {\n    await withMcpContext(async (_response, context) => {\n      const page = await context.newPage();\n      const timeoutBefore = page.pptrPage.getDefaultNavigationTimeout();\n      await context.emulate({networkConditions: 'Slow 3G'});\n      const timeoutAfter = page.pptrPage.getDefaultNavigationTimeout();\n      assert(timeoutBefore < timeoutAfter, 'Timeout was less then expected');\n    });\n  });\n\n  it('should call waitForEventsAfterAction with correct multipliers', async () => {\n    await withMcpContext(async (_response, context) => {\n      const page = await context.newPage();\n\n      await context.emulate({\n        cpuThrottlingRate: 2,\n        networkConditions: 'Slow 3G',\n      });\n      const stub = sinon.spy(context, 'getWaitForHelper');\n\n      await context.waitForEventsAfterAction(async () => {\n        // trigger the waiting only\n      });\n\n      sinon.assert.calledWithExactly(stub, page.pptrPage, 2, 10);\n    });\n  });\n\n  it('should should detect open DevTools pages', async () => {\n    await withMcpContext(\n      async (_response, context) => {\n        const page = await context.newPage();\n        // TODO: we do not know when the CLI flag to auto open DevTools will run\n        // so we need this until\n        // https://github.com/puppeteer/puppeteer/issues/14368 is there.\n        await new Promise(resolve => setTimeout(resolve, 5000));\n        await context.createPagesSnapshot();\n        assert.ok(context.getDevToolsPage(page.pptrPage));\n      },\n      {\n        autoOpenDevTools: true,\n      },\n    );\n  });\n  it('resolves uid from a non-selected page snapshot', async () => {\n    await withMcpContext(async (_response, context) => {\n      // Page 1: set content and snapshot\n      const page1 = context.getSelectedMcpPage();\n      await page1.pptrPage.setContent(html`<button>Page1 Button</button>`);\n      await context.createTextSnapshot(page1, false, undefined);\n\n      // Capture a uid from page1's snapshot (snapshotId=1, button is node 1)\n      const page1Uid = '1_1';\n      const page1Node = context.getAXNodeByUid(page1Uid);\n      assert.ok(page1Node, 'uid should resolve from page1 snapshot');\n\n      // Page 2: new page, set content, snapshot\n      const page2 = await context.newPage();\n      context.selectPage(page2);\n      await page2.pptrPage.setContent(html`<button>Page2 Button</button>`);\n      await context.createTextSnapshot(page2, false, undefined);\n\n      // Page 2 is now selected. Page 1's uid should still resolve.\n      const node = context.getAXNodeByUid(page1Uid);\n      assert.ok(node, 'page1 uid should still resolve after page2 snapshot');\n      assert.strictEqual(node?.name, 'Page1 Button');\n\n      // The element should also be retrievable when the target page is provided.\n      const element = await page1.getElementByUid(page1Uid);\n      assert.ok(element, 'should get element handle from page1 snapshot uid');\n    });\n  });\n\n  it('should include network requests in structured content', async t => {\n    await withMcpContext(async (response, context) => {\n      const mockRequest = getMockRequest({\n        url: 'http://example.com/api',\n        stableId: 123,\n      });\n\n      sinon.stub(context, 'getNetworkRequests').returns([mockRequest]);\n      sinon.stub(context, 'getNetworkRequestStableId').returns(123);\n\n      response.setIncludeNetworkRequests(true);\n      const result = await response.handle('test', context);\n\n      t.assert.snapshot?.(JSON.stringify(result.structuredContent, null, 2));\n    });\n  });\n\n  it('should include detailed network request in structured content', async t => {\n    await withMcpContext(async (response, context) => {\n      const mockRequest = getMockRequest({\n        url: 'http://example.com/detail',\n        stableId: 456,\n      });\n\n      sinon.stub(context, 'getNetworkRequestById').returns(mockRequest);\n      sinon.stub(context, 'getNetworkRequestStableId').returns(456);\n\n      response.attachNetworkRequest(456);\n      const result = await response.handle('test', context);\n\n      t.assert.snapshot?.(JSON.stringify(result.structuredContent, null, 2));\n    });\n  });\n\n  it('should include file paths in structured content when saving to file', async t => {\n    await withMcpContext(async (response, context) => {\n      const mockRequest = getMockRequest({\n        url: 'http://example.com/file-save',\n        stableId: 789,\n        hasPostData: true,\n        postData: 'some detailed data',\n        response: {\n          status: () => 200,\n          headers: () => ({'content-type': 'text/plain'}),\n          buffer: async () => Buffer.from('some response data'),\n        } as unknown as HTTPResponse,\n      });\n\n      sinon.stub(context, 'getNetworkRequestById').returns(mockRequest);\n      sinon.stub(context, 'getNetworkRequestStableId').returns(789);\n\n      // We stub NetworkFormatter.from to avoid actual file system writes and verify arguments\n      const fromStub = sinon\n        .stub(NetworkFormatter, 'from')\n        .callsFake(async (_req, opts) => {\n          // Verify we received the file paths\n          assert.strictEqual(opts?.requestFilePath, '/tmp/req.txt');\n          assert.strictEqual(opts?.responseFilePath, '/tmp/res.txt');\n          // Return a dummy formatter that behaves as if it saved files\n          // We need to create a real instance or mock one.\n          // Since constructor is private, we can't easily new it up.\n          // But we can return a mock object.\n          return {\n            toStringDetailed: () => 'Detailed string',\n            toJSONDetailed: () => ({\n              requestBody: '/tmp/req.txt',\n              responseBody: '/tmp/res.txt',\n            }),\n          } as unknown as NetworkFormatter;\n        });\n\n      response.attachNetworkRequest(789, {\n        requestFilePath: '/tmp/req.txt',\n        responseFilePath: '/tmp/res.txt',\n      });\n      const result = await response.handle('test', context);\n\n      t.assert.snapshot?.(JSON.stringify(result.structuredContent, null, 2));\n\n      fromStub.restore();\n    });\n  });\n});\n"
  },
  {
    "path": "tests/McpResponse.test.js.snapshot",
    "content": "exports[`McpResponse > add network request when attached 1`] = `\n## Request http://example.com\nStatus: pending\n### Request Headers\n- content-size:10\n## Network requests\nShowing 1-1 of 1 (Page 1 of 1).\nreqid=1 GET http://example.com [pending]\n`;\n\nexports[`McpResponse > add network request when attached 2`] = `\n{\n  \"networkRequest\": {\n    \"requestId\": 1,\n    \"method\": \"GET\",\n    \"url\": \"http://example.com\",\n    \"status\": \"pending\",\n    \"requestHeaders\": {\n      \"content-size\": \"10\"\n    }\n  },\n  \"pagination\": {\n    \"currentPage\": 0,\n    \"totalPages\": 1,\n    \"hasNextPage\": false,\n    \"hasPreviousPage\": false,\n    \"startIndex\": 0,\n    \"endIndex\": 1,\n    \"invalidPage\": false\n  },\n  \"networkRequests\": [\n    {\n      \"requestId\": 1,\n      \"method\": \"GET\",\n      \"url\": \"http://example.com\",\n      \"status\": \"pending\",\n      \"selectedInDevToolsUI\": false\n    }\n  ]\n}\n`;\n\nexports[`McpResponse > add network request when attached with POST data 1`] = `\n## Request http://example.com\nStatus: 200\n### Request Headers\n- content-size:10\n### Request Body\n{\"request\":\"body\"}\n### Response Headers\n- Content-Type:application/json\n### Response Body\n{\"response\":\"body\"}\n## Network requests\nShowing 1-1 of 1 (Page 1 of 1).\nreqid=1 POST http://example.com [200]\n`;\n\nexports[`McpResponse > add network request when attached with POST data 2`] = `\n{\n  \"networkRequest\": {\n    \"requestId\": 1,\n    \"method\": \"POST\",\n    \"url\": \"http://example.com\",\n    \"status\": \"200\",\n    \"requestHeaders\": {\n      \"content-size\": \"10\"\n    },\n    \"requestBody\": \"{\\\\\"request\\\\\":\\\\\"body\\\\\"}\",\n    \"responseHeaders\": {\n      \"Content-Type\": \"application/json\"\n    },\n    \"responseBody\": \"{\\\\\"response\\\\\":\\\\\"body\\\\\"}\"\n  },\n  \"pagination\": {\n    \"currentPage\": 0,\n    \"totalPages\": 1,\n    \"hasNextPage\": false,\n    \"hasPreviousPage\": false,\n    \"startIndex\": 0,\n    \"endIndex\": 1,\n    \"invalidPage\": false\n  },\n  \"networkRequests\": [\n    {\n      \"requestId\": 1,\n      \"method\": \"POST\",\n      \"url\": \"http://example.com\",\n      \"status\": \"200\",\n      \"selectedInDevToolsUI\": false\n    }\n  ]\n}\n`;\n\nexports[`McpResponse > add network requests when setting is true 1`] = `\n## Network requests\nShowing 1-2 of 2 (Page 1 of 1).\nreqid=1 GET http://example.com [pending]\nreqid=2 GET http://example.com [pending]\n`;\n\nexports[`McpResponse > add network requests when setting is true 2`] = `\n{\n  \"pagination\": {\n    \"currentPage\": 0,\n    \"totalPages\": 1,\n    \"hasNextPage\": false,\n    \"hasPreviousPage\": false,\n    \"startIndex\": 0,\n    \"endIndex\": 2,\n    \"invalidPage\": false\n  },\n  \"networkRequests\": [\n    {\n      \"requestId\": 1,\n      \"method\": \"GET\",\n      \"url\": \"http://example.com\",\n      \"status\": \"pending\",\n      \"selectedInDevToolsUI\": false\n    },\n    {\n      \"requestId\": 2,\n      \"method\": \"GET\",\n      \"url\": \"http://example.com\",\n      \"status\": \"pending\",\n      \"selectedInDevToolsUI\": false\n    }\n  ]\n}\n`;\n\nexports[`McpResponse > adds a message when no console messages exist 1`] = `\n## Console messages\n<no console messages found>\n`;\n\nexports[`McpResponse > adds a message when no console messages exist 2`] = `\n{}\n`;\n\nexports[`McpResponse > adds a prompt dialog 1`] = `\n# Open dialog\nprompt: message (default value: \"default\").\nCall handle_dialog to handle it before continuing.\n`;\n\nexports[`McpResponse > adds a prompt dialog 2`] = `\n{\n  \"dialog\": {\n    \"type\": \"prompt\",\n    \"message\": \"message\",\n    \"defaultValue\": \"default\"\n  }\n}\n`;\n\nexports[`McpResponse > adds an alert dialog 1`] = `\n# Open dialog\nalert: message.\nCall handle_dialog to handle it before continuing.\n`;\n\nexports[`McpResponse > adds an alert dialog 2`] = `\n{\n  \"dialog\": {\n    \"type\": \"alert\",\n    \"message\": \"message\",\n    \"defaultValue\": \"\"\n  }\n}\n`;\n\nexports[`McpResponse > adds color scheme emulation setting when it is set 1`] = `\nEmulating color scheme: dark\n`;\n\nexports[`McpResponse > adds color scheme emulation setting when it is set 2`] = `\n{\n  \"colorScheme\": \"dark\"\n}\n`;\n\nexports[`McpResponse > adds console messages when the setting is true 1`] = `\n## Console messages\nShowing 1-1 of 1 (Page 1 of 1).\nmsgid=1 [log] Hello from the test (1 args)\n`;\n\nexports[`McpResponse > adds console messages when the setting is true 2`] = `\n{\n  \"pagination\": {\n    \"currentPage\": 0,\n    \"totalPages\": 1,\n    \"hasNextPage\": false,\n    \"hasPreviousPage\": false,\n    \"startIndex\": 0,\n    \"endIndex\": 1,\n    \"invalidPage\": false\n  },\n  \"consoleMessages\": [\n    {\n      \"type\": \"log\",\n      \"text\": \"Hello from the test\",\n      \"argsCount\": 1,\n      \"id\": 1\n    }\n  ]\n}\n`;\n\nexports[`McpResponse > adds cpu throttling setting when it is over 1 1`] = `\nEmulating CPU throttling: 4x slowdown\n`;\n\nexports[`McpResponse > adds cpu throttling setting when it is over 1 2`] = `\n{\n  \"cpuThrottlingRate\": 4\n}\n`;\n\nexports[`McpResponse > adds image when image is attached 1`] = `\n\n`;\n\nexports[`McpResponse > adds image when image is attached 2`] = `\n{}\n`;\n\nexports[`McpResponse > adds throttling setting when it is not null 1`] = `\nEmulating network conditions: Slow 3G\nDefault navigation timeout set to 100000 ms\n`;\n\nexports[`McpResponse > adds throttling setting when it is not null 2`] = `\n{\n  \"networkConditions\": \"Slow 3G\",\n  \"navigationTimeout\": 100000\n}\n`;\n\nexports[`McpResponse > adds userAgent emulation setting when it is set 1`] = `\nEmulating user agent: MyUA\n`;\n\nexports[`McpResponse > adds userAgent emulation setting when it is set 2`] = `\n{\n  \"userAgent\": \"MyUA\"\n}\n`;\n\nexports[`McpResponse > adds viewport emulation setting when it is set 1`] = `\nEmulating viewport: {\"deviceScaleFactor\":1,\"isMobile\":false,\"hasTouch\":false,\"isLandscape\":false,\"width\":400,\"height\":400}\n`;\n\nexports[`McpResponse > adds viewport emulation setting when it is set 2`] = `\n{\n  \"viewport\": {\n    \"deviceScaleFactor\": 1,\n    \"isMobile\": false,\n    \"hasTouch\": false,\n    \"isLandscape\": false,\n    \"width\": 400,\n    \"height\": 400\n  }\n}\n`;\n\nexports[`McpResponse > allows response text lines to be added 1`] = `\nTesting 1\nTesting 2\n`;\n\nexports[`McpResponse > allows response text lines to be added 2`] = `\n{\n  \"message\": \"Testing 1\\\\nTesting 2\"\n}\n`;\n\nexports[`McpResponse > does not include anything in response if snapshot is null 1`] = `\n\n`;\n\nexports[`McpResponse > does not include anything in response if snapshot is null 2`] = `\n{}\n`;\n\nexports[`McpResponse > does not include cpu throttling setting when it is 1 1`] = `\n\n`;\n\nexports[`McpResponse > does not include cpu throttling setting when it is 1 2`] = `\n{}\n`;\n\nexports[`McpResponse > does not include network requests when setting is false 1`] = `\n\n`;\n\nexports[`McpResponse > does not include network requests when setting is false 2`] = `\n{}\n`;\n\nexports[`McpResponse > does not include throttling setting when it is null 1`] = `\n\n`;\n\nexports[`McpResponse > does not include throttling setting when it is null 2`] = `\n{}\n`;\n\nexports[`McpResponse > doesn't list the issue message if mapping returns null 1`] = `\n{}\n`;\n\nexports[`McpResponse > list pages 1`] = `\n## Pages\n1: about:blank [selected]\n`;\n\nexports[`McpResponse > list pages 2`] = `\n{\n  \"pages\": [\n    {\n      \"id\": 1,\n      \"url\": \"about:blank\",\n      \"selected\": true\n    }\n  ]\n}\n`;\n\nexports[`McpResponse > returns correctly formatted snapshot for a simple tree 1`] = `\n## Latest page snapshot\nuid=1_0 RootWebArea \"My test page\" url=\"about:blank\"\n  uid=1_1 button \"Click me\" focusable focused\n  uid=1_2 textbox value=\"Input\"\n\n`;\n\nexports[`McpResponse > returns correctly formatted snapshot for a simple tree 2`] = `\n{\n  \"snapshot\": {\n    \"id\": \"1_0\",\n    \"role\": \"RootWebArea\",\n    \"name\": \"My test page\",\n    \"url\": \"about:blank\",\n    \"children\": [\n      {\n        \"id\": \"1_1\",\n        \"role\": \"button\",\n        \"name\": \"Click me\",\n        \"focusable\": true,\n        \"focused\": true\n      },\n      {\n        \"id\": \"1_2\",\n        \"role\": \"textbox\",\n        \"value\": \"Input\"\n      }\n    ]\n  }\n}\n`;\n\nexports[`McpResponse > returns values for textboxes 1`] = `\n## Latest page snapshot\nuid=1_0 RootWebArea \"My test page\" url=\"about:blank\"\n  uid=1_1 StaticText \"username\"\n  uid=1_2 textbox \"username\" focusable focused value=\"mcp\"\n\n`;\n\nexports[`McpResponse > returns values for textboxes 2`] = `\n{\n  \"snapshot\": {\n    \"id\": \"1_0\",\n    \"role\": \"RootWebArea\",\n    \"name\": \"My test page\",\n    \"url\": \"about:blank\",\n    \"children\": [\n      {\n        \"id\": \"1_1\",\n        \"role\": \"StaticText\",\n        \"name\": \"username\"\n      },\n      {\n        \"id\": \"1_2\",\n        \"role\": \"textbox\",\n        \"name\": \"username\",\n        \"focusable\": true,\n        \"focused\": true,\n        \"value\": \"mcp\"\n      }\n    ]\n  }\n}\n`;\n\nexports[`McpResponse > returns verbose snapshot and structured content 1`] = `\n## Latest page snapshot\nuid=1_0 RootWebArea \"My test page\" url=\"about:blank\"\n  uid=1_1 ignored\n    uid=1_2 ignored\n      uid=1_3 complementary\n        uid=1_4 StaticText \"test\"\n          uid=1_5 InlineTextBox \"test\"\n\n`;\n\nexports[`McpResponse > returns verbose snapshot and structured content 2`] = `\n{\n  \"snapshot\": {\n    \"id\": \"1_0\",\n    \"role\": \"RootWebArea\",\n    \"name\": \"My test page\",\n    \"url\": \"about:blank\",\n    \"children\": [\n      {\n        \"id\": \"1_1\",\n        \"role\": \"none\",\n        \"children\": [\n          {\n            \"id\": \"1_2\",\n            \"role\": \"none\",\n            \"children\": [\n              {\n                \"id\": \"1_3\",\n                \"role\": \"complementary\",\n                \"children\": [\n                  {\n                    \"id\": \"1_4\",\n                    \"role\": \"StaticText\",\n                    \"name\": \"test\",\n                    \"children\": [\n                      {\n                        \"id\": \"1_5\",\n                        \"role\": \"InlineTextBox\",\n                        \"name\": \"test\"\n                      }\n                    ]\n                  }\n                ]\n              }\n            ]\n          }\n        ]\n      }\n    ]\n  }\n}\n`;\n\nexports[`McpResponse > saves snapshot to file and returns structured content 1`] = `\nSaved snapshot to <file>\n`;\n\nexports[`McpResponse > saves snapshot to file and returns structured content 2`] = `\n{\n  \"snapshotFilePath\": \"<file>\"\n}\n`;\n\nexports[`McpResponse > saves snapshot to file and returns structured content 3`] = `\nuid=1_0 RootWebArea \"My test page\" url=\"about:blank\"\n  uid=1_1 ignored\n    uid=1_2 ignored\n      uid=1_3 complementary\n        uid=1_4 StaticText \"test\"\n          uid=1_5 InlineTextBox \"test\"\n\n`;\n\nexports[`McpResponse network pagination > handles invalid page number by showing first page 1`] = `\n{\n  \"pagination\": {\n    \"currentPage\": 0,\n    \"totalPages\": 3,\n    \"hasNextPage\": true,\n    \"hasPreviousPage\": false,\n    \"startIndex\": 0,\n    \"endIndex\": 2,\n    \"invalidPage\": true\n  },\n  \"networkRequests\": [\n    {\n      \"requestId\": 1,\n      \"method\": \"GET\",\n      \"url\": \"http://example.com\",\n      \"status\": \"pending\",\n      \"selectedInDevToolsUI\": false\n    },\n    {\n      \"requestId\": 1,\n      \"method\": \"GET\",\n      \"url\": \"http://example.com\",\n      \"status\": \"pending\",\n      \"selectedInDevToolsUI\": false\n    }\n  ]\n}\n`;\n\nexports[`McpResponse network pagination > returns all requests when pagination is not provided 1`] = `\n{\n  \"pagination\": {\n    \"currentPage\": 0,\n    \"totalPages\": 1,\n    \"hasNextPage\": false,\n    \"hasPreviousPage\": false,\n    \"startIndex\": 0,\n    \"endIndex\": 5,\n    \"invalidPage\": false\n  },\n  \"networkRequests\": [\n    {\n      \"requestId\": 1,\n      \"method\": \"GET\",\n      \"url\": \"http://example.com\",\n      \"status\": \"pending\",\n      \"selectedInDevToolsUI\": false\n    },\n    {\n      \"requestId\": 1,\n      \"method\": \"GET\",\n      \"url\": \"http://example.com\",\n      \"status\": \"pending\",\n      \"selectedInDevToolsUI\": false\n    },\n    {\n      \"requestId\": 1,\n      \"method\": \"GET\",\n      \"url\": \"http://example.com\",\n      \"status\": \"pending\",\n      \"selectedInDevToolsUI\": false\n    },\n    {\n      \"requestId\": 1,\n      \"method\": \"GET\",\n      \"url\": \"http://example.com\",\n      \"status\": \"pending\",\n      \"selectedInDevToolsUI\": false\n    },\n    {\n      \"requestId\": 1,\n      \"method\": \"GET\",\n      \"url\": \"http://example.com\",\n      \"status\": \"pending\",\n      \"selectedInDevToolsUI\": false\n    }\n  ]\n}\n`;\n\nexports[`McpResponse network pagination > returns first page by default 1`] = `\n{\n  \"pagination\": {\n    \"currentPage\": 0,\n    \"totalPages\": 3,\n    \"hasNextPage\": true,\n    \"hasPreviousPage\": false,\n    \"startIndex\": 0,\n    \"endIndex\": 10,\n    \"invalidPage\": false\n  },\n  \"networkRequests\": [\n    {\n      \"requestId\": 1,\n      \"method\": \"GET-0\",\n      \"url\": \"http://example.com\",\n      \"status\": \"pending\",\n      \"selectedInDevToolsUI\": false\n    },\n    {\n      \"requestId\": 1,\n      \"method\": \"GET-1\",\n      \"url\": \"http://example.com\",\n      \"status\": \"pending\",\n      \"selectedInDevToolsUI\": false\n    },\n    {\n      \"requestId\": 1,\n      \"method\": \"GET-2\",\n      \"url\": \"http://example.com\",\n      \"status\": \"pending\",\n      \"selectedInDevToolsUI\": false\n    },\n    {\n      \"requestId\": 1,\n      \"method\": \"GET-3\",\n      \"url\": \"http://example.com\",\n      \"status\": \"pending\",\n      \"selectedInDevToolsUI\": false\n    },\n    {\n      \"requestId\": 1,\n      \"method\": \"GET-4\",\n      \"url\": \"http://example.com\",\n      \"status\": \"pending\",\n      \"selectedInDevToolsUI\": false\n    },\n    {\n      \"requestId\": 1,\n      \"method\": \"GET-5\",\n      \"url\": \"http://example.com\",\n      \"status\": \"pending\",\n      \"selectedInDevToolsUI\": false\n    },\n    {\n      \"requestId\": 1,\n      \"method\": \"GET-6\",\n      \"url\": \"http://example.com\",\n      \"status\": \"pending\",\n      \"selectedInDevToolsUI\": false\n    },\n    {\n      \"requestId\": 1,\n      \"method\": \"GET-7\",\n      \"url\": \"http://example.com\",\n      \"status\": \"pending\",\n      \"selectedInDevToolsUI\": false\n    },\n    {\n      \"requestId\": 1,\n      \"method\": \"GET-8\",\n      \"url\": \"http://example.com\",\n      \"status\": \"pending\",\n      \"selectedInDevToolsUI\": false\n    },\n    {\n      \"requestId\": 1,\n      \"method\": \"GET-9\",\n      \"url\": \"http://example.com\",\n      \"status\": \"pending\",\n      \"selectedInDevToolsUI\": false\n    }\n  ]\n}\n`;\n\nexports[`McpResponse network pagination > returns subsequent page when pageIdx provided 1`] = `\n{\n  \"pagination\": {\n    \"currentPage\": 1,\n    \"totalPages\": 3,\n    \"hasNextPage\": true,\n    \"hasPreviousPage\": true,\n    \"startIndex\": 10,\n    \"endIndex\": 20,\n    \"invalidPage\": false\n  },\n  \"networkRequests\": [\n    {\n      \"requestId\": 1,\n      \"method\": \"GET-10\",\n      \"url\": \"http://example.com\",\n      \"status\": \"pending\",\n      \"selectedInDevToolsUI\": false\n    },\n    {\n      \"requestId\": 1,\n      \"method\": \"GET-11\",\n      \"url\": \"http://example.com\",\n      \"status\": \"pending\",\n      \"selectedInDevToolsUI\": false\n    },\n    {\n      \"requestId\": 1,\n      \"method\": \"GET-12\",\n      \"url\": \"http://example.com\",\n      \"status\": \"pending\",\n      \"selectedInDevToolsUI\": false\n    },\n    {\n      \"requestId\": 1,\n      \"method\": \"GET-13\",\n      \"url\": \"http://example.com\",\n      \"status\": \"pending\",\n      \"selectedInDevToolsUI\": false\n    },\n    {\n      \"requestId\": 1,\n      \"method\": \"GET-14\",\n      \"url\": \"http://example.com\",\n      \"status\": \"pending\",\n      \"selectedInDevToolsUI\": false\n    },\n    {\n      \"requestId\": 1,\n      \"method\": \"GET-15\",\n      \"url\": \"http://example.com\",\n      \"status\": \"pending\",\n      \"selectedInDevToolsUI\": false\n    },\n    {\n      \"requestId\": 1,\n      \"method\": \"GET-16\",\n      \"url\": \"http://example.com\",\n      \"status\": \"pending\",\n      \"selectedInDevToolsUI\": false\n    },\n    {\n      \"requestId\": 1,\n      \"method\": \"GET-17\",\n      \"url\": \"http://example.com\",\n      \"status\": \"pending\",\n      \"selectedInDevToolsUI\": false\n    },\n    {\n      \"requestId\": 1,\n      \"method\": \"GET-18\",\n      \"url\": \"http://example.com\",\n      \"status\": \"pending\",\n      \"selectedInDevToolsUI\": false\n    },\n    {\n      \"requestId\": 1,\n      \"method\": \"GET-19\",\n      \"url\": \"http://example.com\",\n      \"status\": \"pending\",\n      \"selectedInDevToolsUI\": false\n    }\n  ]\n}\n`;\n\nexports[`McpResponse network pagination > trace insights > includes error if insight not found 1`] = `\nNo Performance Insights for the given insight set id. Only use ids given in the \"Available insight sets\" list.\n`;\n\nexports[`McpResponse network pagination > trace insights > includes error if insight not found 2`] = `\n{}\n`;\n\nexports[`McpResponse network pagination > trace insights > includes the trace insight output 1`] = `\n## Insight Title: LCP breakdown\n\n## Insight Summary:\nThis insight is used to analyze the time spent that contributed to the final LCP time and identify which of the 4 phases (or 2 if there was no LCP resource) are contributing most to the delay in rendering the LCP element.\n\n## Detailed analysis:\nThe Largest Contentful Paint (LCP) time for this navigation was 129 ms.\nThe LCP element is an image fetched from https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/4i7JstVZvgTFk9dxCe4a.svg (eventKey: s-1314, ts: 122411037986).\n## LCP resource network request: https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/4i7JstVZvgTFk9dxCe4a.svg\neventKey: s-1314\nTimings:\n- Queued at: 41 ms\n- Request sent at: 47 ms\n- Download complete at: 56 ms\n- Main thread processing completed at: 58 ms\nDurations:\n- Download time: 0.3 ms\n- Main thread processing time: 2 ms\n- Total duration: 17 ms\nRedirects: no redirects\nStatus code: 200\nMIME Type: image/svg+xml\nProtocol: unknown\nPriority: VeryHigh\nRender-blocking: No\nFrom a service worker: No\nInitiators (root request to the request that directly loaded this one): none\n\n\nWe can break this time down into the 4 phases that combine to make the LCP time:\n\n- Time to first byte: 8 ms (6.1% of total LCP time)\n- Resource load delay: 33 ms (25.7% of total LCP time)\n- Resource load duration: 15 ms (11.4% of total LCP time)\n- Element render delay: 73 ms (56.8% of total LCP time)\n\n## Estimated savings: none\n\n## External resources:\n- https://developer.chrome.com/docs/performance/insights/lcp-breakdown\n- https://web.dev/articles/lcp\n- https://web.dev/articles/optimize-lcp\n`;\n\nexports[`McpResponse network pagination > trace insights > includes the trace insight output 2`] = `\n{}\n`;\n\nexports[`McpResponse network pagination > trace summaries > includes the trace summary text and structured data 1`] = `\n## Summary of Performance trace findings:\nURL: https://web.dev/\nTrace bounds: {min: 122410994891, max: 122416385853}\nCPU throttling: none\nNetwork throttling: none\n\n# Available insight sets\n\nThe following is a list of insight sets. An insight set covers a specific part of the trace, split by navigations. The insights within each insight set are specific to that part of the trace. Be sure to consider the insight set id and bounds when calling functions. If no specific insight set or navigation is mentioned, assume the user is referring to the first one.\n\n## insight set id: NAVIGATION_0\n\nURL: https://web.dev/\nBounds: {min: 122410996889, max: 122416385853}\nMetrics (lab / observed):\n  - LCP: 129 ms, event: (eventKey: r-6063, ts: 122411126100), nodeId: 7\n  - LCP breakdown:\n    - TTFB: 8 ms, bounds: {min: 122410996889, max: 122411004828}\n    - Load delay: 33 ms, bounds: {min: 122411004828, max: 122411037986}\n    - Load duration: 15 ms, bounds: {min: 122411037986, max: 122411052690}\n    - Render delay: 73 ms, bounds: {min: 122411052690, max: 122411126100}\n  - CLS: 0.00\nMetrics (field / real users): n/a – no data for this page in CrUX\nAvailable insights:\n  - insight name: LCPBreakdown\n    description: Each [subpart has specific improvement strategies](https://developer.chrome.com/docs/performance/insights/lcp-breakdown). Ideally, most of the LCP time should be spent on loading the resources, not within delays.\n    relevant trace bounds: {min: 122410996889, max: 122411126100}\n    example question: Help me optimize my LCP score\n    example question: Which LCP phase was most problematic?\n    example question: What can I do to reduce the LCP time for this page load?\n  - insight name: LCPDiscovery\n    description: [Optimize LCP](https://developer.chrome.com/docs/performance/insights/lcp-discovery) by making the LCP image discoverable from the HTML immediately, and avoiding lazy-loading\n    relevant trace bounds: {min: 122411004828, max: 122411055039}\n    example question: Suggest fixes to reduce my LCP\n    example question: What can I do to reduce my LCP discovery time?\n    example question: Why is LCP discovery time important?\n  - insight name: RenderBlocking\n    description: Requests are blocking the page's initial render, which may delay LCP. [Deferring or inlining](https://developer.chrome.com/docs/performance/insights/render-blocking) can move these network requests out of the critical path.\n    relevant trace bounds: {min: 122411037528, max: 122411053852}\n    example question: Show me the most impactful render-blocking requests that I should focus on\n    example question: How can I reduce the number of render-blocking requests?\n  - insight name: DocumentLatency\n    description: Your first network request is the most important. [Reduce its latency](https://developer.chrome.com/docs/performance/insights/document-latency) by avoiding redirects, ensuring a fast server response, and enabling text compression.\n    relevant trace bounds: {min: 122410998910, max: 122411043781}\n    estimated metric savings: FCP 0 ms, LCP 0 ms\n    estimated wasted bytes: 77.1 kB\n    example question: How do I decrease the initial loading time of my page?\n    example question: Did anything slow down the request for this document?\n  - insight name: ThirdParties\n    description: 3rd party code can significantly impact load performance. [Reduce and defer loading of 3rd party code](https://developer.chrome.com/docs/performance/insights/third-parties) to prioritize your page's content.\n    relevant trace bounds: {min: 122411037881, max: 122416229595}\n    example question: Which third parties are having the largest impact on my page performance?\n  - insight name: CharacterSet\n    description: A character encoding declaration is required. It can be done with a meta charset tag in the first 1024 bytes of the HTML or in the Content-Type HTTP response header. [Learn more about declaring the character encoding](https://developer.chrome.com/docs/insights/charset/).\n    relevant trace bounds: {min: 122410998910, max: 122411043781}\n    example question: How do I declare a character encoding for my page?\n\n## Details on call tree & network request formats:\nInformation on performance traces may contain main thread activity represented as call frames and network requests.\n\nEach call frame is presented in the following format:\n\n'id;eventKey;name;duration;selfTime;urlIndex;childRange;[line];[column];[S]'\n\nKey definitions:\n\n* id: A unique numerical identifier for the call frame. Never mention this id in the output to the user.\n* eventKey: String that uniquely identifies this event in the flame chart.\n* name: A concise string describing the call frame (e.g., 'Evaluate Script', 'render', 'fetchData').\n* duration: The total execution time of the call frame, including its children.\n* selfTime: The time spent directly within the call frame, excluding its children's execution.\n* urlIndex: Index referencing the \"All URLs\" list. Empty if no specific script URL is associated.\n* childRange: Specifies the direct children of this node using their IDs. If empty ('' or 'S' at the end), the node has no children. If a single number (e.g., '4'), the node has one child with that ID. If in the format 'firstId-lastId' (e.g., '4-5'), it indicates a consecutive range of child IDs from 'firstId' to 'lastId', inclusive.\n* line: An optional field for a call frame's line number. This is where the function is defined.\n* column: An optional field for a call frame's column number. This is where the function is defined.\n* S: _Optional_. The letter 'S' terminates the line if that call frame was selected by the user.\n\nExample Call Tree:\n\n1;r-123;main;500;100;0;1;;\n2;r-124;update;200;50;;3;0;1;\n3;p-49575-15428179-2834-374;animate;150;20;0;4-5;0;1;S\n4;p-49575-15428179-3505-1162;calculatePosition;80;80;0;1;;\n5;p-49575-15428179-5391-2767;applyStyles;50;50;0;1;;\n\n\nNetwork requests are formatted like this:\n\\`urlIndex;eventKey;queuedTime;requestSentTime;downloadCompleteTime;processingCompleteTime;totalDuration;downloadDuration;mainThreadProcessingDuration;statusCode;mimeType;priority;initialPriority;finalPriority;renderBlocking;protocol;fromServiceWorker;initiators;redirects:[[redirectUrlIndex|startTime|duration]];responseHeaders:[header1Value|header2Value|...]\\`\n\n- \\`urlIndex\\`: Numerical index for the request's URL, referencing the \"All URLs\" list.\n- \\`eventKey\\`: String that uniquely identifies this request's trace event.\nTimings (all in milliseconds, relative to navigation start):\n- \\`queuedTime\\`: When the request was queued.\n- \\`requestSentTime\\`: When the request was sent.\n- \\`downloadCompleteTime\\`: When the download completed.\n- \\`processingCompleteTime\\`: When main thread processing finished.\nDurations (all in milliseconds):\n- \\`totalDuration\\`: Total time from the request being queued until its main thread processing completed.\n- \\`downloadDuration\\`: Time spent actively downloading the resource.\n- \\`mainThreadProcessingDuration\\`: Time spent on the main thread after the download completed.\n- \\`statusCode\\`: The HTTP status code of the response (e.g., 200, 404).\n- \\`mimeType\\`: The MIME type of the resource (e.g., \"text/html\", \"application/javascript\").\n- \\`priority\\`: The final network request priority (e.g., \"VeryHigh\", \"Low\").\n- \\`initialPriority\\`: The initial network request priority.\n- \\`finalPriority\\`: The final network request priority (redundant if \\`priority\\` is always final, but kept for clarity if \\`initialPriority\\` and \\`priority\\` differ).\n- \\`renderBlocking\\`: 't' if the request was render-blocking, 'f' otherwise.\n- \\`protocol\\`: The network protocol used (e.g., \"h2\", \"http/1.1\").\n- \\`fromServiceWorker\\`: 't' if the request was served from a service worker, 'f' otherwise.\n- \\`initiators\\`: A list (separated by ,) of URL indices for the initiator chain of this request. Listed in order starting from the root request to the request that directly loaded this one. This represents the network dependencies necessary to load this request. If there is no initiator, this is empty.\n- \\`redirects\\`: A comma-separated list of redirects, enclosed in square brackets. Each redirect is formatted as\n\\`[redirectUrlIndex|startTime|duration]\\`, where: \\`redirectUrlIndex\\`: Numerical index for the redirect's URL. \\`startTime\\`: The start time of the redirect in milliseconds, relative to navigation start. \\`duration\\`: The duration of the redirect in milliseconds.\n- \\`responseHeaders\\`: A list (separated by '|') of values for specific, pre-defined response headers, enclosed in square brackets.\nThe order of headers corresponds to an internal fixed list. If a header is not present, its value will be empty.\n\n`;\n\nexports[`McpResponse network pagination > trace summaries > includes the trace summary text and structured data 2`] = `\n\"## Summary of Performance trace findings:\\\\nURL: https://web.dev/\\\\nTrace bounds: {min: 122410994891, max: 122416385853}\\\\nCPU throttling: none\\\\nNetwork throttling: none\\\\n\\\\n# Available insight sets\\\\n\\\\nThe following is a list of insight sets. An insight set covers a specific part of the trace, split by navigations. The insights within each insight set are specific to that part of the trace. Be sure to consider the insight set id and bounds when calling functions. If no specific insight set or navigation is mentioned, assume the user is referring to the first one.\\\\n\\\\n## insight set id: NAVIGATION_0\\\\n\\\\nURL: https://web.dev/\\\\nBounds: {min: 122410996889, max: 122416385853}\\\\nMetrics (lab / observed):\\\\n  - LCP: 129 ms, event: (eventKey: r-6063, ts: 122411126100), nodeId: 7\\\\n  - LCP breakdown:\\\\n    - TTFB: 8 ms, bounds: {min: 122410996889, max: 122411004828}\\\\n    - Load delay: 33 ms, bounds: {min: 122411004828, max: 122411037986}\\\\n    - Load duration: 15 ms, bounds: {min: 122411037986, max: 122411052690}\\\\n    - Render delay: 73 ms, bounds: {min: 122411052690, max: 122411126100}\\\\n  - CLS: 0.00\\\\nMetrics (field / real users): n/a – no data for this page in CrUX\\\\nAvailable insights:\\\\n  - insight name: LCPBreakdown\\\\n    description: Each [subpart has specific improvement strategies](https://developer.chrome.com/docs/performance/insights/lcp-breakdown). Ideally, most of the LCP time should be spent on loading the resources, not within delays.\\\\n    relevant trace bounds: {min: 122410996889, max: 122411126100}\\\\n    example question: Help me optimize my LCP score\\\\n    example question: Which LCP phase was most problematic?\\\\n    example question: What can I do to reduce the LCP time for this page load?\\\\n  - insight name: LCPDiscovery\\\\n    description: [Optimize LCP](https://developer.chrome.com/docs/performance/insights/lcp-discovery) by making the LCP image discoverable from the HTML immediately, and avoiding lazy-loading\\\\n    relevant trace bounds: {min: 122411004828, max: 122411055039}\\\\n    example question: Suggest fixes to reduce my LCP\\\\n    example question: What can I do to reduce my LCP discovery time?\\\\n    example question: Why is LCP discovery time important?\\\\n  - insight name: RenderBlocking\\\\n    description: Requests are blocking the page's initial render, which may delay LCP. [Deferring or inlining](https://developer.chrome.com/docs/performance/insights/render-blocking) can move these network requests out of the critical path.\\\\n    relevant trace bounds: {min: 122411037528, max: 122411053852}\\\\n    example question: Show me the most impactful render-blocking requests that I should focus on\\\\n    example question: How can I reduce the number of render-blocking requests?\\\\n  - insight name: DocumentLatency\\\\n    description: Your first network request is the most important. [Reduce its latency](https://developer.chrome.com/docs/performance/insights/document-latency) by avoiding redirects, ensuring a fast server response, and enabling text compression.\\\\n    relevant trace bounds: {min: 122410998910, max: 122411043781}\\\\n    estimated metric savings: FCP 0 ms, LCP 0 ms\\\\n    estimated wasted bytes: 77.1 kB\\\\n    example question: How do I decrease the initial loading time of my page?\\\\n    example question: Did anything slow down the request for this document?\\\\n  - insight name: ThirdParties\\\\n    description: 3rd party code can significantly impact load performance. [Reduce and defer loading of 3rd party code](https://developer.chrome.com/docs/performance/insights/third-parties) to prioritize your page's content.\\\\n    relevant trace bounds: {min: 122411037881, max: 122416229595}\\\\n    example question: Which third parties are having the largest impact on my page performance?\\\\n  - insight name: CharacterSet\\\\n    description: A character encoding declaration is required. It can be done with a meta charset tag in the first 1024 bytes of the HTML or in the Content-Type HTTP response header. [Learn more about declaring the character encoding](https://developer.chrome.com/docs/insights/charset/).\\\\n    relevant trace bounds: {min: 122410998910, max: 122411043781}\\\\n    example question: How do I declare a character encoding for my page?\\\\n\\\\n## Details on call tree & network request formats:\\\\nInformation on performance traces may contain main thread activity represented as call frames and network requests.\\\\n\\\\nEach call frame is presented in the following format:\\\\n\\\\n'id;eventKey;name;duration;selfTime;urlIndex;childRange;[line];[column];[S]'\\\\n\\\\nKey definitions:\\\\n\\\\n* id: A unique numerical identifier for the call frame. Never mention this id in the output to the user.\\\\n* eventKey: String that uniquely identifies this event in the flame chart.\\\\n* name: A concise string describing the call frame (e.g., 'Evaluate Script', 'render', 'fetchData').\\\\n* duration: The total execution time of the call frame, including its children.\\\\n* selfTime: The time spent directly within the call frame, excluding its children's execution.\\\\n* urlIndex: Index referencing the \\\\\"All URLs\\\\\" list. Empty if no specific script URL is associated.\\\\n* childRange: Specifies the direct children of this node using their IDs. If empty ('' or 'S' at the end), the node has no children. If a single number (e.g., '4'), the node has one child with that ID. If in the format 'firstId-lastId' (e.g., '4-5'), it indicates a consecutive range of child IDs from 'firstId' to 'lastId', inclusive.\\\\n* line: An optional field for a call frame's line number. This is where the function is defined.\\\\n* column: An optional field for a call frame's column number. This is where the function is defined.\\\\n* S: _Optional_. The letter 'S' terminates the line if that call frame was selected by the user.\\\\n\\\\nExample Call Tree:\\\\n\\\\n1;r-123;main;500;100;0;1;;\\\\n2;r-124;update;200;50;;3;0;1;\\\\n3;p-49575-15428179-2834-374;animate;150;20;0;4-5;0;1;S\\\\n4;p-49575-15428179-3505-1162;calculatePosition;80;80;0;1;;\\\\n5;p-49575-15428179-5391-2767;applyStyles;50;50;0;1;;\\\\n\\\\n\\\\nNetwork requests are formatted like this:\\\\n\\`urlIndex;eventKey;queuedTime;requestSentTime;downloadCompleteTime;processingCompleteTime;totalDuration;downloadDuration;mainThreadProcessingDuration;statusCode;mimeType;priority;initialPriority;finalPriority;renderBlocking;protocol;fromServiceWorker;initiators;redirects:[[redirectUrlIndex|startTime|duration]];responseHeaders:[header1Value|header2Value|...]\\`\\\\n\\\\n- \\`urlIndex\\`: Numerical index for the request's URL, referencing the \\\\\"All URLs\\\\\" list.\\\\n- \\`eventKey\\`: String that uniquely identifies this request's trace event.\\\\nTimings (all in milliseconds, relative to navigation start):\\\\n- \\`queuedTime\\`: When the request was queued.\\\\n- \\`requestSentTime\\`: When the request was sent.\\\\n- \\`downloadCompleteTime\\`: When the download completed.\\\\n- \\`processingCompleteTime\\`: When main thread processing finished.\\\\nDurations (all in milliseconds):\\\\n- \\`totalDuration\\`: Total time from the request being queued until its main thread processing completed.\\\\n- \\`downloadDuration\\`: Time spent actively downloading the resource.\\\\n- \\`mainThreadProcessingDuration\\`: Time spent on the main thread after the download completed.\\\\n- \\`statusCode\\`: The HTTP status code of the response (e.g., 200, 404).\\\\n- \\`mimeType\\`: The MIME type of the resource (e.g., \\\\\"text/html\\\\\", \\\\\"application/javascript\\\\\").\\\\n- \\`priority\\`: The final network request priority (e.g., \\\\\"VeryHigh\\\\\", \\\\\"Low\\\\\").\\\\n- \\`initialPriority\\`: The initial network request priority.\\\\n- \\`finalPriority\\`: The final network request priority (redundant if \\`priority\\` is always final, but kept for clarity if \\`initialPriority\\` and \\`priority\\` differ).\\\\n- \\`renderBlocking\\`: 't' if the request was render-blocking, 'f' otherwise.\\\\n- \\`protocol\\`: The network protocol used (e.g., \\\\\"h2\\\\\", \\\\\"http/1.1\\\\\").\\\\n- \\`fromServiceWorker\\`: 't' if the request was served from a service worker, 'f' otherwise.\\\\n- \\`initiators\\`: A list (separated by ,) of URL indices for the initiator chain of this request. Listed in order starting from the root request to the request that directly loaded this one. This represents the network dependencies necessary to load this request. If there is no initiator, this is empty.\\\\n- \\`redirects\\`: A comma-separated list of redirects, enclosed in square brackets. Each redirect is formatted as\\\\n\\`[redirectUrlIndex|startTime|duration]\\`, where: \\`redirectUrlIndex\\`: Numerical index for the redirect's URL. \\`startTime\\`: The start time of the redirect in milliseconds, relative to navigation start. \\`duration\\`: The duration of the redirect in milliseconds.\\\\n- \\`responseHeaders\\`: A list (separated by '|') of values for specific, pre-defined response headers, enclosed in square brackets.\\\\nThe order of headers corresponds to an internal fixed list. If a header is not present, its value will be empty.\\\\n\"\n`;\n\nexports[`McpResponse network pagination > trace summaries > includes the trace summary text and structured data 3`] = `\n[\n  {\n    \"insightName\": \"INPBreakdown\",\n    \"insightKey\": \"INPBreakdown\"\n  },\n  {\n    \"insightName\": \"LCPBreakdown\",\n    \"insightKey\": \"LCPBreakdown\"\n  },\n  {\n    \"insightName\": \"LCPDiscovery\",\n    \"insightKey\": \"LCPDiscovery\"\n  },\n  {\n    \"insightName\": \"CLSCulprits\",\n    \"insightKey\": \"CLSCulprits\"\n  },\n  {\n    \"insightName\": \"RenderBlocking\",\n    \"insightKey\": \"RenderBlocking\"\n  },\n  {\n    \"insightName\": \"NetworkDependencyTree\",\n    \"insightKey\": \"NetworkDependencyTree\"\n  },\n  {\n    \"insightName\": \"ImageDelivery\",\n    \"insightKey\": \"ImageDelivery\"\n  },\n  {\n    \"insightName\": \"DocumentLatency\",\n    \"insightKey\": \"DocumentLatency\"\n  },\n  {\n    \"insightName\": \"FontDisplay\",\n    \"insightKey\": \"FontDisplay\"\n  },\n  {\n    \"insightName\": \"Viewport\",\n    \"insightKey\": \"Viewport\"\n  },\n  {\n    \"insightName\": \"DOMSize\",\n    \"insightKey\": \"DOMSize\"\n  },\n  {\n    \"insightName\": \"ThirdParties\",\n    \"insightKey\": \"ThirdParties\"\n  },\n  {\n    \"insightName\": \"DuplicatedJavaScript\",\n    \"insightKey\": \"DuplicatedJavaScript\"\n  },\n  {\n    \"insightName\": \"SlowCSSSelector\",\n    \"insightKey\": \"SlowCSSSelector\"\n  },\n  {\n    \"insightName\": \"ForcedReflow\",\n    \"insightKey\": \"ForcedReflow\"\n  },\n  {\n    \"insightName\": \"Cache\",\n    \"insightKey\": \"Cache\"\n  },\n  {\n    \"insightName\": \"CharacterSet\",\n    \"insightKey\": \"CharacterSet\"\n  },\n  {\n    \"insightName\": \"ModernHTTP\",\n    \"insightKey\": \"ModernHTTP\"\n  },\n  {\n    \"insightName\": \"LegacyJavaScript\",\n    \"insightKey\": \"LegacyJavaScript\"\n  }\n]\n`;\n\nexports[`McpResponse network request filtering > filters network requests by resource type 1`] = `\n## Network requests\nShowing 1-2 of 2 (Page 1 of 1).\nreqid=1 GET http://example.com [pending]\nreqid=1 GET http://example.com [pending]\n`;\n\nexports[`McpResponse network request filtering > filters network requests by resource type 2`] = `\n{\n  \"pagination\": {\n    \"currentPage\": 0,\n    \"totalPages\": 1,\n    \"hasNextPage\": false,\n    \"hasPreviousPage\": false,\n    \"startIndex\": 0,\n    \"endIndex\": 2,\n    \"invalidPage\": false\n  },\n  \"networkRequests\": [\n    {\n      \"requestId\": 1,\n      \"method\": \"GET\",\n      \"url\": \"http://example.com\",\n      \"status\": \"pending\",\n      \"selectedInDevToolsUI\": false\n    },\n    {\n      \"requestId\": 1,\n      \"method\": \"GET\",\n      \"url\": \"http://example.com\",\n      \"status\": \"pending\",\n      \"selectedInDevToolsUI\": false\n    }\n  ]\n}\n`;\n\nexports[`McpResponse network request filtering > filters network requests by single resource type 1`] = `\n## Network requests\nShowing 1-1 of 1 (Page 1 of 1).\nreqid=1 GET http://example.com [pending]\n`;\n\nexports[`McpResponse network request filtering > filters network requests by single resource type 2`] = `\n{\n  \"pagination\": {\n    \"currentPage\": 0,\n    \"totalPages\": 1,\n    \"hasNextPage\": false,\n    \"hasPreviousPage\": false,\n    \"startIndex\": 0,\n    \"endIndex\": 1,\n    \"invalidPage\": false\n  },\n  \"networkRequests\": [\n    {\n      \"requestId\": 1,\n      \"method\": \"GET\",\n      \"url\": \"http://example.com\",\n      \"status\": \"pending\",\n      \"selectedInDevToolsUI\": false\n    }\n  ]\n}\n`;\n\nexports[`McpResponse network request filtering > shows all requests when empty resourceTypes array is provided 1`] = `\n## Network requests\nShowing 1-5 of 5 (Page 1 of 1).\nreqid=1 GET http://example.com [pending]\nreqid=1 GET http://example.com [pending]\nreqid=1 GET http://example.com [pending]\nreqid=1 GET http://example.com [pending]\nreqid=1 GET http://example.com [pending]\n`;\n\nexports[`McpResponse network request filtering > shows all requests when empty resourceTypes array is provided 2`] = `\n{\n  \"pagination\": {\n    \"currentPage\": 0,\n    \"totalPages\": 1,\n    \"hasNextPage\": false,\n    \"hasPreviousPage\": false,\n    \"startIndex\": 0,\n    \"endIndex\": 5,\n    \"invalidPage\": false\n  },\n  \"networkRequests\": [\n    {\n      \"requestId\": 1,\n      \"method\": \"GET\",\n      \"url\": \"http://example.com\",\n      \"status\": \"pending\",\n      \"selectedInDevToolsUI\": false\n    },\n    {\n      \"requestId\": 1,\n      \"method\": \"GET\",\n      \"url\": \"http://example.com\",\n      \"status\": \"pending\",\n      \"selectedInDevToolsUI\": false\n    },\n    {\n      \"requestId\": 1,\n      \"method\": \"GET\",\n      \"url\": \"http://example.com\",\n      \"status\": \"pending\",\n      \"selectedInDevToolsUI\": false\n    },\n    {\n      \"requestId\": 1,\n      \"method\": \"GET\",\n      \"url\": \"http://example.com\",\n      \"status\": \"pending\",\n      \"selectedInDevToolsUI\": false\n    },\n    {\n      \"requestId\": 1,\n      \"method\": \"GET\",\n      \"url\": \"http://example.com\",\n      \"status\": \"pending\",\n      \"selectedInDevToolsUI\": false\n    }\n  ]\n}\n`;\n\nexports[`McpResponse network request filtering > shows all requests when no filters are provided 1`] = `\n## Network requests\nShowing 1-5 of 5 (Page 1 of 1).\nreqid=1 GET http://example.com [pending]\nreqid=1 GET http://example.com [pending]\nreqid=1 GET http://example.com [pending]\nreqid=1 GET http://example.com [pending]\nreqid=1 GET http://example.com [pending]\n`;\n\nexports[`McpResponse network request filtering > shows all requests when no filters are provided 2`] = `\n{\n  \"pagination\": {\n    \"currentPage\": 0,\n    \"totalPages\": 1,\n    \"hasNextPage\": false,\n    \"hasPreviousPage\": false,\n    \"startIndex\": 0,\n    \"endIndex\": 5,\n    \"invalidPage\": false\n  },\n  \"networkRequests\": [\n    {\n      \"requestId\": 1,\n      \"method\": \"GET\",\n      \"url\": \"http://example.com\",\n      \"status\": \"pending\",\n      \"selectedInDevToolsUI\": false\n    },\n    {\n      \"requestId\": 1,\n      \"method\": \"GET\",\n      \"url\": \"http://example.com\",\n      \"status\": \"pending\",\n      \"selectedInDevToolsUI\": false\n    },\n    {\n      \"requestId\": 1,\n      \"method\": \"GET\",\n      \"url\": \"http://example.com\",\n      \"status\": \"pending\",\n      \"selectedInDevToolsUI\": false\n    },\n    {\n      \"requestId\": 1,\n      \"method\": \"GET\",\n      \"url\": \"http://example.com\",\n      \"status\": \"pending\",\n      \"selectedInDevToolsUI\": false\n    },\n    {\n      \"requestId\": 1,\n      \"method\": \"GET\",\n      \"url\": \"http://example.com\",\n      \"status\": \"pending\",\n      \"selectedInDevToolsUI\": false\n    }\n  ]\n}\n`;\n\nexports[`McpResponse network request filtering > shows no requests when filter matches nothing 1`] = `\n\n`;\n\nexports[`McpResponse network request filtering > shows no requests when filter matches nothing 2`] = `\n{}\n`;\n\nexports[`extensions > lists extensions 1`] = `\n## Extensions\nid=id1 \"Extension 1\" v1.0 Enabled\nid=id2 \"Extension 2\" v2.0 Disabled\n`;\n\nexports[`extensions > lists extensions 2`] = `\n{\n  \"extensions\": [\n    {\n      \"id\": \"id1\",\n      \"name\": \"Extension 1\",\n      \"version\": \"1.0\",\n      \"isEnabled\": true,\n      \"path\": \"/path/to/ext1\"\n    },\n    {\n      \"id\": \"id2\",\n      \"name\": \"Extension 2\",\n      \"version\": \"2.0\",\n      \"isEnabled\": false,\n      \"path\": \"/path/to/ext2\"\n    }\n  ]\n}\n`;\n\nexports[`lighthouse > includes lighthouse report paths 1`] = `\n## Lighthouse Audit Results\nMode: navigation\nDevice: desktop\nURL: https://example.com\n### Category Scores\n- Performance: 90 (performance)\n### Audit Summary\nPassed: 10\nFailed: 1\nTotal Timing: 1000ms\n### Reports\n- /tmp/report.json\n- /tmp/report.html\n`;\n\nexports[`lighthouse > includes lighthouse report paths 2`] = `\n{\n  \"lighthouseResult\": {\n    \"summary\": {\n      \"mode\": \"navigation\",\n      \"device\": \"desktop\",\n      \"url\": \"https://example.com\",\n      \"scores\": [\n        {\n          \"id\": \"performance\",\n          \"title\": \"Performance\",\n          \"score\": 0.9\n        }\n      ],\n      \"audits\": {\n        \"failed\": 1,\n        \"passed\": 10\n      },\n      \"timing\": {\n        \"total\": 1000\n      }\n    },\n    \"reports\": [\n      \"/tmp/report.json\",\n      \"/tmp/report.html\"\n    ]\n  }\n}\n`;\n"
  },
  {
    "path": "tests/McpResponse.test.ts",
    "content": "/**\n * @license\n * Copyright 2025 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport assert from 'node:assert';\nimport {readFile, rm} from 'node:fs/promises';\nimport {tmpdir} from 'node:os';\nimport {join} from 'node:path';\nimport {describe, it} from 'node:test';\n\nimport type {InsightName} from '../src/trace-processing/parse.js';\nimport {\n  parseRawTraceBuffer,\n  traceResultIsSuccess,\n} from '../src/trace-processing/parse.js';\n\nimport {serverHooks} from './server.js';\nimport {loadTraceAsBuffer} from './trace-processing/fixtures/load.js';\nimport {\n  getImageContent,\n  getMockAggregatedIssue,\n  getMockRequest,\n  getMockResponse,\n  getTextContent,\n  html,\n  stabilizeResponseOutput,\n  stabilizeStructuredContent,\n  withMcpContext,\n} from './utils.js';\n\ndescribe('McpResponse', () => {\n  it('list pages', async t => {\n    await withMcpContext(async (response, context) => {\n      response.setIncludePages(true);\n      const {content, structuredContent} = await response.handle(\n        'test',\n        context,\n      );\n      assert.equal(content[0].type, 'text');\n      t.assert.snapshot?.(getTextContent(content[0]));\n      t.assert.snapshot?.(\n        JSON.stringify(stabilizeStructuredContent(structuredContent), null, 2),\n      );\n    });\n  });\n\n  it('allows response text lines to be added', async t => {\n    await withMcpContext(async (response, context) => {\n      response.appendResponseLine('Testing 1');\n      response.appendResponseLine('Testing 2');\n      const {content, structuredContent} = await response.handle(\n        'test',\n        context,\n      );\n      assert.equal(content[0].type, 'text');\n      t.assert.snapshot?.(getTextContent(content[0]));\n      t.assert.snapshot?.(\n        JSON.stringify(stabilizeStructuredContent(structuredContent), null, 2),\n      );\n    });\n  });\n\n  it('does not include anything in response if snapshot is null', async t => {\n    await withMcpContext(async (response, context) => {\n      const page = context.getSelectedPptrPage();\n      page.accessibility.snapshot = async () => null;\n      const {content, structuredContent} = await response.handle(\n        'test',\n        context,\n      );\n      t.assert.snapshot?.(getTextContent(content[0]));\n      t.assert.snapshot?.(\n        JSON.stringify(stabilizeStructuredContent(structuredContent), null, 2),\n      );\n    });\n  });\n\n  it('returns correctly formatted snapshot for a simple tree', async t => {\n    await withMcpContext(async (response, context) => {\n      const page = context.getSelectedPptrPage();\n      await page.setContent(\n        html`<button>Click me</button>\n          <input\n            type=\"text\"\n            value=\"Input\"\n          />`,\n      );\n      await page.focus('button');\n      response.includeSnapshot();\n      const {content, structuredContent} = await response.handle(\n        'test',\n        context,\n      );\n      t.assert.snapshot?.(getTextContent(content[0]));\n      t.assert.snapshot?.(\n        JSON.stringify(stabilizeStructuredContent(structuredContent), null, 2),\n      );\n    });\n  });\n\n  it('returns values for textboxes', async t => {\n    await withMcpContext(async (response, context) => {\n      const page = context.getSelectedPptrPage();\n      await page.setContent(\n        html`<label\n          >username<input\n            name=\"username\"\n            value=\"mcp\"\n        /></label>`,\n      );\n      await page.focus('input');\n      response.includeSnapshot();\n      const {content, structuredContent} = await response.handle(\n        'test',\n        context,\n      );\n      assert.equal(content[0].type, 'text');\n      t.assert.snapshot?.(getTextContent(content[0]));\n      t.assert.snapshot?.(\n        JSON.stringify(stabilizeStructuredContent(structuredContent), null, 2),\n      );\n    });\n  });\n\n  it('returns verbose snapshot and structured content', async t => {\n    await withMcpContext(async (response, context) => {\n      const page = context.getSelectedPptrPage();\n      await page.setContent(html`<aside>test</aside>`);\n      response.includeSnapshot({\n        verbose: true,\n      });\n      const {content, structuredContent} = await response.handle(\n        'test',\n        context,\n      );\n      assert.equal(content[0].type, 'text');\n      t.assert.snapshot?.(getTextContent(content[0]));\n      t.assert.snapshot?.(JSON.stringify(structuredContent, null, 2));\n    });\n  });\n\n  it('saves snapshot to file and returns structured content', async t => {\n    const filePath = join(tmpdir(), 'test-screenshot.png');\n    try {\n      await withMcpContext(async (response, context) => {\n        const page = context.getSelectedPptrPage();\n        await page.setContent(html`<aside>test</aside>`);\n        response.includeSnapshot({\n          verbose: true,\n          filePath,\n        });\n        const {content, structuredContent} = await response.handle(\n          'test',\n          context,\n        );\n        assert.equal(content[0].type, 'text');\n        t.assert.snapshot?.(\n          stabilizeResponseOutput(getTextContent(content[0])),\n        );\n        t.assert.snapshot?.(\n          JSON.stringify(\n            stabilizeStructuredContent(structuredContent),\n            null,\n            2,\n          ),\n        );\n      });\n      const content = await readFile(filePath, 'utf-8');\n      t.assert.snapshot?.(stabilizeResponseOutput(content));\n    } finally {\n      await rm(filePath, {force: true});\n    }\n  });\n\n  it('preserves mapping ids across multiple snapshots', async () => {\n    await withMcpContext(async (response, context) => {\n      const page = context.getSelectedPptrPage();\n      await page.setContent(html`\n        <div>\n          <button id=\"btn1\">Button 1</button>\n          <span id=\"span1\">Span 1</span>\n        </div>\n      `);\n      response.includeSnapshot();\n      // First snapshot\n      const res1 = await response.handle('test', context);\n      const text1 = getTextContent(res1.content[0]);\n      const btn1IdMatch = text1.match(/uid=(\\S+) .*Button 1/);\n      const span1IdMatch = text1.match(/uid=(\\S+) .*Span 1/);\n\n      assert.ok(btn1IdMatch, 'Button 1 ID not found in first snapshot');\n      assert.ok(span1IdMatch, 'Span 1 ID not found in first snapshot');\n\n      const btn1Id = btn1IdMatch[1];\n      const span1Id = span1IdMatch[1];\n\n      // Modify page: add a new element before the others to potentially shift indices if not stable\n      await page.evaluate(() => {\n        const newBtn = document.createElement('button');\n        newBtn.textContent = 'Button 2';\n        document.body.prepend(newBtn);\n      });\n\n      // Second snapshot\n      const res2 = await response.handle('test', context);\n      const text2 = getTextContent(res2.content[0]);\n\n      const btn1IdMatch2 = text2.match(/uid=(\\S+) .*Button 1/);\n      const span1IdMatch2 = text2.match(/uid=(\\S+) .*Span 1/);\n      const btn2IdMatch = text2.match(/uid=(\\S+) .*Button 2/);\n\n      assert.ok(btn1IdMatch2, 'Button 1 ID not found in second snapshot');\n      assert.ok(span1IdMatch2, 'Span 1 ID not found in second snapshot');\n      assert.ok(btn2IdMatch, 'Button 2 ID not found in second snapshot');\n\n      assert.strictEqual(\n        btn1IdMatch2[1],\n        btn1Id,\n        'Button 1 ID changed between snapshots',\n      );\n      assert.strictEqual(\n        span1IdMatch2[1],\n        span1Id,\n        'Span 1 ID changed between snapshots',\n      );\n      assert.notStrictEqual(\n        btn2IdMatch[1],\n        btn1Id,\n        'Button 2 ID collides with Button 1',\n      );\n      assert.notStrictEqual(\n        btn2IdMatch[1],\n        btn1Id,\n        'Button 2 ID collides with Button 1',\n      );\n    });\n  });\n\n  describe('navigation', () => {\n    const server = serverHooks();\n\n    it('resets ids after navigation', async () => {\n      await withMcpContext(async (response, context) => {\n        server.addHtmlRoute(\n          '/page.html',\n          html`\n            <div>\n              <button id=\"btn1\">Button 1</button>\n            </div>\n          `,\n        );\n        const page = context.getSelectedPptrPage();\n        await page.goto(server.getRoute('/page.html'));\n\n        response.includeSnapshot();\n        const res1 = await response.handle('test', context);\n        const text1 = getTextContent(res1.content[0]);\n        const btn1IdMatch = text1.match(/uid=(\\S+) .*Button 1/);\n        assert.ok(btn1IdMatch, 'Button 1 ID not found in first snapshot');\n        const btn1Id = btn1IdMatch[1];\n\n        // Navigate to the same page again (or meaningful navigation)\n        await page.goto(server.getRoute('/page.html'));\n\n        const res2 = await response.handle('test', context);\n        const text2 = getTextContent(res2.content[0]);\n        const btn1IdMatch2 = text2.match(/uid=(\\S+) .*Button 1/);\n        assert.ok(btn1IdMatch2, 'Button 1 ID not found in second snapshot');\n        const btn1Id2 = btn1IdMatch2[1];\n\n        assert.notStrictEqual(\n          btn1Id2,\n          btn1Id,\n          'ID should reset after navigation',\n        );\n      });\n    });\n  });\n\n  it('adds throttling setting when it is not null', async t => {\n    await withMcpContext(async (response, context) => {\n      await context.emulate({networkConditions: 'Slow 3G'});\n      const {content, structuredContent} = await response.handle(\n        'test',\n        context,\n      );\n      assert.equal(content[0].type, 'text');\n      t.assert.snapshot?.(getTextContent(content[0]));\n      t.assert.snapshot?.(\n        JSON.stringify(stabilizeStructuredContent(structuredContent), null, 2),\n      );\n    });\n  });\n\n  it('does not include throttling setting when it is null', async t => {\n    await withMcpContext(async (response, context) => {\n      const {content, structuredContent} = await response.handle(\n        'test',\n        context,\n      );\n      await context.emulate({});\n      t.assert.snapshot?.(getTextContent(content[0]));\n      t.assert.snapshot?.(\n        JSON.stringify(stabilizeStructuredContent(structuredContent), null, 2),\n      );\n    });\n  });\n  it('adds image when image is attached', async t => {\n    await withMcpContext(async (response, context) => {\n      response.attachImage({data: 'imageBase64', mimeType: 'image/png'});\n      const {content, structuredContent} = await response.handle(\n        'test',\n        context,\n      );\n      t.assert.snapshot?.(getTextContent(content[0]));\n      assert.equal(content[1].type, 'image');\n      assert.strictEqual(getImageContent(content[1]).data, 'imageBase64');\n      assert.strictEqual(getImageContent(content[1]).mimeType, 'image/png');\n      t.assert.snapshot?.(\n        JSON.stringify(stabilizeStructuredContent(structuredContent), null, 2),\n      );\n    });\n  });\n\n  it('adds cpu throttling setting when it is over 1', async t => {\n    await withMcpContext(async (response, context) => {\n      await context.emulate({cpuThrottlingRate: 4});\n      const {content, structuredContent} = await response.handle(\n        'test',\n        context,\n      );\n      t.assert.snapshot?.(getTextContent(content[0]));\n      t.assert.snapshot?.(\n        JSON.stringify(stabilizeStructuredContent(structuredContent), null, 2),\n      );\n    });\n  });\n\n  it('does not include cpu throttling setting when it is 1', async t => {\n    await withMcpContext(async (response, context) => {\n      await context.emulate({cpuThrottlingRate: 1});\n      const {content, structuredContent} = await response.handle(\n        'test',\n        context,\n      );\n      t.assert.snapshot?.(getTextContent(content[0]));\n      t.assert.snapshot?.(\n        JSON.stringify(stabilizeStructuredContent(structuredContent), null, 2),\n      );\n    });\n  });\n\n  it('adds viewport emulation setting when it is set', async t => {\n    await withMcpContext(async (response, context) => {\n      await context.emulate({\n        viewport: {width: 400, height: 400, deviceScaleFactor: 1},\n      });\n      const {content, structuredContent} = await response.handle(\n        'test',\n        context,\n      );\n      t.assert.snapshot?.(getTextContent(content[0]));\n      t.assert.snapshot?.(\n        JSON.stringify(stabilizeStructuredContent(structuredContent), null, 2),\n      );\n    });\n  });\n\n  it('adds userAgent emulation setting when it is set', async t => {\n    await withMcpContext(async (response, context) => {\n      await context.emulate({userAgent: 'MyUA'});\n      const {content, structuredContent} = await response.handle(\n        'test',\n        context,\n      );\n      t.assert.snapshot?.(getTextContent(content[0]));\n      t.assert.snapshot?.(\n        JSON.stringify(stabilizeStructuredContent(structuredContent), null, 2),\n      );\n    });\n  });\n\n  it('adds color scheme emulation setting when it is set', async t => {\n    await withMcpContext(async (response, context) => {\n      await context.emulate({colorScheme: 'dark'});\n      const {content, structuredContent} = await response.handle(\n        'test',\n        context,\n      );\n      t.assert.snapshot?.(getTextContent(content[0]));\n      t.assert.snapshot?.(\n        JSON.stringify(stabilizeStructuredContent(structuredContent), null, 2),\n      );\n    });\n  });\n\n  it('adds a prompt dialog', async t => {\n    await withMcpContext(async (response, context) => {\n      const page = context.getSelectedMcpPage();\n      const dialogPromise = new Promise<void>(resolve => {\n        page.pptrPage.on('dialog', () => {\n          resolve();\n        });\n      });\n      page.pptrPage.evaluate(() => {\n        prompt('message', 'default');\n      });\n      await dialogPromise;\n      const {content, structuredContent} = await response.handle(\n        'test',\n        context,\n      );\n      await page.getDialog()?.dismiss();\n      t.assert.snapshot?.(getTextContent(content[0]));\n      t.assert.snapshot?.(\n        JSON.stringify(stabilizeStructuredContent(structuredContent), null, 2),\n      );\n    });\n  });\n\n  it('adds an alert dialog', async t => {\n    await withMcpContext(async (response, context) => {\n      const page = context.getSelectedMcpPage();\n      const dialogPromise = new Promise<void>(resolve => {\n        page.pptrPage.on('dialog', () => {\n          resolve();\n        });\n      });\n      page.pptrPage.evaluate(() => {\n        alert('message');\n      });\n      await dialogPromise;\n      const {content, structuredContent} = await response.handle(\n        'test',\n        context,\n      );\n      await page.getDialog()?.dismiss();\n      t.assert.snapshot?.(getTextContent(content[0]));\n      t.assert.snapshot?.(\n        JSON.stringify(stabilizeStructuredContent(structuredContent), null, 2),\n      );\n    });\n  });\n\n  it('add network requests when setting is true', async t => {\n    await withMcpContext(async (response, context) => {\n      response.setIncludeNetworkRequests(true);\n      context.getNetworkRequests = () => {\n        return [getMockRequest({stableId: 1}), getMockRequest({stableId: 2})];\n      };\n      const {content, structuredContent} = await response.handle(\n        'test',\n        context,\n      );\n      t.assert.snapshot?.(getTextContent(content[0]));\n      t.assert.snapshot?.(\n        JSON.stringify(stabilizeStructuredContent(structuredContent), null, 2),\n      );\n    });\n  });\n\n  it('does not include network requests when setting is false', async t => {\n    await withMcpContext(async (response, context) => {\n      response.setIncludeNetworkRequests(false);\n      context.getNetworkRequests = () => {\n        return [getMockRequest()];\n      };\n      const {content, structuredContent} = await response.handle(\n        'test',\n        context,\n      );\n      t.assert.snapshot?.(getTextContent(content[0]));\n      t.assert.snapshot?.(\n        JSON.stringify(stabilizeStructuredContent(structuredContent), null, 2),\n      );\n    });\n  });\n\n  it('add network request when attached with POST data', async t => {\n    await withMcpContext(async (response, context) => {\n      response.setIncludeNetworkRequests(true);\n      const httpResponse = getMockResponse();\n      httpResponse.buffer = () => {\n        return Promise.resolve(Buffer.from(JSON.stringify({response: 'body'})));\n      };\n      httpResponse.headers = () => {\n        return {\n          'Content-Type': 'application/json',\n        };\n      };\n      const request = getMockRequest({\n        method: 'POST',\n        hasPostData: true,\n        postData: JSON.stringify({request: 'body'}),\n        response: httpResponse,\n      });\n      context.getNetworkRequests = () => {\n        return [request];\n      };\n      context.getNetworkRequestById = () => {\n        return request;\n      };\n      response.attachNetworkRequest(1);\n\n      const {content, structuredContent} = await response.handle(\n        'test',\n        context,\n      );\n\n      t.assert.snapshot?.(getTextContent(content[0]));\n      t.assert.snapshot?.(\n        JSON.stringify(stabilizeStructuredContent(structuredContent), null, 2),\n      );\n    });\n  });\n\n  it('add network request when attached', async t => {\n    await withMcpContext(async (response, context) => {\n      response.setIncludeNetworkRequests(true);\n      const request = getMockRequest();\n      context.getNetworkRequests = () => {\n        return [request];\n      };\n      context.getNetworkRequestById = () => {\n        return request;\n      };\n      response.attachNetworkRequest(1);\n      const {content, structuredContent} = await response.handle(\n        'test',\n        context,\n      );\n      t.assert.snapshot?.(getTextContent(content[0]));\n      t.assert.snapshot?.(\n        JSON.stringify(stabilizeStructuredContent(structuredContent), null, 2),\n      );\n    });\n  });\n\n  it('adds console messages when the setting is true', async t => {\n    await withMcpContext(async (response, context) => {\n      response.setIncludeConsoleData(true);\n      const page = context.getSelectedPptrPage();\n      const consoleMessagePromise = new Promise<void>(resolve => {\n        page.on('console', () => {\n          resolve();\n        });\n      });\n      page.evaluate(() => {\n        console.log('Hello from the test');\n      });\n      await consoleMessagePromise;\n      const {content, structuredContent} = await response.handle(\n        'test',\n        context,\n      );\n      assert.ok(getTextContent(content[0]));\n      t.assert.snapshot?.(getTextContent(content[0]));\n      t.assert.snapshot?.(\n        JSON.stringify(stabilizeStructuredContent(structuredContent), null, 2),\n      );\n    });\n  });\n\n  it('adds a message when no console messages exist', async t => {\n    await withMcpContext(async (response, context) => {\n      response.setIncludeConsoleData(true);\n      const {content, structuredContent} = await response.handle(\n        'test',\n        context,\n      );\n      assert.ok(getTextContent(content[0]));\n      t.assert.snapshot?.(getTextContent(content[0]));\n      t.assert.snapshot?.(\n        JSON.stringify(stabilizeStructuredContent(structuredContent), null, 2),\n      );\n    });\n  });\n\n  it(\"doesn't list the issue message if mapping returns null\", async t => {\n    await withMcpContext(async (response, context) => {\n      const mockAggregatedIssue = getMockAggregatedIssue();\n      const mockDescription = {\n        file: 'not-existing-description-file.md',\n        links: [],\n      };\n      mockAggregatedIssue.getDescription.returns(mockDescription);\n      response.setIncludeConsoleData(true);\n      context.getConsoleData = () => {\n        return [mockAggregatedIssue];\n      };\n\n      const {content, structuredContent} = await response.handle(\n        'test',\n        context,\n      );\n      const text = getTextContent(content[0]);\n      assert.ok(text.includes('<no console messages found>'));\n      t.assert.snapshot?.(\n        JSON.stringify(stabilizeStructuredContent(structuredContent), null, 2),\n      );\n    });\n  });\n\n  it('throws error if mapping returns null on get issue details', async () => {\n    await withMcpContext(async (response, context) => {\n      const mockAggregatedIssue = getMockAggregatedIssue();\n      const mockDescription = {\n        file: 'not-existing-description-file.md',\n        links: [],\n      };\n      mockAggregatedIssue.getDescription.returns(mockDescription);\n      response.attachConsoleMessage(1);\n      context.getConsoleMessageById = () => {\n        return mockAggregatedIssue;\n      };\n\n      try {\n        await response.handle('test', context);\n      } catch (e) {\n        assert.ok(e.message.includes(\"Can't provide detals for the msgid 1\"));\n      }\n    });\n  });\n});\n\ndescribe('McpResponse network request filtering', () => {\n  it('filters network requests by resource type', async t => {\n    await withMcpContext(async (response, context) => {\n      response.setIncludeNetworkRequests(true, {\n        resourceTypes: ['script', 'stylesheet'],\n      });\n      context.getNetworkRequests = () => {\n        return [\n          getMockRequest({resourceType: 'script'}),\n          getMockRequest({resourceType: 'image'}),\n          getMockRequest({resourceType: 'stylesheet'}),\n          getMockRequest({resourceType: 'document'}),\n        ];\n      };\n      const {content, structuredContent} = await response.handle(\n        'test',\n        context,\n      );\n      t.assert.snapshot?.(getTextContent(content[0]));\n      t.assert.snapshot?.(\n        JSON.stringify(stabilizeStructuredContent(structuredContent), null, 2),\n      );\n    });\n  });\n\n  it('filters network requests by single resource type', async t => {\n    await withMcpContext(async (response, context) => {\n      response.setIncludeNetworkRequests(true, {\n        resourceTypes: ['image'],\n      });\n      context.getNetworkRequests = () => {\n        return [\n          getMockRequest({resourceType: 'script'}),\n          getMockRequest({resourceType: 'image'}),\n          getMockRequest({resourceType: 'stylesheet'}),\n        ];\n      };\n      const {content, structuredContent} = await response.handle(\n        'test',\n        context,\n      );\n      t.assert.snapshot?.(getTextContent(content[0]));\n      t.assert.snapshot?.(\n        JSON.stringify(stabilizeStructuredContent(structuredContent), null, 2),\n      );\n    });\n  });\n\n  it('shows no requests when filter matches nothing', async t => {\n    await withMcpContext(async (response, context) => {\n      response.setIncludeNetworkRequests(true, {\n        resourceTypes: ['font'],\n      });\n      context.getNetworkRequests = () => {\n        return [\n          getMockRequest({resourceType: 'script'}),\n          getMockRequest({resourceType: 'image'}),\n          getMockRequest({resourceType: 'stylesheet'}),\n        ];\n      };\n      const {content, structuredContent} = await response.handle(\n        'test',\n        context,\n      );\n      t.assert.snapshot?.(getTextContent(content[0]));\n      t.assert.snapshot?.(\n        JSON.stringify(stabilizeStructuredContent(structuredContent), null, 2),\n      );\n    });\n  });\n\n  it('shows all requests when no filters are provided', async t => {\n    await withMcpContext(async (response, context) => {\n      response.setIncludeNetworkRequests(true);\n      context.getNetworkRequests = () => {\n        return [\n          getMockRequest({resourceType: 'script'}),\n          getMockRequest({resourceType: 'image'}),\n          getMockRequest({resourceType: 'stylesheet'}),\n          getMockRequest({resourceType: 'document'}),\n          getMockRequest({resourceType: 'font'}),\n        ];\n      };\n      const {content, structuredContent} = await response.handle(\n        'test',\n        context,\n      );\n\n      t.assert.snapshot?.(getTextContent(content[0]));\n      t.assert.snapshot?.(\n        JSON.stringify(stabilizeStructuredContent(structuredContent), null, 2),\n      );\n    });\n  });\n\n  it('shows all requests when empty resourceTypes array is provided', async t => {\n    await withMcpContext(async (response, context) => {\n      response.setIncludeNetworkRequests(true, {\n        resourceTypes: [],\n      });\n      context.getNetworkRequests = () => {\n        return [\n          getMockRequest({resourceType: 'script'}),\n          getMockRequest({resourceType: 'image'}),\n          getMockRequest({resourceType: 'stylesheet'}),\n          getMockRequest({resourceType: 'document'}),\n          getMockRequest({resourceType: 'font'}),\n        ];\n      };\n      const {content, structuredContent} = await response.handle(\n        'test',\n        context,\n      );\n      t.assert.snapshot?.(getTextContent(content[0]));\n      t.assert.snapshot?.(\n        JSON.stringify(stabilizeStructuredContent(structuredContent), null, 2),\n      );\n    });\n  });\n});\n\ndescribe('McpResponse network pagination', () => {\n  it('returns all requests when pagination is not provided', async t => {\n    await withMcpContext(async (response, context) => {\n      const requests = Array.from({length: 5}, () => getMockRequest());\n      context.getNetworkRequests = () => requests;\n      response.setIncludeNetworkRequests(true);\n      const {content, structuredContent} = await response.handle(\n        'test',\n        context,\n      );\n      const text = getTextContent(content[0]);\n      assert.ok(text.includes('Showing 1-5 of 5 (Page 1 of 1).'));\n      assert.ok(!text.includes('Next page:'));\n      assert.ok(!text.includes('Previous page:'));\n      t.assert.snapshot?.(\n        JSON.stringify(stabilizeStructuredContent(structuredContent), null, 2),\n      );\n    });\n  });\n\n  it('returns first page by default', async t => {\n    await withMcpContext(async (response, context) => {\n      const requests = Array.from({length: 30}, (_, idx) =>\n        getMockRequest({method: `GET-${idx}`}),\n      );\n      context.getNetworkRequests = () => {\n        return requests;\n      };\n      response.setIncludeNetworkRequests(true, {pageSize: 10});\n      const {content, structuredContent} = await response.handle(\n        'test',\n        context,\n      );\n      const text = getTextContent(content[0]);\n      assert.ok(text.includes('Showing 1-10 of 30 (Page 1 of 3).'));\n      assert.ok(text.includes('Next page: 1'));\n      assert.ok(!text.includes('Previous page:'));\n      t.assert.snapshot?.(\n        JSON.stringify(stabilizeStructuredContent(structuredContent), null, 2),\n      );\n    });\n  });\n\n  it('returns subsequent page when pageIdx provided', async t => {\n    await withMcpContext(async (response, context) => {\n      const requests = Array.from({length: 25}, (_, idx) =>\n        getMockRequest({method: `GET-${idx}`}),\n      );\n      context.getNetworkRequests = () => requests;\n      response.setIncludeNetworkRequests(true, {\n        pageSize: 10,\n        pageIdx: 1,\n      });\n      const {content, structuredContent} = await response.handle(\n        'test',\n        context,\n      );\n      const text = getTextContent(content[0]);\n      assert.ok(text.includes('Showing 11-20 of 25 (Page 2 of 3).'));\n      assert.ok(text.includes('Next page: 2'));\n      assert.ok(text.includes('Previous page: 0'));\n      t.assert.snapshot?.(\n        JSON.stringify(stabilizeStructuredContent(structuredContent), null, 2),\n      );\n    });\n  });\n\n  it('handles invalid page number by showing first page', async t => {\n    await withMcpContext(async (response, context) => {\n      const requests = Array.from({length: 5}, () => getMockRequest());\n      context.getNetworkRequests = () => requests;\n      response.setIncludeNetworkRequests(true, {\n        pageSize: 2,\n        pageIdx: 10, // Invalid page number\n      });\n      const {content, structuredContent} = await response.handle(\n        'test',\n        context,\n      );\n      const text = getTextContent(content[0]);\n      assert.ok(\n        text.includes('Invalid page number provided. Showing first page.'),\n      );\n      assert.ok(text.includes('Showing 1-2 of 5 (Page 1 of 3).'));\n      t.assert.snapshot?.(\n        JSON.stringify(stabilizeStructuredContent(structuredContent), null, 2),\n      );\n    });\n  });\n\n  describe('trace summaries', () => {\n    it('includes the trace summary text and structured data', async t => {\n      const rawData = loadTraceAsBuffer('web-dev-with-commit.json.gz');\n      const result = await parseRawTraceBuffer(rawData);\n      if (!traceResultIsSuccess(result)) {\n        throw new Error(result.error);\n      }\n\n      await withMcpContext(async (response, context) => {\n        response.attachTraceSummary(result);\n        const {content, structuredContent} = await response.handle(\n          'test',\n          context,\n        );\n\n        t.assert.snapshot?.(getTextContent(content[0]));\n        const typedStructuredContent = structuredContent as {\n          traceSummary?: string;\n          traceInsights?: unknown[];\n        };\n        t.assert.snapshot?.(\n          JSON.stringify(typedStructuredContent.traceSummary, null, 2),\n        );\n        t.assert.snapshot?.(\n          JSON.stringify(typedStructuredContent.traceInsights, null, 2),\n        );\n      });\n    });\n  });\n\n  describe('trace insights', () => {\n    it('includes the trace insight output', async t => {\n      const rawData = loadTraceAsBuffer('web-dev-with-commit.json.gz');\n      const result = await parseRawTraceBuffer(rawData);\n      if (!traceResultIsSuccess(result)) {\n        throw new Error(result.error);\n      }\n\n      await withMcpContext(async (response, context) => {\n        response.attachTraceInsight(\n          result,\n          'NAVIGATION_0',\n          'LCPBreakdown' as InsightName,\n        );\n        const {content, structuredContent} = await response.handle(\n          'test',\n          context,\n        );\n\n        t.assert.snapshot?.(getTextContent(content[0]));\n        t.assert.snapshot?.(\n          JSON.stringify(\n            stabilizeStructuredContent(structuredContent),\n            null,\n            2,\n          ),\n        );\n      });\n    });\n\n    it('includes error if insight not found', async t => {\n      const rawData = loadTraceAsBuffer('web-dev-with-commit.json.gz');\n      const result = await parseRawTraceBuffer(rawData);\n      if (!traceResultIsSuccess(result)) {\n        throw new Error(result.error);\n      }\n\n      await withMcpContext(async (response, context) => {\n        response.attachTraceInsight(\n          result,\n          'BAD_ID',\n          'LCPBreakdown' as InsightName,\n        );\n        const {content, structuredContent} = await response.handle(\n          'test',\n          context,\n        );\n\n        t.assert.snapshot?.(getTextContent(content[0]));\n        t.assert.snapshot?.(\n          JSON.stringify(\n            stabilizeStructuredContent(structuredContent),\n            null,\n            2,\n          ),\n        );\n      });\n    });\n  });\n});\n\ndescribe('extensions', () => {\n  it('lists extensions', async t => {\n    await withMcpContext(async (response, context) => {\n      response.setListExtensions();\n      // Empty state testing\n      const emptyResult = await response.handle('test', context);\n      const emptyText = getTextContent(emptyResult.content[0]);\n      assert.ok(\n        emptyText.includes('No extensions installed.'),\n        'Should show message for ampty extensions',\n      );\n\n      response.resetResponseLineForTesting();\n      // Testing with extensions\n      context.listExtensions = () => [\n        {\n          id: 'id1',\n          name: 'Extension 1',\n          version: '1.0',\n          isEnabled: true,\n          path: '/path/to/ext1',\n        },\n        {\n          id: 'id2',\n          name: 'Extension 2',\n          version: '2.0',\n          isEnabled: false,\n          path: '/path/to/ext2',\n        },\n      ];\n      response.setListExtensions();\n      const {content, structuredContent} = await response.handle(\n        'test',\n        context,\n      );\n\n      t.assert.snapshot?.(getTextContent(content[0]));\n      t.assert.snapshot?.(JSON.stringify(structuredContent, null, 2));\n    });\n  });\n});\n\ndescribe('lighthouse', () => {\n  it('includes lighthouse report paths', async t => {\n    await withMcpContext(async (response, context) => {\n      const lighthouseResult = {\n        summary: {\n          mode: 'navigation',\n          device: 'desktop',\n          url: 'https://example.com',\n          scores: [\n            {\n              id: 'performance',\n              title: 'Performance',\n              score: 0.9,\n            },\n          ],\n          audits: {\n            failed: 1,\n            passed: 10,\n          },\n          timing: {\n            total: 1000,\n          },\n        },\n        reports: ['/tmp/report.json', '/tmp/report.html'],\n      };\n\n      response.attachLighthouseResult(lighthouseResult);\n      const {content, structuredContent} = await response.handle(\n        'test',\n        context,\n      );\n\n      const text = getTextContent(content[0]);\n      assert.ok(text.includes('### Reports'));\n      assert.ok(text.includes('- /tmp/report.json'));\n      assert.ok(text.includes('- /tmp/report.html'));\n\n      t.assert.snapshot?.(getTextContent(content[0]));\n      t.assert.snapshot?.(\n        JSON.stringify(stabilizeStructuredContent(structuredContent), null, 2),\n      );\n    });\n  });\n});\n"
  },
  {
    "path": "tests/PageCollector.test.ts",
    "content": "/**\n * @license\n * Copyright 2025 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport assert from 'node:assert';\nimport {afterEach, beforeEach, describe, it} from 'node:test';\n\nimport type {Frame, HTTPRequest, Target, Protocol} from 'puppeteer-core';\nimport sinon from 'sinon';\n\nimport type {ListenerMap} from '../src/PageCollector.js';\nimport {\n  ConsoleCollector,\n  NetworkCollector,\n  PageCollector,\n} from '../src/PageCollector.js';\nimport {DevTools} from '../src/third_party/index.js';\n\nimport {getMockRequest, getMockBrowser} from './utils.js';\n\ndescribe('PageCollector', () => {\n  it('works', async () => {\n    const browser = getMockBrowser();\n    const page = (await browser.pages())[0];\n    const request = getMockRequest();\n    const collector = new PageCollector(browser, collect => {\n      return {\n        request: req => {\n          collect(req);\n        },\n      } as ListenerMap;\n    });\n    await collector.init([page]);\n    page.emit('request', request);\n\n    assert.equal(collector.getData(page)[0], request);\n  });\n\n  it('clean up after navigation', async () => {\n    const browser = getMockBrowser();\n    const page = (await browser.pages())[0];\n    const mainFrame = page.mainFrame();\n    const request = getMockRequest();\n    const collector = new PageCollector(browser, collect => {\n      return {\n        request: req => {\n          collect(req);\n        },\n      } as ListenerMap;\n    });\n    await collector.init([page]);\n    page.emit('request', request);\n\n    assert.equal(collector.getData(page)[0], request);\n    page.emit('framenavigated', mainFrame);\n\n    assert.equal(collector.getData(page).length, 0);\n  });\n\n  it('does not clean up after sub frame navigation', async () => {\n    const browser = getMockBrowser();\n    const page = (await browser.pages())[0];\n    const request = getMockRequest();\n    const collector = new PageCollector(browser, collect => {\n      return {\n        request: req => {\n          collect(req);\n        },\n      } as ListenerMap;\n    });\n    await collector.init([page]);\n    page.emit('request', request);\n    page.emit('framenavigated', {} as Frame);\n\n    assert.equal(collector.getData(page).length, 1);\n  });\n\n  it('clean up after navigation and be able to add data after', async () => {\n    const browser = getMockBrowser();\n    const page = (await browser.pages())[0];\n    const mainFrame = page.mainFrame();\n    const request = getMockRequest();\n    const collector = new PageCollector(browser, collect => {\n      return {\n        request: req => {\n          collect(req);\n        },\n      } as ListenerMap;\n    });\n    await collector.init([page]);\n    page.emit('request', request);\n\n    assert.equal(collector.getData(page)[0], request);\n    page.emit('framenavigated', mainFrame);\n\n    assert.equal(collector.getData(page).length, 0);\n\n    page.emit('request', request);\n\n    assert.equal(collector.getData(page).length, 1);\n  });\n\n  it('should only subscribe once', async () => {\n    const browser = getMockBrowser();\n    const page = (await browser.pages())[0];\n    const request = getMockRequest();\n    const collector = new PageCollector(browser, collect => {\n      return {\n        request: req => {\n          collect(req);\n        },\n      } as ListenerMap;\n    });\n    await collector.init([page]);\n    browser.emit('targetcreated', {\n      page() {\n        return Promise.resolve(page);\n      },\n    } as Target);\n\n    // The page inside part is async so we need to await some time\n    await new Promise<void>(res => res());\n\n    assert.equal(collector.getData(page).length, 0);\n\n    page.emit('request', request);\n\n    assert.equal(collector.getData(page).length, 1);\n\n    page.emit('request', request);\n\n    assert.equal(collector.getData(page).length, 2);\n  });\n\n  it('should clear data on page destroy', async () => {\n    const browser = getMockBrowser();\n    const page = (await browser.pages())[0];\n    const request = getMockRequest();\n    const collector = new PageCollector(browser, collect => {\n      return {\n        request: req => {\n          collect(req);\n        },\n      } as ListenerMap;\n    });\n    await collector.init([page]);\n\n    page.emit('request', request);\n\n    assert.equal(collector.getData(page).length, 1);\n\n    browser.emit('targetdestroyed', {\n      page() {\n        return Promise.resolve(page);\n      },\n    } as Target);\n\n    // The page inside part is async so we need to await some time\n    await new Promise<void>(res => res());\n\n    assert.equal(collector.getData(page).length, 0);\n  });\n\n  it('should assign ids to requests', async () => {\n    const browser = getMockBrowser();\n    const page = (await browser.pages())[0];\n    const request1 = getMockRequest();\n    const request2 = getMockRequest();\n    const collector = new PageCollector<HTTPRequest>(browser, collect => {\n      return {\n        request: req => {\n          collect(req);\n        },\n      } as ListenerMap;\n    });\n    await collector.init([page]);\n\n    page.emit('request', request1);\n    page.emit('request', request2);\n\n    assert.equal(collector.getData(page).length, 2);\n\n    assert.equal(collector.getIdForResource(request1), 1);\n    assert.equal(collector.getIdForResource(request2), 2);\n  });\n});\n\ndescribe('NetworkCollector', () => {\n  it('correctly picks up navigation requests to latest navigation', async () => {\n    const browser = getMockBrowser();\n    const page = (await browser.pages())[0];\n    const mainFrame = page.mainFrame();\n    const request = getMockRequest();\n    const navRequest = getMockRequest({\n      navigationRequest: true,\n      frame: page.mainFrame(),\n    });\n    const request2 = getMockRequest();\n    const collector = new NetworkCollector(browser);\n    await collector.init([page]);\n    page.emit('request', request);\n    page.emit('request', navRequest);\n\n    assert.equal(collector.getData(page)[0], request);\n    assert.equal(collector.getData(page)[1], navRequest);\n    page.emit('framenavigated', mainFrame);\n\n    assert.equal(collector.getData(page).length, 1);\n    assert.equal(collector.getData(page)[0], navRequest);\n\n    page.emit('request', request2);\n\n    assert.equal(collector.getData(page).length, 2);\n    assert.equal(collector.getData(page)[0], navRequest);\n    assert.equal(collector.getData(page)[1], request2);\n  });\n\n  it('correctly picks up after multiple back to back navigations', async () => {\n    const browser = getMockBrowser();\n    const page = (await browser.pages())[0];\n    const mainFrame = page.mainFrame();\n    const navRequest = getMockRequest({\n      navigationRequest: true,\n      frame: page.mainFrame(),\n    });\n    const navRequest2 = getMockRequest({\n      navigationRequest: true,\n      frame: page.mainFrame(),\n    });\n    const request = getMockRequest();\n\n    const collector = new NetworkCollector(browser);\n    await collector.init([page]);\n    page.emit('request', navRequest);\n    assert.equal(collector.getData(page)[0], navRequest);\n\n    page.emit('framenavigated', mainFrame);\n    assert.equal(collector.getData(page).length, 1);\n    assert.equal(collector.getData(page)[0], navRequest);\n\n    page.emit('request', navRequest2);\n    assert.equal(collector.getData(page).length, 2);\n    assert.equal(collector.getData(page)[0], navRequest);\n    assert.equal(collector.getData(page)[1], navRequest2);\n\n    page.emit('framenavigated', mainFrame);\n    assert.equal(collector.getData(page).length, 1);\n    assert.equal(collector.getData(page)[0], navRequest2);\n\n    page.emit('request', request);\n    assert.equal(collector.getData(page).length, 2);\n  });\n\n  it('works with previous navigations', async () => {\n    const browser = getMockBrowser();\n    const page = (await browser.pages())[0];\n    const mainFrame = page.mainFrame();\n    const navRequest = getMockRequest({\n      navigationRequest: true,\n      frame: page.mainFrame(),\n    });\n    const navRequest2 = getMockRequest({\n      navigationRequest: true,\n      frame: page.mainFrame(),\n    });\n    const request = getMockRequest();\n\n    const collector = new NetworkCollector(browser);\n    await collector.init([page]);\n    page.emit('request', navRequest);\n    assert.equal(collector.getData(page, true).length, 1);\n\n    page.emit('framenavigated', mainFrame);\n    assert.equal(collector.getData(page, true).length, 1);\n\n    page.emit('request', navRequest2);\n    assert.equal(collector.getData(page, true).length, 2);\n\n    page.emit('framenavigated', mainFrame);\n    assert.equal(collector.getData(page, true).length, 2);\n\n    page.emit('request', request);\n    assert.equal(collector.getData(page, true).length, 3);\n  });\n});\n\ndescribe('ConsoleCollector', () => {\n  let issue: Protocol.Audits.InspectorIssue;\n\n  beforeEach(() => {\n    issue = {\n      code: 'MixedContentIssue',\n      details: {\n        mixedContentIssueDetails: {\n          insecureURL: 'test.url',\n          resolutionStatus: 'MixedContentBlocked',\n          mainResourceURL: '',\n        },\n      },\n    };\n  });\n\n  afterEach(() => {\n    sinon.restore();\n  });\n\n  it('emits issues on page', async () => {\n    const browser = getMockBrowser();\n    const page = (await browser.pages())[0];\n    // @ts-expect-error internal API.\n    const cdpSession = page._client();\n    const onIssuesListener = sinon.spy();\n\n    page.on('issue', onIssuesListener);\n\n    const collector = new ConsoleCollector(browser, collect => {\n      return {\n        issue: issue => {\n          collect(issue as DevTools.AggregatedIssue);\n        },\n      } as ListenerMap;\n    });\n    await collector.init([page]);\n    cdpSession.emit('Audits.issueAdded', {issue});\n    sinon.assert.calledOnce(onIssuesListener);\n\n    const issueArgument = onIssuesListener.getCall(0).args[0];\n    assert(issueArgument instanceof DevTools.AggregatedIssue);\n  });\n\n  it('collects issues', async () => {\n    const browser = getMockBrowser();\n    const page = (await browser.pages())[0];\n    // @ts-expect-error internal API.\n    const cdpSession = page._client();\n\n    const collector = new ConsoleCollector(browser, collect => {\n      return {\n        issue: issue => {\n          collect(issue as DevTools.AggregatedIssue);\n        },\n      } as ListenerMap;\n    });\n    await collector.init([page]);\n\n    const issue2 = {\n      code: 'ElementAccessibilityIssue' as const,\n      details: {\n        elementAccessibilityIssueDetails: {\n          nodeId: 1,\n          elementAccessibilityIssueReason: 'DisallowedSelectChild',\n          hasDisallowedAttributes: true,\n        },\n      },\n    } satisfies Protocol.Audits.InspectorIssue;\n\n    cdpSession.emit('Audits.issueAdded', {issue});\n    cdpSession.emit('Audits.issueAdded', {issue: issue2});\n    const data = collector.getData(page);\n    assert.equal(data.length, 2);\n  });\n\n  it('filters duplicated issues', async () => {\n    const browser = getMockBrowser();\n    const page = (await browser.pages())[0];\n    // @ts-expect-error internal API.\n    const cdpSession = page._client();\n\n    const collector = new ConsoleCollector(browser, collect => {\n      return {\n        issue: issue => {\n          collect(issue as DevTools.AggregatedIssue);\n        },\n      } as ListenerMap;\n    });\n    await collector.init([page]);\n\n    cdpSession.emit('Audits.issueAdded', {issue});\n    cdpSession.emit('Audits.issueAdded', {issue});\n    const data = collector.getData(page);\n    assert.equal(data.length, 1);\n    const collectedIssue = data[0];\n    assert(collectedIssue instanceof DevTools.AggregatedIssue);\n    assert.equal(collectedIssue.code(), 'MixedContentIssue');\n    assert.equal(collectedIssue.getAggregatedIssuesCount(), 1);\n  });\n\n  it('emits UncaughtErrors for Runtime.exceptionThrown CDP events', async () => {\n    const browser = getMockBrowser();\n    const page = (await browser.pages())[0];\n    // @ts-expect-error internal API.\n    const cdpSession = page._client();\n    const onUncaughtErrorListener = sinon.spy();\n    const collector = new ConsoleCollector(browser, () => {\n      return {\n        uncaughtError: onUncaughtErrorListener,\n      } as ListenerMap;\n    });\n    await collector.init([page]);\n\n    cdpSession.emit('Runtime.exceptionThrown', {\n      exceptionDetails: {\n        exception: {description: 'SyntaxError: Expected {'},\n        text: 'Uncaught',\n        stackTrace: {callFrames: []},\n      },\n    });\n\n    sinon.assert.calledOnceWithMatch(\n      onUncaughtErrorListener,\n      sinon.match(e => {\n        return (\n          e.details.exception.description === 'SyntaxError: Expected {',\n          e.details.text === 'Uncaught',\n          e.details.stackTrace.callFrames.length === 0\n        );\n      }),\n    );\n  });\n});\n"
  },
  {
    "path": "tests/browser.test.ts",
    "content": "/**\n * @license\n * Copyright 2025 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport assert from 'node:assert';\nimport os from 'node:os';\nimport path from 'node:path';\nimport {describe, it} from 'node:test';\n\nimport {executablePath} from 'puppeteer';\n\nimport {detectDisplay, ensureBrowserConnected, launch} from '../src/browser.js';\n\ndescribe('browser', () => {\n  it('detects display does not crash', () => {\n    detectDisplay();\n  });\n\n  it('cannot launch multiple times with the same profile', async () => {\n    const tmpDir = os.tmpdir();\n    const folderPath = path.join(tmpDir, `temp-folder-${crypto.randomUUID()}`);\n    const browser1 = await launch({\n      headless: true,\n      isolated: false,\n      userDataDir: folderPath,\n      executablePath: executablePath(),\n      devtools: false,\n    });\n    try {\n      try {\n        const browser2 = await launch({\n          headless: true,\n          isolated: false,\n          userDataDir: folderPath,\n          executablePath: executablePath(),\n          devtools: false,\n        });\n        await browser2.close();\n        assert.fail('not reached');\n      } catch (err) {\n        assert.strictEqual(\n          err.message,\n          `The browser is already running for ${folderPath}. Use --isolated to run multiple browser instances.`,\n        );\n      }\n    } finally {\n      await browser1.close();\n    }\n  });\n\n  it('launches with the initial viewport', async () => {\n    const tmpDir = os.tmpdir();\n    const folderPath = path.join(tmpDir, `temp-folder-${crypto.randomUUID()}`);\n    const browser = await launch({\n      headless: true,\n      isolated: false,\n      userDataDir: folderPath,\n      executablePath: executablePath(),\n      viewport: {\n        width: 1501,\n        height: 801,\n      },\n      devtools: false,\n    });\n    try {\n      const [page] = await browser.pages();\n      const result = await page.evaluate(() => {\n        return {width: window.innerWidth, height: window.innerHeight};\n      });\n      assert.deepStrictEqual(result, {\n        width: 1501,\n        height: 801,\n      });\n    } finally {\n      await browser.close();\n    }\n  });\n  it('connects to an existing browser with userDataDir', async () => {\n    const tmpDir = os.tmpdir();\n    const folderPath = path.join(tmpDir, `temp-folder-${crypto.randomUUID()}`);\n    const browser = await launch({\n      headless: true,\n      isolated: false,\n      userDataDir: folderPath,\n      executablePath: executablePath(),\n      devtools: false,\n      chromeArgs: ['--remote-debugging-port=0'],\n    });\n    try {\n      const connectedBrowser = await ensureBrowserConnected({\n        userDataDir: folderPath,\n        devtools: false,\n      });\n      assert.ok(connectedBrowser);\n      assert.ok(connectedBrowser.connected);\n      connectedBrowser.disconnect();\n    } finally {\n      await browser.close();\n    }\n  });\n});\n"
  },
  {
    "path": "tests/cli.test.ts",
    "content": "/**\n * @license\n * Copyright 2025 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport assert from 'node:assert';\nimport {describe, it} from 'node:test';\n\nimport {parseArguments} from '../src/bin/chrome-devtools-mcp-cli-options.js';\n\ndescribe('cli args parsing', () => {\n  const defaultArgs = {\n    'category-emulation': true,\n    categoryEmulation: true,\n    'category-performance': true,\n    categoryPerformance: true,\n    'category-network': true,\n    categoryNetwork: true,\n    'auto-connect': undefined,\n    autoConnect: undefined,\n    'performance-crux': true,\n    performanceCrux: true,\n    'usage-statistics': true,\n    usageStatistics: true,\n  };\n\n  it('parses with default args', async () => {\n    const args = parseArguments('1.0.0', ['node', 'main.js']);\n    assert.deepStrictEqual(args, {\n      ...defaultArgs,\n      _: [],\n      headless: false,\n      $0: 'npx chrome-devtools-mcp@latest',\n      channel: 'stable',\n    });\n  });\n\n  it('parses with browser url', async () => {\n    const args = parseArguments('1.0.0', [\n      'node',\n      'main.js',\n      '--browserUrl',\n      'http://localhost:3000',\n    ]);\n    assert.deepStrictEqual(args, {\n      ...defaultArgs,\n      _: [],\n      headless: false,\n      $0: 'npx chrome-devtools-mcp@latest',\n      'browser-url': 'http://localhost:3000',\n      browserUrl: 'http://localhost:3000',\n      u: 'http://localhost:3000',\n    });\n  });\n\n  it('parses with user data dir', async () => {\n    const args = parseArguments('1.0.0', [\n      'node',\n      'main.js',\n      '--user-data-dir',\n      '/tmp/chrome-profile',\n    ]);\n    assert.deepStrictEqual(args, {\n      ...defaultArgs,\n      _: [],\n      headless: false,\n      $0: 'npx chrome-devtools-mcp@latest',\n      channel: 'stable',\n      'user-data-dir': '/tmp/chrome-profile',\n      userDataDir: '/tmp/chrome-profile',\n    });\n  });\n\n  it('parses an empty browser url', async () => {\n    const args = parseArguments('1.0.0', [\n      'node',\n      'main.js',\n      '--browserUrl',\n      '',\n    ]);\n    assert.deepStrictEqual(args, {\n      ...defaultArgs,\n      _: [],\n      headless: false,\n      $0: 'npx chrome-devtools-mcp@latest',\n      'browser-url': undefined,\n      browserUrl: undefined,\n      u: undefined,\n      channel: 'stable',\n    });\n  });\n\n  it('parses with executable path', async () => {\n    const args = parseArguments('1.0.0', [\n      'node',\n      'main.js',\n      '--executablePath',\n      '/tmp/test 123/chrome',\n    ]);\n    assert.deepStrictEqual(args, {\n      ...defaultArgs,\n      _: [],\n      headless: false,\n      $0: 'npx chrome-devtools-mcp@latest',\n      'executable-path': '/tmp/test 123/chrome',\n      e: '/tmp/test 123/chrome',\n      executablePath: '/tmp/test 123/chrome',\n    });\n  });\n\n  it('parses viewport', async () => {\n    const args = parseArguments('1.0.0', [\n      'node',\n      'main.js',\n      '--viewport',\n      '888x777',\n    ]);\n    assert.deepStrictEqual(args, {\n      ...defaultArgs,\n      _: [],\n      headless: false,\n      $0: 'npx chrome-devtools-mcp@latest',\n      channel: 'stable',\n      viewport: {\n        width: 888,\n        height: 777,\n      },\n    });\n  });\n\n  it('parses chrome args', async () => {\n    const args = parseArguments('1.0.0', [\n      'node',\n      'main.js',\n      `--chrome-arg='--no-sandbox'`,\n      `--chrome-arg='--disable-setuid-sandbox'`,\n    ]);\n    assert.deepStrictEqual(args, {\n      ...defaultArgs,\n      _: [],\n      headless: false,\n      $0: 'npx chrome-devtools-mcp@latest',\n      channel: 'stable',\n      'chrome-arg': ['--no-sandbox', '--disable-setuid-sandbox'],\n      chromeArg: ['--no-sandbox', '--disable-setuid-sandbox'],\n    });\n  });\n\n  it('parses ignore chrome args', async () => {\n    const args = parseArguments('1.0.0', [\n      'node',\n      'main.js',\n      `--ignore-default-chrome-arg='--disable-extensions'`,\n      `--ignore-default-chrome-arg='--disable-cancel-all-touches'`,\n    ]);\n    assert.deepStrictEqual(args, {\n      ...defaultArgs,\n      _: [],\n      headless: false,\n      $0: 'npx chrome-devtools-mcp@latest',\n      channel: 'stable',\n      'ignore-default-chrome-arg': [\n        '--disable-extensions',\n        '--disable-cancel-all-touches',\n      ],\n      ignoreDefaultChromeArg: [\n        '--disable-extensions',\n        '--disable-cancel-all-touches',\n      ],\n    });\n  });\n\n  it('parses wsEndpoint with ws:// protocol', async () => {\n    const args = parseArguments('1.0.0', [\n      'node',\n      'main.js',\n      '--wsEndpoint',\n      'ws://127.0.0.1:9222/devtools/browser/abc123',\n    ]);\n    assert.deepStrictEqual(args, {\n      ...defaultArgs,\n      _: [],\n      headless: false,\n      $0: 'npx chrome-devtools-mcp@latest',\n      'ws-endpoint': 'ws://127.0.0.1:9222/devtools/browser/abc123',\n      wsEndpoint: 'ws://127.0.0.1:9222/devtools/browser/abc123',\n      w: 'ws://127.0.0.1:9222/devtools/browser/abc123',\n    });\n  });\n\n  it('parses wsEndpoint with wss:// protocol', async () => {\n    const args = parseArguments('1.0.0', [\n      'node',\n      'main.js',\n      '--wsEndpoint',\n      'wss://example.com:9222/devtools/browser/abc123',\n    ]);\n    assert.deepStrictEqual(args, {\n      ...defaultArgs,\n      _: [],\n      headless: false,\n      $0: 'npx chrome-devtools-mcp@latest',\n      'ws-endpoint': 'wss://example.com:9222/devtools/browser/abc123',\n      wsEndpoint: 'wss://example.com:9222/devtools/browser/abc123',\n      w: 'wss://example.com:9222/devtools/browser/abc123',\n    });\n  });\n\n  it('parses wsHeaders with valid JSON', async () => {\n    const args = parseArguments('1.0.0', [\n      'node',\n      'main.js',\n      '--wsEndpoint',\n      'ws://127.0.0.1:9222/devtools/browser/abc123',\n      '--wsHeaders',\n      '{\"Authorization\":\"Bearer token\",\"X-Custom\":\"value\"}',\n    ]);\n    assert.deepStrictEqual(args.wsHeaders, {\n      Authorization: 'Bearer token',\n      'X-Custom': 'value',\n    });\n  });\n\n  it('parses disabled category', async () => {\n    const args = parseArguments('1.0.0', [\n      'node',\n      'main.js',\n      '--no-category-emulation',\n    ]);\n    assert.deepStrictEqual(args, {\n      ...defaultArgs,\n      _: [],\n      headless: false,\n      $0: 'npx chrome-devtools-mcp@latest',\n      channel: 'stable',\n      'category-emulation': false,\n      categoryEmulation: false,\n    });\n  });\n  it('parses auto-connect', async () => {\n    const args = parseArguments('1.0.0', ['node', 'main.js', '--auto-connect']);\n    assert.deepStrictEqual(args, {\n      ...defaultArgs,\n      _: [],\n      headless: false,\n      $0: 'npx chrome-devtools-mcp@latest',\n      channel: 'stable',\n      'auto-connect': true,\n      autoConnect: true,\n    });\n  });\n\n  it('parses usage statistics flag', async () => {\n    // Test default (should be true).\n    const defaultArgs = parseArguments('1.0.0', ['node', 'main.js']);\n    assert.strictEqual(defaultArgs.usageStatistics, true);\n\n    // Test enabling it\n    const enabledArgs = parseArguments('1.0.0', [\n      'node',\n      'main.js',\n      '--usage-statistics',\n    ]);\n    assert.strictEqual(enabledArgs.usageStatistics, true);\n\n    // Test disabling it\n    const disabledArgs = parseArguments('1.0.0', [\n      'node',\n      'main.js',\n      '--no-usage-statistics',\n    ]);\n    assert.strictEqual(disabledArgs.usageStatistics, false);\n  });\n\n  it('parses performance crux flag', async () => {\n    const defaultArgs = parseArguments('1.0.0', ['node', 'main.js']);\n    assert.strictEqual(defaultArgs.performanceCrux, true);\n\n    // force enable\n    const enabledArgs = parseArguments('1.0.0', [\n      'node',\n      'main.js',\n      '--performance-crux',\n    ]);\n    assert.strictEqual(enabledArgs.performanceCrux, true);\n\n    const disabledArgs = parseArguments('1.0.0', [\n      'node',\n      'main.js',\n      '--no-performance-crux',\n    ]);\n    assert.strictEqual(disabledArgs.performanceCrux, false);\n  });\n});\n"
  },
  {
    "path": "tests/daemon/client.test.ts",
    "content": "/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport assert from 'node:assert';\nimport {describe, it, afterEach, beforeEach} from 'node:test';\n\nimport {\n  handleResponse,\n  startDaemon,\n  stopDaemon,\n} from '../../src/daemon/client.js';\nimport {isDaemonRunning} from '../../src/daemon/utils.js';\n\ndescribe('daemon client', () => {\n  describe('start/stop', () => {\n    beforeEach(async () => {\n      await stopDaemon();\n    });\n\n    afterEach(async () => {\n      await stopDaemon();\n    });\n\n    it('should start and stop daemon', async () => {\n      assert.ok(!isDaemonRunning(), 'Daemon should not be running initially');\n\n      await startDaemon();\n      assert.ok(isDaemonRunning(), 'Daemon should be running after start');\n\n      await stopDaemon();\n      assert.ok(!isDaemonRunning(), 'Daemon should not be running after stop');\n    });\n\n    it('should handle starting daemon when already running', async () => {\n      await startDaemon();\n      assert.ok(isDaemonRunning(), 'Daemon should be running');\n\n      // Starting again should be a no-op\n      await startDaemon();\n      assert.ok(isDaemonRunning(), 'Daemon should still be running');\n    });\n\n    it('should handle stopping daemon when not running', async () => {\n      assert.ok(!isDaemonRunning(), 'Daemon should not be running initially');\n\n      // Stopping when not running should be a no-op\n      await stopDaemon();\n      assert.ok(!isDaemonRunning(), 'Daemon should still not be running');\n    });\n  });\n\n  describe('parsing', () => {\n    it('handles MCP response with text format', async () => {\n      const textResponse = {content: [{type: 'text' as const, text: 'test'}]};\n      assert.strictEqual(await handleResponse(textResponse, 'md'), 'test');\n    });\n\n    it('handles JSON response', async () => {\n      const jsonResponse = {\n        content: [],\n        structuredContent: {\n          test: 'data',\n          number: 123,\n        },\n      };\n      assert.strictEqual(\n        await handleResponse(jsonResponse, 'json'),\n        JSON.stringify(jsonResponse.structuredContent),\n      );\n    });\n\n    it('handles error response when isError is true', async () => {\n      const errorResponse = {\n        isError: true,\n        content: [{type: 'text' as const, text: 'Something went wrong'}],\n      };\n      assert.strictEqual(\n        await handleResponse(errorResponse, 'md'),\n        JSON.stringify(errorResponse.content),\n      );\n    });\n\n    it('handles text response when json format is requested but no structured content', async () => {\n      const textResponse = {\n        content: [{type: 'text' as const, text: 'Fall through text'}],\n      };\n      assert.deepStrictEqual(\n        await handleResponse(textResponse, 'json'),\n        JSON.stringify(['Fall through text']),\n      );\n    });\n\n    it('supports images', async () => {\n      const unsupportedContentResponse = {\n        content: [\n          {\n            type: 'image' as const,\n            data: 'base64data',\n            mimeType: 'image/png',\n          },\n        ],\n        structuredContent: {},\n      };\n      const response = await handleResponse(unsupportedContentResponse, 'md');\n      assert.ok(response.includes('.png'));\n    });\n  });\n});\n"
  },
  {
    "path": "tests/daemon/utils.test.ts",
    "content": "/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport assert from 'node:assert';\nimport {describe, it} from 'node:test';\n\nimport type {ParsedArguments} from '../../src/bin/chrome-devtools-mcp-cli-options.js';\nimport {serializeArgs} from '../../src/daemon/utils.js';\nimport type {YargsOptions} from '../../src/third_party/index.js';\n\ndescribe('serializeArgs', () => {\n  it('should ignore undefined or null values', () => {\n    const options: Record<string, YargsOptions> = {\n      foo: {},\n      bar: {},\n      baz: {},\n    };\n    const argv = {\n      foo: undefined,\n      bar: null,\n      baz: 'value',\n      _: [],\n      $0: 'test',\n    } as unknown as ParsedArguments;\n    const result = serializeArgs(options, argv);\n    assert.deepStrictEqual(result, ['--baz', 'value']);\n  });\n\n  it('should handle boolean values', () => {\n    const options: Record<string, YargsOptions> = {foo: {}, bar: {}};\n    const argv = {\n      foo: true,\n      bar: false,\n      _: [],\n      $0: 'test',\n    } as unknown as ParsedArguments;\n    const result = serializeArgs(options, argv);\n    assert.deepStrictEqual(result, ['--foo', '--no-bar']);\n  });\n\n  it('should handle array values', () => {\n    const options: Record<string, YargsOptions> = {foo: {}};\n    const argv = {\n      foo: ['val1', 'val2'],\n      _: [],\n      $0: 'test',\n    } as unknown as ParsedArguments;\n    const result = serializeArgs(options, argv);\n    assert.deepStrictEqual(result, ['--foo', 'val1', '--foo', 'val2']);\n  });\n\n  it('should handle primitive values', () => {\n    const options: Record<string, YargsOptions> = {foo: {}, bar: {}};\n    const argv = {\n      foo: 'string',\n      bar: 42,\n      _: [],\n      $0: 'test',\n    } as unknown as ParsedArguments;\n    const result = serializeArgs(options, argv);\n    assert.deepStrictEqual(result, ['--foo', 'string', '--bar', '42']);\n  });\n\n  it('should convert camelCase keys to kebab-case', () => {\n    const options: Record<string, YargsOptions> = {\n      camelCaseKey: {},\n      anotherKey: {},\n    };\n    const argv = {\n      camelCaseKey: 'value1',\n      anotherKey: true,\n      _: [],\n      $0: 'test',\n    } as unknown as ParsedArguments;\n    const result = serializeArgs(options, argv);\n    assert.deepStrictEqual(result, [\n      '--camel-case-key',\n      'value1',\n      '--another-key',\n    ]);\n  });\n});\n"
  },
  {
    "path": "tests/e2e/chrome-devtools.test.ts",
    "content": "/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport assert from 'node:assert';\nimport {spawn} from 'node:child_process';\nimport path from 'node:path';\nimport {describe, it, afterEach, beforeEach} from 'node:test';\n\nconst CLI_PATH = path.resolve('build/src/bin/chrome-devtools.js');\n\nasync function runCli(\n  args: string[],\n): Promise<{status: number | null; stdout: string; stderr: string}> {\n  return new Promise((resolve, reject) => {\n    const child = spawn('node', [CLI_PATH, ...args]);\n    let stdout = '';\n    let stderr = '';\n    child.stdout.on('data', chunk => {\n      stdout += chunk;\n      process.stdout.write(chunk);\n    });\n    child.stderr.on('data', chunk => {\n      stderr += chunk;\n      process.stderr.write(chunk);\n    });\n    child.on('close', status => resolve({status, stdout, stderr}));\n    child.on('error', reject);\n  });\n}\n\ndescribe('chrome-devtools', () => {\n  async function assertDaemonIsNotRunning() {\n    const result = await runCli(['status']);\n    assert.strictEqual(\n      result.stdout,\n      'chrome-devtools-mcp daemon is not running.\\n',\n    );\n  }\n\n  async function assertDaemonIsRunning() {\n    const result = await runCli(['status']);\n    assert.ok(\n      result.stdout.startsWith('chrome-devtools-mcp daemon is running.\\n'),\n      'chrome-devtools-mcp daemon is not running',\n    );\n  }\n\n  beforeEach(async () => {\n    await runCli(['stop']);\n    await assertDaemonIsNotRunning();\n  });\n\n  afterEach(async () => {\n    await runCli(['stop']);\n    await assertDaemonIsNotRunning();\n  });\n\n  it('reports daemon status correctly', async () => {\n    await assertDaemonIsNotRunning();\n\n    const startResult = await runCli(['start']);\n    assert.strictEqual(\n      startResult.status,\n      0,\n      `start command failed: ${startResult.stderr}`,\n    );\n\n    await assertDaemonIsRunning();\n  });\n\n  it('can start and stop the daemon', async () => {\n    await assertDaemonIsNotRunning();\n\n    const startResult = await runCli(['start']);\n    assert.strictEqual(\n      startResult.status,\n      0,\n      `start command failed: ${startResult.stderr}`,\n    );\n\n    await assertDaemonIsRunning();\n\n    const stopResult = await runCli(['stop']);\n    assert.strictEqual(\n      stopResult.status,\n      0,\n      `stop command failed: ${stopResult.stderr}`,\n    );\n\n    await assertDaemonIsNotRunning();\n  });\n\n  it('can invoke list_pages', async () => {\n    await assertDaemonIsNotRunning();\n\n    const startResult = await runCli(['start']);\n    assert.strictEqual(\n      startResult.status,\n      0,\n      `start command failed: ${startResult.stderr}`,\n    );\n\n    const listPagesResult = await runCli(['list_pages']);\n    assert.strictEqual(\n      listPagesResult.status,\n      0,\n      `list_pages command failed: ${listPagesResult.stderr}`,\n    );\n    assert(\n      listPagesResult.stdout.includes('about:blank'),\n      'list_pages output is unexpected',\n    );\n\n    await assertDaemonIsRunning();\n  });\n\n  it('can take screenshot', async () => {\n    const startResult = await runCli(['start']);\n    assert.strictEqual(\n      startResult.status,\n      0,\n      `start command failed: ${startResult.stderr}`,\n    );\n\n    const result = await runCli(['take_screenshot']);\n    assert.strictEqual(\n      result.status,\n      0,\n      `take_screenshot command failed: ${result.stderr}`,\n    );\n    assert(\n      result.stdout.includes('.png'),\n      'take_screenshot output is unexpected',\n    );\n  });\n\n  it('forwards disclaimers to stderr on start', async () => {\n    const result = await runCli(['start']);\n    assert.strictEqual(\n      result.status,\n      0,\n      `start command failed: ${result.stderr}`,\n    );\n    assert(\n      result.stderr.includes('chrome-devtools-mcp exposes content'),\n      'Disclaimer not found in stderr on start',\n    );\n  });\n});\n"
  },
  {
    "path": "tests/e2e/telemetry.test.ts",
    "content": "/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport assert from 'node:assert';\nimport {spawn, type ChildProcess, type SpawnOptions} from 'node:child_process';\nimport http from 'node:http';\nimport type {AddressInfo} from 'node:net';\nimport path from 'node:path';\nimport {describe, it} from 'node:test';\n\nimport type {ChromeDevToolsMcpExtension} from '../../src/telemetry/types';\n\nconst SERVER_PATH = path.resolve('build/src/bin/chrome-devtools-mcp.js');\n\ninterface MockServerContext {\n  server: http.Server;\n  port: number;\n  events: ChromeDevToolsMcpExtension[];\n  watchdogPid?: number;\n  waitForEvent: (\n    predicate: (event: ChromeDevToolsMcpExtension) => boolean,\n  ) => Promise<ChromeDevToolsMcpExtension>;\n}\n\nasync function startMockServer(): Promise<MockServerContext> {\n  const events: ChromeDevToolsMcpExtension[] = [];\n  let waitingResolvers: Array<{\n    predicate: (event: ChromeDevToolsMcpExtension) => boolean;\n    resolve: (event: ChromeDevToolsMcpExtension) => void;\n  }> = [];\n  let watchdogPid: number | undefined;\n\n  const server = http.createServer((req, res) => {\n    if (req.method === 'POST') {\n      const pidHeader = req.headers['x-watchdog-pid'];\n      if (pidHeader && !Array.isArray(pidHeader)) {\n        watchdogPid = parseInt(pidHeader, 10);\n      }\n\n      let body = '';\n      req.on('data', chunk => {\n        body += chunk.toString();\n      });\n      req.on('end', () => {\n        try {\n          const parsed = JSON.parse(body);\n          // Extract internal log events\n          if (parsed.log_event) {\n            for (const logEvent of parsed.log_event) {\n              if (logEvent.source_extension_json) {\n                const ext = JSON.parse(\n                  logEvent.source_extension_json,\n                ) as ChromeDevToolsMcpExtension;\n                events.push(ext);\n\n                // Check if any waiters are satisfied\n                waitingResolvers = waitingResolvers.filter(\n                  ({predicate, resolve}) => {\n                    if (predicate(ext)) {\n                      resolve(ext);\n                      return false;\n                    }\n                    return true;\n                  },\n                );\n              }\n            }\n          }\n        } catch (err) {\n          console.error('Failed to parse mock server request', err);\n        }\n        res.writeHead(200, {'Content-Type': 'application/json'});\n        res.end(JSON.stringify({next_request_wait_millis: 100}));\n      });\n    } else {\n      res.writeHead(404);\n      res.end();\n    }\n  });\n\n  await new Promise<void>(resolve => {\n    server.listen(0, '127.0.0.1', () => resolve());\n  });\n\n  const address = server.address() as AddressInfo;\n  return {\n    server,\n    port: address.port,\n    events,\n    get watchdogPid() {\n      return watchdogPid;\n    },\n    waitForEvent: predicate => {\n      const existing = events.find(predicate);\n      if (existing) {\n        return Promise.resolve(existing);\n      }\n\n      return new Promise(resolve => {\n        waitingResolvers.push({predicate, resolve});\n      });\n    },\n  };\n}\n\ninterface TestContext {\n  process?: ChildProcess;\n  mockServer?: MockServerContext;\n}\n\nfunction isProcessAlive(pid: number): boolean {\n  try {\n    process.kill(pid, 0);\n    return true;\n  } catch {\n    return false;\n  }\n}\n\nasync function waitForProcessExit(\n  pid: number,\n  timeoutMs = 5000,\n): Promise<void> {\n  const startTime = Date.now();\n  while (Date.now() - startTime < timeoutMs) {\n    if (!isProcessAlive(pid)) {\n      return;\n    }\n    await new Promise(resolve => setTimeout(resolve, 50));\n  }\n  throw new Error(`Timeout waiting for process ${pid} to exit`);\n}\n\nfunction cleanupTest(ctx: TestContext): void {\n  // Kill Main Process\n  if (ctx.process && ctx.process.exitCode === null) {\n    try {\n      ctx.process.kill('SIGKILL');\n    } catch {\n      // ignore\n    }\n  }\n  // Kill Watchdog Process\n  if (ctx.mockServer?.watchdogPid) {\n    try {\n      process.kill(ctx.mockServer.watchdogPid, 'SIGKILL');\n    } catch {\n      // ignore\n    }\n  }\n  // Stop Mock Server\n  if (ctx.mockServer) {\n    ctx.mockServer.server.close();\n  }\n}\n\ndescribe('Telemetry E2E', () => {\n  async function runTelemetryTest(\n    killFn: (ctx: TestContext) => void,\n    spawnOptions?: SpawnOptions,\n  ): Promise<void> {\n    const mockContext = await startMockServer();\n    const ctx: TestContext = {\n      mockServer: mockContext,\n    };\n\n    try {\n      ctx.process = spawn(\n        process.execPath,\n        [\n          SERVER_PATH,\n          '--usage-statistics',\n          '--headless',\n          `--clearcutEndpoint=http://127.0.0.1:${mockContext.port}`,\n          '--clearcutForceFlushIntervalMs=10',\n          '--clearcutIncludePidHeader',\n        ],\n        {\n          stdio: ['pipe', 'pipe', 'pipe'],\n          env: {\n            ...process.env,\n            CI: undefined,\n            CHROME_DEVTOOLS_MCP_NO_USAGE_STATISTICS: undefined,\n          },\n          ...spawnOptions,\n        },\n      );\n\n      const startEvent = await Promise.race([\n        mockContext.waitForEvent(e => e.server_start !== undefined),\n        new Promise((_, reject) =>\n          setTimeout(\n            () => reject(new Error('Timeout waiting for server_start')),\n            10000,\n          ),\n        ),\n      ]);\n      assert.ok(startEvent, 'server_start event not received');\n\n      // Now that we received an event, we should have the Watchdog PID\n      const watchdogPid = mockContext.watchdogPid;\n      assert.ok(watchdogPid, 'Watchdog PID not captured from headers');\n\n      // Assert Watchdog is actually running\n      assert.strictEqual(\n        isProcessAlive(watchdogPid),\n        true,\n        'Watchdog process should be running',\n      );\n\n      // Trigger shutdown\n      killFn(ctx);\n\n      // Verify shutdown event\n      const shutdownEvent = await Promise.race([\n        mockContext.waitForEvent(e => e.server_shutdown !== undefined),\n        new Promise((_, reject) =>\n          setTimeout(\n            () => reject(new Error('Timeout waiting for server_shutdown')),\n            10000,\n          ),\n        ),\n      ]);\n      assert.ok(shutdownEvent, 'server_shutdown event not received');\n\n      // Wait for Watchdog to exit naturally\n      await waitForProcessExit(watchdogPid);\n    } finally {\n      cleanupTest(ctx);\n    }\n  }\n\n  it('handles SIGKILL', () =>\n    runTelemetryTest(ctx => {\n      ctx.process!.kill('SIGKILL');\n    }));\n\n  it('handles SIGTERM', () =>\n    runTelemetryTest(ctx => {\n      ctx.process!.kill('SIGTERM');\n    }));\n\n  it(\n    'handles POSIX process group SIGTERM',\n    {skip: process.platform === 'win32'},\n    () =>\n      runTelemetryTest(\n        ctx => {\n          process.kill(-ctx.process!.pid!, 'SIGTERM');\n        },\n        {detached: true},\n      ),\n  );\n});\n"
  },
  {
    "path": "tests/formatters/ConsoleFormatter.test.js.snapshot",
    "content": "exports[`ConsoleFormatter > toString/toJSON > formats a console.log message toJSON 1`] = `\n{\n  \"type\": \"log\",\n  \"text\": \"Hello, world!\",\n  \"argsCount\": 0,\n  \"id\": 1\n}\n`;\n\nexports[`ConsoleFormatter > toString/toJSON > formats a console.log message toString 1`] = `\nmsgid=1 [log] Hello, world! (0 args)\n`;\n\nexports[`ConsoleFormatter > toString/toJSON > formats a console.log message with multiple arguments toJSON 1`] = `\n{\n  \"type\": \"log\",\n  \"text\": \"Processing file:\",\n  \"argsCount\": 2,\n  \"id\": 1\n}\n`;\n\nexports[`ConsoleFormatter > toString/toJSON > formats a console.log message with multiple arguments toString 1`] = `\nmsgid=1 [log] Processing file: (2 args)\n`;\n\nexports[`ConsoleFormatter > toString/toJSON > formats a console.log message with one argument toJSON 1`] = `\n{\n  \"type\": \"log\",\n  \"text\": \"Processing file:\",\n  \"argsCount\": 1,\n  \"id\": 1\n}\n`;\n\nexports[`ConsoleFormatter > toString/toJSON > formats a console.log message with one argument toString 1`] = `\nmsgid=1 [log] Processing file: (1 args)\n`;\n\nexports[`ConsoleFormatter > toString/toJSON > formats an UncaughtError toJSON 1`] = `\n{\n  \"type\": \"error\",\n  \"text\": \"Uncaught TypeError: Cannot read properties of undefined\",\n  \"argsCount\": 0,\n  \"id\": 1\n}\n`;\n\nexports[`ConsoleFormatter > toString/toJSON > formats an UncaughtError toString 1`] = `\nmsgid=1 [error] Uncaught TypeError: Cannot read properties of undefined (0 args)\n`;\n\nexports[`ConsoleFormatter > toStringDetailed/toJSONDetailed > does not show call frames with ignore listed scripts toJSONDetailed 1`] = `\n{\n  \"id\": 12,\n  \"type\": \"log\",\n  \"text\": \"Hello stack trace!\",\n  \"argsCount\": 0,\n  \"args\": [],\n  \"stackTrace\": \"at foo (foo.ts:10:2)\\\\nat bar (foo.ts:20:2)\\\\nNote: line and column numbers use 1-based indexing\"\n}\n`;\n\nexports[`ConsoleFormatter > toStringDetailed/toJSONDetailed > does not show call frames with ignore listed scripts toStringDetailed 1`] = `\nID: 12\nMessage: log> Hello stack trace!\n### Stack trace\nat foo (foo.ts:10:2)\nat bar (foo.ts:20:2)\nNote: line and column numbers use 1-based indexing\n`;\n\nexports[`ConsoleFormatter > toStringDetailed/toJSONDetailed > does not show fragments where all frames are ignore listed toJSONDetailed 1`] = `\n{\n  \"id\": 13,\n  \"type\": \"log\",\n  \"text\": \"Hello stack trace!\",\n  \"argsCount\": 0,\n  \"args\": [],\n  \"stackTrace\": \"at foo (foo.ts:10:2)\\\\n--- await ------------------------------\\\\nat bar (foo.ts:20:2)\\\\nNote: line and column numbers use 1-based indexing\"\n}\n`;\n\nexports[`ConsoleFormatter > toStringDetailed/toJSONDetailed > does not show fragments where all frames are ignore listed toStringDetailed 1`] = `\nID: 13\nMessage: log> Hello stack trace!\n### Stack trace\nat foo (foo.ts:10:2)\n--- await ------------------------------\nat bar (foo.ts:20:2)\nNote: line and column numbers use 1-based indexing\n`;\n\nexports[`ConsoleFormatter > toStringDetailed/toJSONDetailed > formats a console message with a stack trace toJSONDetailed 1`] = `\n{\n  \"id\": 1,\n  \"type\": \"log\",\n  \"text\": \"Hello stack trace!\",\n  \"argsCount\": 0,\n  \"args\": [],\n  \"stackTrace\": \"at foo (foo.ts:10:2)\\\\nat bar (foo.ts:20:2)\\\\n--- setTimeout -------------------------\\\\nat schedule (util.ts:5:2)\\\\nNote: line and column numbers use 1-based indexing\"\n}\n`;\n\nexports[`ConsoleFormatter > toStringDetailed/toJSONDetailed > formats a console message with a stack trace toStringDetailed 1`] = `\nID: 1\nMessage: log> Hello stack trace!\n### Stack trace\nat foo (foo.ts:10:2)\nat bar (foo.ts:20:2)\n--- setTimeout -------------------------\nat schedule (util.ts:5:2)\nNote: line and column numbers use 1-based indexing\n`;\n\nexports[`ConsoleFormatter > toStringDetailed/toJSONDetailed > formats a console message with an Error object argument toJSONDetailed 1`] = `\n{\n  \"id\": 8,\n  \"type\": \"log\",\n  \"text\": \"JSHandle@error\",\n  \"argsCount\": 1,\n  \"args\": [\n    \"TypeError: Cannot read properties of undefined\\\\nat foo (foo.ts:10:2)\\\\nat bar (foo.ts:20:2)\\\\nNote: line and column numbers use 1-based indexing\"\n  ]\n}\n`;\n\nexports[`ConsoleFormatter > toStringDetailed/toJSONDetailed > formats a console message with an Error object argument toStringDetailed 1`] = `\nID: 8\nMessage: log> JSHandle@error\n### Arguments\nArg #0: TypeError: Cannot read properties of undefined\nat foo (foo.ts:10:2)\nat bar (foo.ts:20:2)\nNote: line and column numbers use 1-based indexing\n`;\n\nexports[`ConsoleFormatter > toStringDetailed/toJSONDetailed > formats a console message with an Error object with cause toJSONDetailed 1`] = `\n{\n  \"id\": 9,\n  \"type\": \"log\",\n  \"text\": \"JSHandle@error\",\n  \"argsCount\": 1,\n  \"args\": [\n    \"AppError: Compute failed\\\\nat foo (foo.ts:10:2)\\\\nat bar (foo.ts:20:2)\\\\nCaused by: TypeError: Cannot read properties of undefined\\\\nat compute (library.js:5:10)\\\\nNote: line and column numbers use 1-based indexing\"\n  ]\n}\n`;\n\nexports[`ConsoleFormatter > toStringDetailed/toJSONDetailed > formats a console message with an Error object with cause toStringDetailed 1`] = `\nID: 9\nMessage: log> JSHandle@error\n### Arguments\nArg #0: AppError: Compute failed\nat foo (foo.ts:10:2)\nat bar (foo.ts:20:2)\nCaused by: TypeError: Cannot read properties of undefined\nat compute (library.js:5:10)\nNote: line and column numbers use 1-based indexing\n`;\n\nexports[`ConsoleFormatter > toStringDetailed/toJSONDetailed > formats a console.error message toJSONDetailed 1`] = `\n{\n  \"id\": 1,\n  \"type\": \"error\",\n  \"text\": \"Something went wrong\",\n  \"argsCount\": 0,\n  \"args\": []\n}\n`;\n\nexports[`ConsoleFormatter > toStringDetailed/toJSONDetailed > formats a console.error message toStringDetailed 1`] = `\nID: 1\nMessage: error> Something went wrong\n`;\n\nexports[`ConsoleFormatter > toStringDetailed/toJSONDetailed > formats a console.log message toJSONDetailed 1`] = `\n{\n  \"id\": 1,\n  \"type\": \"log\",\n  \"text\": \"Hello, world!\",\n  \"argsCount\": 0,\n  \"args\": []\n}\n`;\n\nexports[`ConsoleFormatter > toStringDetailed/toJSONDetailed > formats a console.log message toStringDetailed 1`] = `\nID: 1\nMessage: log> Hello, world!\n`;\n\nexports[`ConsoleFormatter > toStringDetailed/toJSONDetailed > formats a console.log message with multiple arguments toJSONDetailed 1`] = `\n{\n  \"id\": 1,\n  \"type\": \"log\",\n  \"text\": \"Processing file:\",\n  \"argsCount\": 2,\n  \"args\": [\n    \"file.txt\",\n    \"another file\"\n  ]\n}\n`;\n\nexports[`ConsoleFormatter > toStringDetailed/toJSONDetailed > formats a console.log message with multiple arguments toStringDetailed 1`] = `\nID: 1\nMessage: log> Processing file:\n### Arguments\nArg #0: file.txt\nArg #1: another file\n`;\n\nexports[`ConsoleFormatter > toStringDetailed/toJSONDetailed > formats a console.log message with one argument toJSONDetailed 1`] = `\n{\n  \"id\": 1,\n  \"type\": \"log\",\n  \"text\": \"Processing file:\",\n  \"argsCount\": 1,\n  \"args\": [\n    \"file.txt\"\n  ]\n}\n`;\n\nexports[`ConsoleFormatter > toStringDetailed/toJSONDetailed > formats a console.log message with one argument toStringDetailed 1`] = `\nID: 1\nMessage: log> Processing file:\n### Arguments\nArg #0: file.txt\n`;\n\nexports[`ConsoleFormatter > toStringDetailed/toJSONDetailed > formats an UncaughtError with a stack trace and a cause toJSONDetailed 1`] = `\n{\n  \"id\": 10,\n  \"type\": \"error\",\n  \"text\": \"Uncaught TypeError: Cannot read properties of undefined\",\n  \"argsCount\": 0,\n  \"args\": [],\n  \"stackTrace\": \"at foo (foo.ts:10:2)\\\\nat bar (foo.ts:20:2)\\\\n--- setTimeout -------------------------\\\\nat schedule (util.ts:5:2)\\\\nCaused by: TypeError: Cannot read properties of undefined\\\\nat compute (library.js:5:8)\\\\nNote: line and column numbers use 1-based indexing\"\n}\n`;\n\nexports[`ConsoleFormatter > toStringDetailed/toJSONDetailed > formats an UncaughtError with a stack trace and a cause toStringDetailed 1`] = `\nID: 10\nMessage: error> Uncaught TypeError: Cannot read properties of undefined\n### Stack trace\nat foo (foo.ts:10:2)\nat bar (foo.ts:20:2)\n--- setTimeout -------------------------\nat schedule (util.ts:5:2)\nCaused by: TypeError: Cannot read properties of undefined\nat compute (library.js:5:8)\nNote: line and column numbers use 1-based indexing\n`;\n\nexports[`ConsoleFormatter > toStringDetailed/toJSONDetailed > formats an UncaughtError with a stack trace toJSONDetailed 1`] = `\n{\n  \"id\": 7,\n  \"type\": \"error\",\n  \"text\": \"Uncaught TypeError: Cannot read properties of undefined\",\n  \"argsCount\": 0,\n  \"args\": [],\n  \"stackTrace\": \"at foo (foo.ts:10:2)\\\\nat bar (foo.ts:20:2)\\\\n--- setTimeout -------------------------\\\\nat schedule (util.ts:5:2)\\\\nNote: line and column numbers use 1-based indexing\"\n}\n`;\n\nexports[`ConsoleFormatter > toStringDetailed/toJSONDetailed > formats an UncaughtError with a stack trace toStringDetailed 1`] = `\nID: 7\nMessage: error> Uncaught TypeError: Cannot read properties of undefined\n### Stack trace\nat foo (foo.ts:10:2)\nat bar (foo.ts:20:2)\n--- setTimeout -------------------------\nat schedule (util.ts:5:2)\nNote: line and column numbers use 1-based indexing\n`;\n\nexports[`ConsoleFormatter > toStringDetailed/toJSONDetailed > handles \\\"Execution context is not available\\\" error in args toJSONDetailed 1`] = `\n{\n  \"id\": 6,\n  \"type\": \"log\",\n  \"text\": \"Processing file:\",\n  \"argsCount\": 1,\n  \"args\": [\n    \"<error: Argument 0 is no longer available>\"\n  ]\n}\n`;\n\nexports[`ConsoleFormatter > toStringDetailed/toJSONDetailed > handles \\\"Execution context is not available\\\" error in args toStringDetailed 1`] = `\nID: 6\nMessage: log> Processing file:\n### Arguments\nArg #0: <error: Argument 0 is no longer available>\n`;\n\nexports[`ConsoleFormatter > toStringDetailed/toJSONDetailed > limits the number lines for a stack trace toJSONDetailed 1`] = `\n{\n  \"id\": 11,\n  \"type\": \"log\",\n  \"text\": \"Hello stack trace!\",\n  \"argsCount\": 0,\n  \"args\": [],\n  \"stackTrace\": \"at fn0 (main.js:0:0)\\\\nat fn1 (main.js:1:1)\\\\nat fn2 (main.js:2:2)\\\\nat fn3 (main.js:3:3)\\\\nat fn4 (main.js:4:4)\\\\nat fn5 (main.js:5:5)\\\\nat fn6 (main.js:6:6)\\\\nat fn7 (main.js:7:7)\\\\nat fn8 (main.js:8:8)\\\\nat fn9 (main.js:9:9)\\\\nat fn10 (main.js:10:10)\\\\nat fn11 (main.js:11:11)\\\\nat fn12 (main.js:12:12)\\\\nat fn13 (main.js:13:13)\\\\nat fn14 (main.js:14:14)\\\\nat fn15 (main.js:15:15)\\\\nat fn16 (main.js:16:16)\\\\nat fn17 (main.js:17:17)\\\\nat fn18 (main.js:18:18)\\\\nat fn19 (main.js:19:19)\\\\nat fn20 (main.js:20:20)\\\\nat fn21 (main.js:21:21)\\\\nat fn22 (main.js:22:22)\\\\nat fn23 (main.js:23:23)\\\\nat fn24 (main.js:24:24)\\\\nat fn25 (main.js:25:25)\\\\nat fn26 (main.js:26:26)\\\\nat fn27 (main.js:27:27)\\\\nat fn28 (main.js:28:28)\\\\nat fn29 (main.js:29:29)\\\\nat fn30 (main.js:30:30)\\\\nat fn31 (main.js:31:31)\\\\nat fn32 (main.js:32:32)\\\\nat fn33 (main.js:33:33)\\\\nat fn34 (main.js:34:34)\\\\nat fn35 (main.js:35:35)\\\\nat fn36 (main.js:36:36)\\\\nat fn37 (main.js:37:37)\\\\nat fn38 (main.js:38:38)\\\\nat fn39 (main.js:39:39)\\\\nat fn40 (main.js:40:40)\\\\nat fn41 (main.js:41:41)\\\\nat fn42 (main.js:42:42)\\\\nat fn43 (main.js:43:43)\\\\nat fn44 (main.js:44:44)\\\\nat fn45 (main.js:45:45)\\\\nat fn46 (main.js:46:46)\\\\nat fn47 (main.js:47:47)\\\\nat fn48 (main.js:48:48)\\\\nat fn49 (main.js:49:49)\\\\n... and 50 more frames\\\\nNote: line and column numbers use 1-based indexing\"\n}\n`;\n\nexports[`ConsoleFormatter > toStringDetailed/toJSONDetailed > limits the number lines for a stack trace toStringDetailed 1`] = `\nID: 11\nMessage: log> Hello stack trace!\n### Stack trace\nat fn0 (main.js:0:0)\nat fn1 (main.js:1:1)\nat fn2 (main.js:2:2)\nat fn3 (main.js:3:3)\nat fn4 (main.js:4:4)\nat fn5 (main.js:5:5)\nat fn6 (main.js:6:6)\nat fn7 (main.js:7:7)\nat fn8 (main.js:8:8)\nat fn9 (main.js:9:9)\nat fn10 (main.js:10:10)\nat fn11 (main.js:11:11)\nat fn12 (main.js:12:12)\nat fn13 (main.js:13:13)\nat fn14 (main.js:14:14)\nat fn15 (main.js:15:15)\nat fn16 (main.js:16:16)\nat fn17 (main.js:17:17)\nat fn18 (main.js:18:18)\nat fn19 (main.js:19:19)\nat fn20 (main.js:20:20)\nat fn21 (main.js:21:21)\nat fn22 (main.js:22:22)\nat fn23 (main.js:23:23)\nat fn24 (main.js:24:24)\nat fn25 (main.js:25:25)\nat fn26 (main.js:26:26)\nat fn27 (main.js:27:27)\nat fn28 (main.js:28:28)\nat fn29 (main.js:29:29)\nat fn30 (main.js:30:30)\nat fn31 (main.js:31:31)\nat fn32 (main.js:32:32)\nat fn33 (main.js:33:33)\nat fn34 (main.js:34:34)\nat fn35 (main.js:35:35)\nat fn36 (main.js:36:36)\nat fn37 (main.js:37:37)\nat fn38 (main.js:38:38)\nat fn39 (main.js:39:39)\nat fn40 (main.js:40:40)\nat fn41 (main.js:41:41)\nat fn42 (main.js:42:42)\nat fn43 (main.js:43:43)\nat fn44 (main.js:44:44)\nat fn45 (main.js:45:45)\nat fn46 (main.js:46:46)\nat fn47 (main.js:47:47)\nat fn48 (main.js:48:48)\nat fn49 (main.js:49:49)\n... and 50 more frames\nNote: line and column numbers use 1-based indexing\n`;\n"
  },
  {
    "path": "tests/formatters/ConsoleFormatter.test.ts",
    "content": "/**\n * @license\n * Copyright 2025 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport {describe, it} from 'node:test';\n\nimport {SymbolizedError} from '../../src/DevtoolsUtils.js';\nimport {ConsoleFormatter} from '../../src/formatters/ConsoleFormatter.js';\nimport {UncaughtError} from '../../src/PageCollector.js';\nimport type {ConsoleMessage, Protocol} from '../../src/third_party/index.js';\nimport type {DevTools} from '../../src/third_party/index.js';\n\ninterface MockConsoleMessage {\n  type: () => string;\n  text: () => string;\n  args: () => Array<{\n    jsonValue: () => Promise<unknown>;\n    remoteObject: () => Protocol.Runtime.RemoteObject;\n  }>;\n  stackTrace?: DevTools.StackTrace.StackTrace.StackTrace;\n}\n\nconst createMockMessage = (\n  data: Partial<MockConsoleMessage> = {},\n): ConsoleMessage => {\n  return {\n    type: () => data.type?.() ?? 'log',\n    text: () => data.text?.() ?? '',\n    args: () => data.args?.() ?? [],\n    ...data,\n  } as unknown as ConsoleMessage;\n};\n\nfunction formatterTestConcise(\n  label: string,\n  setup: (t: it.TestContext) => Promise<ConsoleFormatter>,\n) {\n  it(label + ' toString', async t => {\n    const formatter = await setup(t);\n    t.assert.snapshot?.(formatter.toString());\n  });\n  it(label + ' toJSON', async t => {\n    const formatter = await setup(t);\n    t.assert.snapshot?.(JSON.stringify(formatter.toJSON(), null, 2));\n  });\n}\n\nfunction formatterTestDetailed(\n  label: string,\n  setup: (t: it.TestContext) => Promise<ConsoleFormatter>,\n) {\n  it(label + ' toStringDetailed', async t => {\n    const formatter = await setup(t);\n    t.assert.snapshot?.(formatter.toStringDetailed());\n  });\n  it(label + ' toJSONDetailed', async t => {\n    const formatter = await setup(t);\n    t.assert.snapshot?.(JSON.stringify(formatter.toJSONDetailed(), null, 2));\n  });\n}\n\ndescribe('ConsoleFormatter', () => {\n  describe('toString/toJSON', () => {\n    formatterTestConcise('formats a console.log message', async () => {\n      const message = createMockMessage({\n        type: () => 'log',\n        text: () => 'Hello, world!',\n      });\n      return await ConsoleFormatter.from(message, {id: 1});\n    });\n\n    formatterTestConcise(\n      'formats a console.log message with one argument',\n      async () => {\n        const message = createMockMessage({\n          type: () => 'log',\n          text: () => 'Processing file:',\n          args: () => [\n            {\n              jsonValue: async () => 'file.txt',\n              remoteObject: () => ({type: 'string'}),\n            },\n          ],\n        });\n        return await ConsoleFormatter.from(message, {id: 1});\n      },\n    );\n\n    formatterTestConcise(\n      'formats a console.log message with multiple arguments',\n      async () => {\n        const message = createMockMessage({\n          type: () => 'log',\n          text: () => 'Processing file:',\n          args: () => [\n            {\n              jsonValue: async () => 'file.txt',\n              remoteObject: () => ({type: 'string'}),\n            },\n            {\n              jsonValue: async () => 'another file',\n              remoteObject: () => ({type: 'string'}),\n            },\n          ],\n        });\n        return await ConsoleFormatter.from(message, {id: 1});\n      },\n    );\n\n    formatterTestConcise('formats an UncaughtError', async () => {\n      const error = new UncaughtError(\n        {\n          exceptionId: 1,\n          lineNumber: 0,\n          columnNumber: 5,\n          exception: {\n            type: 'object',\n            description: 'TypeError: Cannot read properties of undefined',\n          },\n          text: 'Uncaught',\n        },\n        '<mock target ID>',\n      );\n      return await ConsoleFormatter.from(error, {id: 1});\n    });\n  });\n\n  describe('toStringDetailed/toJSONDetailed', () => {\n    formatterTestDetailed('formats a console.log message', async () => {\n      const message = createMockMessage({\n        type: () => 'log',\n        text: () => 'Hello, world!',\n      });\n      return await ConsoleFormatter.from(message, {\n        id: 1,\n        fetchDetailedData: true,\n      });\n    });\n\n    formatterTestDetailed(\n      'formats a console.log message with one argument',\n      async () => {\n        const message = createMockMessage({\n          type: () => 'log',\n          text: () => 'Processing file:',\n          args: () => [\n            {\n              jsonValue: async () => 'file.txt',\n              remoteObject: () => ({type: 'string'}),\n            },\n          ],\n        });\n        return await ConsoleFormatter.from(message, {\n          id: 1,\n          fetchDetailedData: true,\n        });\n      },\n    );\n\n    formatterTestDetailed(\n      'formats a console.log message with multiple arguments',\n      async () => {\n        const message = createMockMessage({\n          type: () => 'log',\n          text: () => 'Processing file:',\n          args: () => [\n            {\n              jsonValue: async () => 'file.txt',\n              remoteObject: () => ({type: 'string'}),\n            },\n            {\n              jsonValue: async () => 'another file',\n              remoteObject: () => ({type: 'string'}),\n            },\n          ],\n        });\n        return await ConsoleFormatter.from(message, {\n          id: 1,\n          fetchDetailedData: true,\n        });\n      },\n    );\n\n    formatterTestDetailed('formats a console.error message', async () => {\n      const message = createMockMessage({\n        type: () => 'error',\n        text: () => 'Something went wrong',\n      });\n      return await ConsoleFormatter.from(message, {\n        id: 1,\n        fetchDetailedData: true,\n      });\n    });\n\n    formatterTestDetailed(\n      'formats a console message with a stack trace',\n      async () => {\n        const message = createMockMessage({\n          type: () => 'log',\n          text: () => 'Hello stack trace!',\n        });\n        const stackTrace = {\n          syncFragment: {\n            frames: [\n              {\n                line: 10,\n                column: 2,\n                url: 'foo.ts',\n                name: 'foo',\n              },\n              {\n                line: 20,\n                column: 2,\n                url: 'foo.ts',\n                name: 'bar',\n              },\n            ],\n          },\n          asyncFragments: [\n            {\n              description: 'setTimeout',\n              frames: [\n                {\n                  line: 5,\n                  column: 2,\n                  url: 'util.ts',\n                  name: 'schedule',\n                },\n              ],\n            },\n          ],\n        } as unknown as DevTools.StackTrace.StackTrace.StackTrace;\n\n        return await ConsoleFormatter.from(message, {\n          id: 1,\n          resolvedStackTraceForTesting: stackTrace,\n        });\n      },\n    );\n\n    formatterTestDetailed(\n      'handles \"Execution context is not available\" error in args',\n      async () => {\n        const message = createMockMessage({\n          type: () => 'log',\n          text: () => 'Processing file:',\n          args: () => [\n            {\n              jsonValue: async () => {\n                throw new Error('Execution context is not available');\n              },\n              remoteObject: () => ({type: 'string'}),\n            },\n          ],\n        });\n        return await ConsoleFormatter.from(message, {\n          id: 6,\n          fetchDetailedData: true,\n        });\n      },\n    );\n\n    formatterTestDetailed(\n      'formats an UncaughtError with a stack trace',\n      async () => {\n        const stackTrace = {\n          syncFragment: {\n            frames: [\n              {\n                line: 10,\n                column: 2,\n                url: 'foo.ts',\n                name: 'foo',\n              },\n              {\n                line: 20,\n                column: 2,\n                url: 'foo.ts',\n                name: 'bar',\n              },\n            ],\n          },\n          asyncFragments: [\n            {\n              description: 'setTimeout',\n              frames: [\n                {\n                  line: 5,\n                  column: 2,\n                  url: 'util.ts',\n                  name: 'schedule',\n                },\n              ],\n            },\n          ],\n        } as unknown as DevTools.StackTrace.StackTrace.StackTrace;\n        const error = new UncaughtError(\n          {\n            exceptionId: 1,\n            lineNumber: 0,\n            columnNumber: 5,\n            exception: {\n              type: 'object',\n              description: 'TypeError: Cannot read properties of undefined',\n            },\n            text: 'Uncaught',\n          },\n          '<mock target ID>',\n        );\n\n        return await ConsoleFormatter.from(error, {\n          id: 7,\n          resolvedStackTraceForTesting: stackTrace,\n        });\n      },\n    );\n\n    formatterTestDetailed(\n      'formats a console message with an Error object argument',\n      async () => {\n        const message = createMockMessage({\n          type: () => 'log',\n          text: () => 'JSHandle@error',\n        });\n        const stackTrace = {\n          syncFragment: {\n            frames: [\n              {\n                line: 10,\n                column: 2,\n                url: 'foo.ts',\n                name: 'foo',\n              },\n              {\n                line: 20,\n                column: 2,\n                url: 'foo.ts',\n                name: 'bar',\n              },\n            ],\n          },\n          asyncFragments: [],\n        } as unknown as DevTools.StackTrace.StackTrace.StackTrace;\n        const error = SymbolizedError.createForTesting(\n          'TypeError: Cannot read properties of undefined',\n          stackTrace,\n        );\n\n        return await ConsoleFormatter.from(message, {\n          id: 8,\n          resolvedArgsForTesting: [error],\n        });\n      },\n    );\n\n    formatterTestDetailed(\n      'formats a console message with an Error object with cause',\n      async () => {\n        const message = createMockMessage({\n          type: () => 'log',\n          text: () => 'JSHandle@error',\n        });\n        const stackTrace = {\n          syncFragment: {\n            frames: [\n              {\n                line: 10,\n                column: 2,\n                url: 'foo.ts',\n                name: 'foo',\n              },\n              {\n                line: 20,\n                column: 2,\n                url: 'foo.ts',\n                name: 'bar',\n              },\n            ],\n          },\n          asyncFragments: [],\n        } as unknown as DevTools.StackTrace.StackTrace.StackTrace;\n        const error = SymbolizedError.createForTesting(\n          'AppError: Compute failed',\n          stackTrace,\n          SymbolizedError.createForTesting(\n            'TypeError: Cannot read properties of undefined',\n            {\n              syncFragment: {\n                frames: [\n                  {\n                    line: 5,\n                    column: 10,\n                    url: 'library.js',\n                    name: 'compute',\n                  },\n                ],\n              },\n              asyncFragments: [],\n            } as unknown as DevTools.StackTrace.StackTrace.StackTrace,\n          ),\n        );\n\n        return await ConsoleFormatter.from(message, {\n          id: 9,\n          resolvedArgsForTesting: [error],\n        });\n      },\n    );\n\n    formatterTestDetailed(\n      'formats an UncaughtError with a stack trace and a cause',\n      async () => {\n        const stackTrace = {\n          syncFragment: {\n            frames: [\n              {\n                line: 10,\n                column: 2,\n                url: 'foo.ts',\n                name: 'foo',\n              },\n              {\n                line: 20,\n                column: 2,\n                url: 'foo.ts',\n                name: 'bar',\n              },\n            ],\n          },\n          asyncFragments: [\n            {\n              description: 'setTimeout',\n              frames: [\n                {\n                  line: 5,\n                  column: 2,\n                  url: 'util.ts',\n                  name: 'schedule',\n                },\n              ],\n            },\n          ],\n        } as unknown as DevTools.StackTrace.StackTrace.StackTrace;\n        const error = new UncaughtError(\n          {\n            exceptionId: 1,\n            lineNumber: 0,\n            columnNumber: 5,\n            exception: {\n              type: 'object',\n              description: 'TypeError: Cannot read properties of undefined',\n            },\n            text: 'Uncaught',\n          },\n          '<mock target ID>',\n        );\n        const cause = SymbolizedError.createForTesting(\n          'TypeError: Cannot read properties of undefined',\n          {\n            syncFragment: {\n              frames: [\n                {\n                  line: 5,\n                  column: 8,\n                  url: 'library.js',\n                  name: 'compute',\n                },\n              ],\n            },\n            asyncFragments: [],\n          } as unknown as DevTools.StackTrace.StackTrace.StackTrace,\n        );\n\n        return await ConsoleFormatter.from(error, {\n          id: 10,\n          resolvedStackTraceForTesting: stackTrace,\n          resolvedCauseForTesting: cause,\n        });\n      },\n    );\n\n    formatterTestDetailed(\n      'limits the number lines for a stack trace',\n      async () => {\n        const message = createMockMessage({\n          type: () => 'log',\n          text: () => 'Hello stack trace!',\n        });\n        const frames: DevTools.StackTrace.StackTrace.Frame[] = [];\n        for (let i = 0; i < 100; ++i) {\n          frames.push({\n            line: i,\n            column: i,\n            url: 'main.js',\n            name: `fn${i}`,\n          });\n        }\n        const stackTrace = {\n          syncFragment: {frames},\n          asyncFragments: [],\n        } as unknown as DevTools.StackTrace.StackTrace.StackTrace;\n\n        return await ConsoleFormatter.from(message, {\n          id: 11,\n          resolvedStackTraceForTesting: stackTrace,\n        });\n      },\n    );\n\n    formatterTestDetailed(\n      'does not show call frames with ignore listed scripts',\n      async () => {\n        const message = createMockMessage({\n          type: () => 'log',\n          text: () => 'Hello stack trace!',\n        });\n        const stackTrace = {\n          syncFragment: {\n            frames: [\n              {\n                line: 10,\n                column: 2,\n                url: 'foo.ts',\n                name: 'foo',\n              },\n              {\n                line: 200,\n                column: 46,\n                url: './node_modules/some-third-party-package/lib/index.js',\n                name: 'doThings',\n              },\n              {\n                line: 250,\n                column: 12,\n                url: './node_modules/some-third-party-package/lib/index.js',\n                name: 'doThings2',\n              },\n              {\n                line: 20,\n                column: 2,\n                url: 'foo.ts',\n                name: 'bar',\n              },\n            ],\n          },\n          asyncFragments: [],\n        } as unknown as DevTools.StackTrace.StackTrace.StackTrace;\n\n        return await ConsoleFormatter.from(message, {\n          id: 12,\n          resolvedStackTraceForTesting: stackTrace,\n          isIgnoredForTesting: frame =>\n            Boolean(frame.url?.includes('node_modules')),\n        });\n      },\n    );\n\n    formatterTestDetailed(\n      'does not show fragments where all frames are ignore listed',\n      async () => {\n        const message = createMockMessage({\n          type: () => 'log',\n          text: () => 'Hello stack trace!',\n        });\n        const stackTrace = {\n          syncFragment: {\n            frames: [\n              {\n                line: 10,\n                column: 2,\n                url: 'foo.ts',\n                name: 'foo',\n              },\n            ],\n          },\n          asyncFragments: [\n            {\n              description: 'setTimeout',\n              frames: [\n                {\n                  line: 200,\n                  column: 46,\n                  url: './node_modules/some-third-party-package/lib/index.js',\n                  name: 'doThings',\n                },\n                {\n                  line: 250,\n                  column: 12,\n                  url: './node_modules/some-third-party-package/lib/index.js',\n                  name: 'doThings2',\n                },\n              ],\n            },\n            {\n              description: 'await',\n              frames: [\n                {\n                  line: 20,\n                  column: 2,\n                  url: 'foo.ts',\n                  name: 'bar',\n                },\n              ],\n            },\n          ],\n        } as unknown as DevTools.StackTrace.StackTrace.StackTrace;\n\n        return await ConsoleFormatter.from(message, {\n          id: 13,\n          resolvedStackTraceForTesting: stackTrace,\n          isIgnoredForTesting: frame =>\n            Boolean(frame.url?.includes('node_modules')),\n        });\n      },\n    );\n  });\n});\n"
  },
  {
    "path": "tests/formatters/IssueFormatter.test.js.snapshot",
    "content": "exports[`IssueFormatter > formats a detailed issue toJSONDetailed 1`] = `\n{\n  \"id\": 5,\n  \"type\": \"issue\",\n  \"title\": \"Mock Issue Title\",\n  \"description\": \"# Mock Issue Title\\\\n\\\\nThis is a mock issue description sub value\",\n  \"links\": [\n    {\n      \"link\": \"http://example.com\",\n      \"linkTitle\": \"Link 1\"\n    }\n  ],\n  \"affectedResources\": [\n    {\n      \"uid\": \"1_1\",\n      \"data\": {\n        \"violatingNodeAttribute\": \"test\"\n      }\n    }\n  ]\n}\n`;\n\nexports[`IssueFormatter > formats a detailed issue toStringDetailed 1`] = `\nID: 5\nMessage: issue> Mock Issue Title\n\nThis is a mock issue description sub value\nLearn more:\n[Link 1](http://example.com)\n### Affected resources\nuid=1_1 data={\"violatingNodeAttribute\":\"test\"}\n`;\n\nexports[`IssueFormatter > formats a simplified issue toJSON 1`] = `\n{\n  \"type\": \"issue\",\n  \"title\": \"Issue Title\",\n  \"count\": 5,\n  \"id\": 1\n}\n`;\n\nexports[`IssueFormatter > formats a simplified issue toString 1`] = `\nmsgid=1 [issue] Issue Title (count: 5)\n`;\n\nexports[`IssueFormatter > formats an issue message toJSON 1`] = `\n{\n  \"type\": \"issue\",\n  \"title\": \"Mock Issue Title\",\n  \"id\": 5\n}\n`;\n\nexports[`IssueFormatter > formats an issue message toString 1`] = `\nmsgid=5 [issue] Mock Issue Title (count: undefined)\n`;\n"
  },
  {
    "path": "tests/formatters/IssueFormatter.test.ts",
    "content": "/**\n * @license\n * Copyright 2025 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport assert from 'node:assert';\nimport {describe, it, beforeEach, afterEach} from 'node:test';\n\nimport sinon from 'sinon';\n\nimport {IssueFormatter} from '../../src/formatters/IssueFormatter.js';\nimport {ISSUE_UTILS} from '../../src/issue-descriptions.js';\nimport {getMockAggregatedIssue} from '../utils.js';\n\ndescribe('IssueFormatter', () => {\n  let getIssueDescriptionStub: sinon.SinonStub;\n\n  beforeEach(() => {\n    getIssueDescriptionStub = sinon.stub(ISSUE_UTILS, 'getIssueDescription');\n  });\n\n  afterEach(() => {\n    sinon.restore();\n  });\n\n  function formatterTestConcise(\n    label: string,\n    setup: (t: it.TestContext) => Promise<IssueFormatter>,\n  ) {\n    it(label + ' toString', async t => {\n      const formatter = await setup(t);\n      t.assert.snapshot?.(formatter.toString());\n    });\n    it(label + ' toJSON', async t => {\n      const formatter = await setup(t);\n      t.assert.snapshot?.(JSON.stringify(formatter.toJSON(), null, 2));\n    });\n  }\n\n  function formatterTestDetailed(\n    label: string,\n    setup: (t: it.TestContext) => Promise<IssueFormatter>,\n  ) {\n    it(label + ' toStringDetailed', async t => {\n      const formatter = await setup(t);\n      t.assert.snapshot?.(formatter.toStringDetailed());\n    });\n    it(label + ' toJSONDetailed', async t => {\n      const formatter = await setup(t);\n      t.assert.snapshot?.(JSON.stringify(formatter.toJSONDetailed(), null, 2));\n    });\n  }\n\n  formatterTestConcise('formats an issue message', async () => {\n    const testGenericIssue = {\n      details: () => {\n        return {\n          violatingNodeId: 2,\n          violatingNodeAttribute: 'test',\n        };\n      },\n    };\n    const mockAggregatedIssue = getMockAggregatedIssue();\n    const mockDescription = {\n      file: 'mock.md',\n      links: [\n        {link: 'http://example.com/learnmore', linkTitle: 'Learn more'},\n        {\n          link: 'http://example.com/another-learnmore',\n          linkTitle: 'Learn more 2',\n        },\n      ],\n    };\n    mockAggregatedIssue.getDescription.returns(mockDescription);\n    // @ts-expect-error generic issue stub bypass\n    mockAggregatedIssue.getGenericIssues.returns(new Set([testGenericIssue]));\n\n    const mockDescriptionFileContent =\n      '# Mock Issue Title\\n\\nThis is a mock issue description';\n\n    getIssueDescriptionStub\n      .withArgs('mock.md')\n      .returns(mockDescriptionFileContent);\n\n    return new IssueFormatter(mockAggregatedIssue, {\n      id: 5,\n    });\n  });\n\n  formatterTestConcise('formats a simplified issue', async () => {\n    const mockAggregatedIssue = getMockAggregatedIssue();\n    mockAggregatedIssue.getDescription.returns({\n      file: 'mock.md',\n      links: [],\n    });\n    mockAggregatedIssue.getAggregatedIssuesCount.returns(5);\n    getIssueDescriptionStub\n      .withArgs('mock.md')\n      .returns('# Issue Title\\n\\nIssue content');\n\n    return new IssueFormatter(mockAggregatedIssue, {id: 1});\n  });\n\n  formatterTestDetailed('formats a detailed issue', async () => {\n    const testGenericIssue = {\n      details: () => {\n        return {\n          violatingNodeId: 2,\n          violatingNodeAttribute: 'test',\n        };\n      },\n    };\n    const mockAggregatedIssue = getMockAggregatedIssue();\n    const mockDescription = {\n      file: 'mock.md',\n      links: [{link: 'http://example.com', linkTitle: 'Link 1'}],\n      substitutions: new Map([['PLACEHOLDER_VALUE', 'sub value']]),\n    };\n    mockAggregatedIssue.getDescription.returns(mockDescription);\n    // @ts-expect-error stubbed generic issue does not match the complete type.\n    mockAggregatedIssue.getAllIssues.returns([testGenericIssue]);\n\n    const mockDescriptionFileContent =\n      '# Mock Issue Title\\n\\nThis is a mock issue description {PLACEHOLDER_VALUE}';\n\n    getIssueDescriptionStub\n      .withArgs('mock.md')\n      .returns(mockDescriptionFileContent);\n\n    return new IssueFormatter(mockAggregatedIssue, {\n      id: 5,\n      elementIdResolver: () => '1_1',\n    });\n  });\n\n  describe('isValid', () => {\n    it('returns false for the issue with no description', () => {\n      const mockAggregatedIssue = getMockAggregatedIssue();\n      mockAggregatedIssue.getDescription.returns(null);\n\n      const formatter = new IssueFormatter(mockAggregatedIssue, {id: 1});\n      assert.strictEqual(formatter.isValid(), false);\n    });\n\n    it('returns false if there is no description file', () => {\n      const mockAggregatedIssue = getMockAggregatedIssue();\n      mockAggregatedIssue.getDescription.returns({\n        file: 'mock.md',\n        links: [],\n      });\n      getIssueDescriptionStub.withArgs('mock.md').returns(null);\n\n      const formatter = new IssueFormatter(mockAggregatedIssue, {id: 1});\n      assert.strictEqual(formatter.isValid(), false);\n    });\n\n    it(\"returns false if can't parse the title\", () => {\n      const mockAggregatedIssue = getMockAggregatedIssue();\n      mockAggregatedIssue.getDescription.returns({\n        file: 'mock.md',\n        links: [],\n      });\n      getIssueDescriptionStub\n        .withArgs('mock.md')\n        .returns('No title test {PLACEHOLDER_VALUE}');\n\n      const formatter = new IssueFormatter(mockAggregatedIssue, {id: 1});\n      assert.strictEqual(formatter.isValid(), false);\n    });\n\n    it('returns false if devtools util function throws an error', () => {\n      const mockAggregatedIssue = getMockAggregatedIssue();\n      mockAggregatedIssue.getDescription.returns({\n        file: 'mock.md',\n        links: [],\n        substitutions: new Map([['PLACEHOLDER_VALUE', 'substitution value']]),\n      });\n\n      getIssueDescriptionStub\n        .withArgs('mock.md')\n        .returns('No title test {WRONG_PLACEHOLDER}');\n\n      const formatter = new IssueFormatter(mockAggregatedIssue, {id: 1});\n      assert.strictEqual(formatter.isValid(), false);\n    });\n\n    it('returns true for valid issue', () => {\n      const mockAggregatedIssue = getMockAggregatedIssue();\n      mockAggregatedIssue.getDescription.returns({\n        file: 'mock.md',\n        links: [],\n        substitutions: new Map([['PLACEHOLDER_VALUE', 'substitution value']]),\n      });\n      getIssueDescriptionStub\n        .withArgs('mock.md')\n        .returns('# Valid Title\\n\\nContent {PLACEHOLDER_VALUE}');\n\n      const formatter = new IssueFormatter(mockAggregatedIssue, {id: 1});\n      assert.strictEqual(formatter.isValid(), true);\n\n      // Verify usage of substitutions in detailed output\n      const detailed = formatter.toStringDetailed();\n      assert.ok(detailed.includes('substitution value'));\n      assert.ok(detailed.includes('Valid Title'));\n    });\n  });\n});\n"
  },
  {
    "path": "tests/formatters/NetworkFormatter.test.ts",
    "content": "/**\n * @license\n * Copyright 2025 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport assert from 'node:assert';\nimport {mkdtemp, readFile, rm, writeFile} from 'node:fs/promises';\nimport {tmpdir} from 'node:os';\nimport {join} from 'node:path';\nimport {afterEach, beforeEach, describe, it} from 'node:test';\n\nimport {NetworkFormatter} from '../../src/formatters/NetworkFormatter.js';\nimport type {HTTPRequest} from '../../src/third_party/index.js';\nimport {getMockRequest, getMockResponse} from '../utils.js';\n\ndescribe('NetworkFormatter', () => {\n  let tmpDir: string;\n\n  beforeEach(async () => {\n    tmpDir = await mkdtemp(join(tmpdir(), 'network-formatter-test-'));\n  });\n\n  afterEach(async () => {\n    await rm(tmpDir, {recursive: true, force: true});\n  });\n\n  describe('toString', () => {\n    it('works', async () => {\n      const request = getMockRequest();\n      const formatter = await NetworkFormatter.from(request, {\n        requestId: 1,\n        saveFile: async () => ({filename: ''}),\n      });\n\n      assert.equal(\n        formatter.toString(),\n        'reqid=1 GET http://example.com [pending]',\n      );\n    });\n    it('shows correct method', async () => {\n      const request = getMockRequest({method: 'POST'});\n      const formatter = await NetworkFormatter.from(request, {\n        requestId: 1,\n        saveFile: async () => ({filename: ''}),\n      });\n\n      assert.equal(\n        formatter.toString(),\n        'reqid=1 POST http://example.com [pending]',\n      );\n    });\n    it('shows correct status for request with response code in 200', async () => {\n      const response = getMockResponse();\n      const request = getMockRequest({response});\n      const formatter = await NetworkFormatter.from(request, {\n        requestId: 1,\n        saveFile: async () => ({filename: ''}),\n      });\n\n      assert.equal(\n        formatter.toString(),\n        'reqid=1 GET http://example.com [200]',\n      );\n    });\n    it('shows correct status for request with response code in 100', async () => {\n      const response = getMockResponse({\n        status: 199,\n      });\n      const request = getMockRequest({response});\n      const formatter = await NetworkFormatter.from(request, {\n        requestId: 1,\n        saveFile: async () => ({filename: ''}),\n      });\n\n      assert.equal(\n        formatter.toString(),\n        'reqid=1 GET http://example.com [199]',\n      );\n    });\n    it('shows correct status for request with response code above 200', async () => {\n      const response = getMockResponse({\n        status: 300,\n      });\n      const request = getMockRequest({response});\n      const formatter = await NetworkFormatter.from(request, {\n        requestId: 1,\n        saveFile: async () => ({filename: ''}),\n      });\n\n      assert.equal(\n        formatter.toString(),\n        'reqid=1 GET http://example.com [300]',\n      );\n    });\n    it('shows correct status for request that failed', async () => {\n      const request = getMockRequest({\n        failure() {\n          return {\n            errorText: 'Error in Network',\n          };\n        },\n      });\n      const formatter = await NetworkFormatter.from(request, {\n        requestId: 1,\n        saveFile: async () => ({filename: ''}),\n      });\n\n      assert.equal(\n        formatter.toString(),\n        'reqid=1 GET http://example.com [Error in Network]',\n      );\n    });\n\n    it('marks requests selected in DevTools UI', async () => {\n      const request = getMockRequest();\n      const formatter = await NetworkFormatter.from(request, {\n        requestId: 1,\n        selectedInDevToolsUI: true,\n        saveFile: async () => ({filename: ''}),\n      });\n\n      assert.equal(\n        formatter.toString(),\n        'reqid=1 GET http://example.com [pending] [selected in the DevTools Network panel]',\n      );\n    });\n  });\n\n  describe('toStringDetailed', () => {\n    it('works with request body from fetchPostData', async () => {\n      const request = getMockRequest({\n        hasPostData: true,\n        postData: undefined,\n        fetchPostData: Promise.resolve('test'),\n      });\n      const formatter = await NetworkFormatter.from(request, {\n        requestId: 200,\n        fetchData: true,\n        saveFile: async () => ({filename: ''}),\n      });\n      const result = formatter.toStringDetailed();\n      assert.match(result, /test/);\n    });\n\n    it('works with request body from postData', async () => {\n      const request = getMockRequest({\n        postData: JSON.stringify({\n          request: 'body',\n        }),\n        hasPostData: true,\n      });\n      const formatter = await NetworkFormatter.from(request, {\n        requestId: 200,\n        fetchData: true,\n        saveFile: async () => ({filename: ''}),\n      });\n      const result = formatter.toStringDetailed();\n\n      assert.match(\n        result,\n        new RegExp(\n          JSON.stringify({\n            request: 'body',\n          }),\n        ),\n      );\n    });\n\n    it('truncates request body', async () => {\n      const request = getMockRequest({\n        postData: 'some text that is longer than expected',\n        hasPostData: true,\n      });\n      const formatter = await NetworkFormatter.from(request, {\n        requestId: 20,\n        fetchData: true,\n        saveFile: async () => ({filename: ''}),\n      });\n      const result = formatter.toStringDetailed();\n      assert.match(result, /some text/);\n    });\n\n    it('should save bodies to file when file paths are provided', async () => {\n      const request = {\n        method: () => 'POST',\n        url: () => 'http://example.com',\n        headers: () => ({}),\n        hasPostData: () => true,\n        postData: () => 'request body',\n        response: () => ({\n          status: () => 200,\n          headers: () => ({}),\n          buffer: async () => Buffer.from('response body'),\n        }),\n        failure: () => null,\n        redirectChain: () => [],\n        fetchPostData: async () => undefined,\n      } as unknown as HTTPRequest;\n\n      const reqPath = join(tmpDir, 'test_req_' + Date.now());\n      const resPath = join(tmpDir, 'test_res_' + Date.now());\n\n      const formatter = await NetworkFormatter.from(request, {\n        fetchData: true,\n        requestFilePath: reqPath,\n        responseFilePath: resPath,\n        saveFile: async (data, filename) => {\n          await writeFile(filename, data);\n          return {filename};\n        },\n      });\n\n      const json = formatter.toJSONDetailed() as {\n        requestBody: string;\n        responseBody: string;\n        requestBodyFilePath: string;\n        responseBodyFilePath: string;\n      };\n      assert.strictEqual(json.requestBodyFilePath, reqPath);\n      assert.strictEqual(json.responseBodyFilePath, resPath);\n      assert.strictEqual(json.requestBody, undefined);\n      assert.strictEqual(json.responseBody, undefined);\n    });\n\n    it('should not truncate large bodies when saving to file', async () => {\n      const largeBody = 'a'.repeat(10005);\n      const request = {\n        method: () => 'POST',\n        url: () => 'http://example.com',\n        headers: () => ({}),\n        hasPostData: () => true,\n        postData: () => largeBody,\n        response: () => ({\n          status: () => 200,\n          headers: () => ({}),\n          buffer: async () => Buffer.from(largeBody),\n        }),\n        failure: () => null,\n        redirectChain: () => [],\n        fetchPostData: async () => undefined,\n      } as unknown as HTTPRequest;\n\n      const reqPath = join(tmpDir, 'test_req_large_' + Date.now());\n      const resPath = join(tmpDir, 'test_res_large_' + Date.now());\n\n      await NetworkFormatter.from(request, {\n        fetchData: true,\n        requestFilePath: reqPath,\n        responseFilePath: resPath,\n        saveFile: async (data, filename) => {\n          await writeFile(filename, data);\n          return {filename};\n        },\n      });\n\n      const reqContent = await readFile(reqPath, 'utf8');\n      const resContent = await readFile(resPath, 'utf8');\n\n      assert.strictEqual(reqContent, largeBody);\n      assert.strictEqual(resContent, largeBody);\n    });\n\n    it('handles response body', async () => {\n      const response = getMockResponse();\n      response.buffer = () => {\n        return Promise.resolve(Buffer.from(JSON.stringify({response: 'body'})));\n      };\n      const request = getMockRequest({response});\n\n      const formatter = await NetworkFormatter.from(request, {\n        requestId: 200,\n        fetchData: true,\n        saveFile: async () => ({filename: ''}),\n      });\n      const result = formatter.toStringDetailed();\n\n      assert.match(result, /\"response\":\"body\"/);\n    });\n\n    it('handles redirect chain', async () => {\n      const redirectRequest = getMockRequest({\n        url: 'http://example.com/redirect',\n      });\n      const request = getMockRequest({\n        redirectChain: [redirectRequest],\n      });\n      const formatter = await NetworkFormatter.from(request, {\n        requestId: 1,\n        requestIdResolver: () => 2,\n        saveFile: async () => ({filename: ''}),\n      });\n      const result = formatter.toStringDetailed();\n      assert.match(result, /Redirect chain/);\n      assert.match(result, /reqid=2/);\n    });\n    it('shows saved to file message in toStringDetailed', async () => {\n      const request = {\n        method: () => 'POST',\n        url: () => 'http://example.com',\n        headers: () => ({}),\n        hasPostData: () => true,\n        postData: () => 'request body',\n        response: () => ({\n          status: () => 200,\n          headers: () => ({}),\n          buffer: async () => Buffer.from('response body'),\n        }),\n        failure: () => null,\n        redirectChain: () => [],\n        fetchPostData: async () => undefined,\n      } as unknown as HTTPRequest;\n\n      const reqPath = join(tmpDir, 'req.txt');\n      const resPath = join(tmpDir, 'res.txt');\n\n      const formatter = await NetworkFormatter.from(request, {\n        fetchData: true,\n        requestFilePath: reqPath,\n        responseFilePath: resPath,\n        saveFile: async (data, filename) => {\n          await writeFile(filename, data);\n          return {filename};\n        },\n      });\n\n      const result = formatter.toStringDetailed();\n      assert.ok(result.includes(`Saved to ${reqPath}.`));\n      assert.ok(result.includes(`Saved to ${resPath}.`));\n    });\n\n    it('handles missing bodies with filepath', async () => {\n      const request = {\n        method: () => 'POST',\n        url: () => 'http://example.com',\n        headers: () => ({}),\n        hasPostData: () => true, // Claim we have data\n        postData: () => null, // But returns null\n        response: () => ({\n          status: () => 200,\n          headers: () => ({}),\n          buffer: async () => {\n            throw new Error('Body not available');\n          },\n        }),\n        failure: () => null,\n        redirectChain: () => [],\n        fetchPostData: async () => {\n          throw new Error('Body not available');\n        },\n      } as unknown as HTTPRequest;\n\n      const reqPath = join(tmpDir, 'req_missing.txt');\n      const resPath = join(tmpDir, 'res_missing.txt');\n\n      const formatter = await NetworkFormatter.from(request, {\n        fetchData: true,\n        requestFilePath: reqPath,\n        responseFilePath: resPath,\n        saveFile: async (data, filename) => {\n          await writeFile(filename, data);\n          return {filename};\n        },\n      });\n\n      const result = formatter.toStringDetailed();\n      assert.ok(\n        result.includes(\n          `### Response Body\\n<Response body not available anymore>`,\n        ),\n      );\n    });\n  });\n\n  describe('toJSON', () => {\n    it('returns structured data', async () => {\n      const request = getMockRequest();\n      const formatter = await NetworkFormatter.from(request, {\n        requestId: 1,\n        selectedInDevToolsUI: true,\n        saveFile: async () => ({filename: ''}),\n      });\n      const result = formatter.toJSON();\n      assert.deepEqual(result, {\n        requestId: 1,\n        method: 'GET',\n        url: 'http://example.com',\n        status: 'pending',\n        selectedInDevToolsUI: true,\n      });\n    });\n  });\n\n  describe('toJSONDetailed', () => {\n    it('returns structured detailed data', async () => {\n      const response = getMockResponse();\n      response.buffer = () => Promise.resolve(Buffer.from('response'));\n      const request = getMockRequest({\n        response,\n        postData: 'request',\n        hasPostData: true,\n      });\n      const formatter = await NetworkFormatter.from(request, {\n        requestId: 1,\n        fetchData: true,\n        saveFile: async () => ({filename: ''}),\n      });\n      const result = formatter.toJSONDetailed();\n      assert.deepEqual(result, {\n        requestId: 1,\n        method: 'GET',\n        url: 'http://example.com',\n        status: '200',\n        selectedInDevToolsUI: undefined,\n        requestHeaders: {\n          'content-size': '10',\n        },\n        requestBody: 'request',\n        requestBodyFilePath: undefined,\n        responseHeaders: {},\n        responseBody: 'response',\n        responseBodyFilePath: undefined,\n        failure: undefined,\n        redirectChain: undefined,\n      });\n    });\n\n    it('returns file paths in structured detailed data', async () => {\n      const request = {\n        method: () => 'POST',\n        url: () => 'http://example.com',\n        headers: () => ({}),\n        hasPostData: () => true,\n        postData: () => 'request body',\n        response: () => ({\n          status: () => 200,\n          headers: () => ({}),\n          buffer: async () => Buffer.from('response body'),\n        }),\n        failure: () => null,\n        redirectChain: () => [],\n        fetchPostData: async () => undefined,\n      } as unknown as HTTPRequest;\n\n      const reqPath = join(tmpDir, 'req_json.txt');\n      const resPath = join(tmpDir, 'res_json.txt');\n\n      const formatter = await NetworkFormatter.from(request, {\n        fetchData: true,\n        requestFilePath: reqPath,\n        responseFilePath: resPath,\n        saveFile: async (data, filename) => {\n          await writeFile(filename, data);\n          return {filename};\n        },\n      });\n\n      const result = formatter.toJSONDetailed() as {\n        requestBodyFilePath: string;\n        responseBodyFilePath: string;\n        requestBody?: string;\n        responseBody?: string;\n      };\n\n      assert.strictEqual(result.requestBodyFilePath, reqPath);\n      assert.strictEqual(result.responseBodyFilePath, resPath);\n      assert.strictEqual(result.requestBody, undefined);\n      assert.strictEqual(result.responseBody, undefined);\n    });\n  });\n});\n"
  },
  {
    "path": "tests/formatters/snapshotFormatter.test.js.snapshot",
    "content": "exports[`snapshotFormatter > does not include a note if the snapshot is already verbose 1`] = `\nNote: there is a selected element in the DevTools Elements panel but it is not included into the current a11y tree snapshot.\nGet a verbose snapshot to include all elements if you are interested in the selected element.\n\nuid=1_1 checkbox \"checkbox\" checked\n  uid=1_2 statictext \"text\"\n\n`;\n\nexports[`snapshotFormatter > formats with DevTools data included into a snapshot 1`] = `\nuid=1_1 checkbox \"checkbox\" checked [selected in the DevTools Elements panel]\n  uid=1_2 statictext \"text\"\n\n`;\n\nexports[`snapshotFormatter > formats with DevTools data not included into a snapshot 1`] = `\nuid=1_1 checkbox \"checkbox\" checked\n  uid=1_2 statictext \"text\"\n\n`;\n"
  },
  {
    "path": "tests/formatters/snapshotFormatter.test.ts",
    "content": "/**\n * @license\n * Copyright 2025 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport assert from 'node:assert';\nimport {describe, it} from 'node:test';\n\nimport type {ElementHandle} from 'puppeteer-core';\n\nimport {SnapshotFormatter} from '../../src/formatters/SnapshotFormatter.js';\nimport type {TextSnapshot, TextSnapshotNode} from '../../src/McpContext.js';\n\ndescribe('snapshotFormatter', () => {\n  it('formats a snapshot with value properties', () => {\n    const node: TextSnapshotNode = {\n      id: '1_1',\n      role: 'textbox',\n      name: 'textbox',\n      value: 'value',\n      live: 'polite',\n      relevant: 'additions',\n      errormessage: 'error-id',\n      details: 'details-id',\n      children: [\n        {\n          id: '1_2',\n          role: 'statictext',\n          name: 'text',\n          children: [],\n          elementHandle: async (): Promise<ElementHandle<Element> | null> => {\n            return null;\n          },\n        },\n      ],\n      elementHandle: async (): Promise<ElementHandle<Element> | null> => {\n        return null;\n      },\n    };\n\n    const formatter = new SnapshotFormatter({root: node} as TextSnapshot);\n    const formatted = formatter.toString();\n    assert.strictEqual(\n      formatted,\n      `uid=1_1 textbox \"textbox\" details=\"details-id\" errormessage=\"error-id\" live=\"polite\" relevant=\"additions\" value=\"value\"\n  uid=1_2 statictext \"text\"\n`,\n    );\n  });\n\n  it('formats a snapshot with boolean properties', () => {\n    const node: TextSnapshotNode = {\n      id: '1_1',\n      role: 'button',\n      name: 'button',\n      disabled: true,\n      busy: true,\n      atomic: true,\n      children: [\n        {\n          id: '1_2',\n          role: 'statictext',\n          name: 'text',\n          children: [],\n          elementHandle: async (): Promise<ElementHandle<Element> | null> => {\n            return null;\n          },\n        },\n      ],\n      elementHandle: async (): Promise<ElementHandle<Element> | null> => {\n        return null;\n      },\n    };\n\n    const formatter = new SnapshotFormatter({root: node} as TextSnapshot);\n    const formatted = formatter.toString();\n    assert.strictEqual(\n      formatted,\n      `uid=1_1 button \"button\" atomic busy disableable disabled\n  uid=1_2 statictext \"text\"\n`,\n    );\n  });\n\n  it('formats a snapshot with checked properties', () => {\n    const node: TextSnapshotNode = {\n      id: '1_1',\n      role: 'checkbox',\n      name: 'checkbox',\n      checked: true,\n      children: [\n        {\n          id: '1_2',\n          role: 'statictext',\n          name: 'text',\n          children: [],\n          elementHandle: async (): Promise<ElementHandle<Element> | null> => {\n            return null;\n          },\n        },\n      ],\n      elementHandle: async (): Promise<ElementHandle<Element> | null> => {\n        return null;\n      },\n    };\n\n    const formatter = new SnapshotFormatter({root: node} as TextSnapshot);\n    const formatted = formatter.toString();\n    assert.strictEqual(\n      formatted,\n      `uid=1_1 checkbox \"checkbox\" checked\n  uid=1_2 statictext \"text\"\n`,\n    );\n  });\n\n  it('formats a snapshot with multiple different type attributes', () => {\n    const node: TextSnapshotNode = {\n      id: '1_1',\n      role: 'root',\n      name: 'root',\n      children: [\n        {\n          id: '1_2',\n          role: 'button',\n          name: 'button',\n          focused: true,\n          disabled: true,\n          children: [],\n          elementHandle: async (): Promise<ElementHandle<Element> | null> => {\n            return null;\n          },\n        },\n        {\n          id: '1_3',\n          role: 'textbox',\n          name: 'textbox',\n          value: 'value',\n          children: [],\n          elementHandle: async (): Promise<ElementHandle<Element> | null> => {\n            return null;\n          },\n        },\n      ],\n      elementHandle: async (): Promise<ElementHandle<Element> | null> => {\n        return null;\n      },\n    };\n\n    const formatter = new SnapshotFormatter({root: node} as TextSnapshot);\n    const formatted = formatter.toString();\n    assert.strictEqual(\n      formatted,\n      `uid=1_1 root \"root\"\n  uid=1_2 button \"button\" disableable disabled focusable focused\n  uid=1_3 textbox \"textbox\" value=\"value\"\n`,\n    );\n  });\n\n  it('formats with DevTools data not included into a snapshot', t => {\n    const node: TextSnapshotNode = {\n      id: '1_1',\n      role: 'checkbox',\n      name: 'checkbox',\n      checked: true,\n      children: [\n        {\n          id: '1_2',\n          role: 'statictext',\n          name: 'text',\n          children: [],\n          elementHandle: async (): Promise<ElementHandle<Element> | null> => {\n            return null;\n          },\n        },\n      ],\n      elementHandle: async (): Promise<ElementHandle<Element> | null> => {\n        return null;\n      },\n    };\n\n    const formatter = new SnapshotFormatter({\n      snapshotId: '1',\n      root: node,\n      idToNode: new Map(),\n      hasSelectedElement: true,\n      verbose: false,\n    });\n    const formatted = formatter.toString();\n\n    t.assert.snapshot?.(formatted);\n  });\n\n  it('does not include a note if the snapshot is already verbose', t => {\n    const node: TextSnapshotNode = {\n      id: '1_1',\n      role: 'checkbox',\n      name: 'checkbox',\n      checked: true,\n      children: [\n        {\n          id: '1_2',\n          role: 'statictext',\n          name: 'text',\n          children: [],\n          elementHandle: async (): Promise<ElementHandle<Element> | null> => {\n            return null;\n          },\n        },\n      ],\n      elementHandle: async (): Promise<ElementHandle<Element> | null> => {\n        return null;\n      },\n    };\n\n    const formatter = new SnapshotFormatter({\n      snapshotId: '1',\n      root: node,\n      idToNode: new Map(),\n      hasSelectedElement: true,\n      verbose: true,\n    });\n    const formatted = formatter.toString();\n\n    t.assert.snapshot?.(formatted);\n  });\n\n  it('formats with DevTools data included into a snapshot', t => {\n    const node: TextSnapshotNode = {\n      id: '1_1',\n      role: 'checkbox',\n      name: 'checkbox',\n      checked: true,\n      children: [\n        {\n          id: '1_2',\n          role: 'statictext',\n          name: 'text',\n          children: [],\n          elementHandle: async (): Promise<ElementHandle<Element> | null> => {\n            return null;\n          },\n        },\n      ],\n      elementHandle: async (): Promise<ElementHandle<Element> | null> => {\n        return null;\n      },\n    };\n\n    const formatter = new SnapshotFormatter({\n      snapshotId: '1',\n      root: node,\n      idToNode: new Map(),\n      hasSelectedElement: true,\n      selectedElementUid: '1_1',\n      verbose: false,\n    });\n    const formatted = formatter.toString();\n\n    t.assert.snapshot?.(formatted);\n  });\n\n  it('toJSON returns expected structure', () => {\n    const node: TextSnapshotNode = {\n      id: '1_1',\n      role: 'root',\n      name: 'root',\n      busy: true,\n      live: 'polite',\n      children: [\n        {\n          id: '1_2',\n          role: 'button',\n          name: 'button',\n          disabled: true,\n          children: [],\n          elementHandle: async () => null,\n        },\n      ],\n      elementHandle: async () => null,\n    };\n\n    const formatter = new SnapshotFormatter({root: node} as TextSnapshot);\n    const json = formatter.toJSON();\n\n    assert.deepStrictEqual(json, {\n      id: '1_1',\n      role: 'root',\n      name: 'root',\n      busy: true,\n      live: 'polite',\n      children: [\n        {\n          id: '1_2',\n          role: 'button',\n          name: 'button',\n          disableable: true,\n          disabled: true,\n        },\n      ],\n    });\n  });\n});\n"
  },
  {
    "path": "tests/index.test.js.snapshot",
    "content": "exports[`e2e > calls a tool 1`] = `\n[{\"type\":\"text\",\"text\":\"## Pages\\\\n1: about:blank [selected]\"}]\n`;\n\nexports[`e2e > calls a tool multiple times 1`] = `\n[{\"type\":\"text\",\"text\":\"## Pages\\\\n1: about:blank [selected]\"}]\n`;\n"
  },
  {
    "path": "tests/index.test.ts",
    "content": "/**\n * @license\n * Copyright 2025 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport assert from 'node:assert';\nimport fs from 'node:fs';\nimport {describe, it} from 'node:test';\n\nimport {Client} from '@modelcontextprotocol/sdk/client/index.js';\nimport {StdioClientTransport} from '@modelcontextprotocol/sdk/client/stdio.js';\nimport {executablePath} from 'puppeteer';\n\nimport type {ToolDefinition} from '../src/tools/ToolDefinition';\n\ndescribe('e2e', () => {\n  async function withClient(\n    cb: (client: Client) => Promise<void>,\n    extraArgs: string[] = [],\n  ) {\n    const transport = new StdioClientTransport({\n      command: 'node',\n      args: [\n        'build/src/bin/chrome-devtools-mcp.js',\n        '--headless',\n        '--isolated',\n        '--executable-path',\n        executablePath(),\n        ...extraArgs,\n      ],\n    });\n    const client = new Client(\n      {\n        name: 'e2e-test',\n        version: '1.0.0',\n      },\n      {\n        capabilities: {},\n      },\n    );\n\n    try {\n      await client.connect(transport);\n      await cb(client);\n    } finally {\n      await client.close();\n    }\n  }\n  it('calls a tool', async t => {\n    await withClient(async client => {\n      const result = await client.callTool({\n        name: 'list_pages',\n        arguments: {},\n      });\n      t.assert.snapshot?.(JSON.stringify(result.content));\n    });\n  });\n\n  it('calls a tool multiple times', async t => {\n    await withClient(async client => {\n      let result = await client.callTool({\n        name: 'list_pages',\n        arguments: {},\n      });\n      result = await client.callTool({\n        name: 'list_pages',\n        arguments: {},\n      });\n      t.assert.snapshot?.(JSON.stringify(result.content));\n    });\n  });\n\n  it('has all tools', async () => {\n    await withClient(async client => {\n      const {tools} = await client.listTools();\n      const exposedNames = tools.map(t => t.name).sort();\n      const files = fs.readdirSync('build/src/tools');\n      const definedNames = [];\n      for (const file of files) {\n        if (\n          file === 'ToolDefinition.js' ||\n          file === 'tools.js' ||\n          file === 'slim'\n        ) {\n          continue;\n        }\n        const fileTools = await import(`../src/tools/${file}`);\n        for (const maybeTool of Object.values<unknown>(fileTools)) {\n          if (typeof maybeTool === 'function') {\n            const tool = (maybeTool as (val: boolean) => ToolDefinition)(false);\n            if (tool && typeof tool === 'object' && 'name' in tool) {\n              if (tool.annotations?.conditions) {\n                continue;\n              }\n              definedNames.push(tool.name);\n            }\n            continue;\n          }\n          if (\n            typeof maybeTool === 'object' &&\n            maybeTool !== null &&\n            'name' in maybeTool\n          ) {\n            const tool = maybeTool as ToolDefinition;\n            if (tool.annotations?.conditions) {\n              continue;\n            }\n            definedNames.push(tool.name);\n          }\n        }\n      }\n      definedNames.sort();\n      assert.deepStrictEqual(exposedNames, definedNames);\n    });\n  });\n\n  it('has experimental extensions tools', async () => {\n    await withClient(\n      async client => {\n        const {tools} = await client.listTools();\n        const clickAt = tools.find(t => t.name === 'install_extension');\n        assert.ok(clickAt);\n      },\n      ['--category-extensions'],\n    );\n  });\n\n  it('has experimental vision tools', async () => {\n    await withClient(\n      async client => {\n        const {tools} = await client.listTools();\n        const clickAt = tools.find(t => t.name === 'click_at');\n        assert.ok(clickAt);\n      },\n      ['--experimental-vision'],\n    );\n  });\n\n  it('has experimental interop tools', async () => {\n    await withClient(\n      async client => {\n        const {tools} = await client.listTools();\n        const getTabId = tools.find(t => t.name === 'get_tab_id');\n        assert.ok(getTabId);\n      },\n      ['--experimental-interop-tools'],\n    );\n  });\n});\n"
  },
  {
    "path": "tests/server.ts",
    "content": "/**\n * @license\n * Copyright 2025 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport http, {\n  type IncomingMessage,\n  type Server,\n  type ServerResponse,\n} from 'node:http';\nimport {before, after, afterEach} from 'node:test';\n\nimport {html} from './utils.js';\n\nexport class TestServer {\n  #port: number;\n  #server: Server;\n\n  static randomPort() {\n    /**\n     * Some ports are restricted by Chromium and will fail to connect\n     * to prevent we start after the\n     *\n     * https://source.chromium.org/chromium/chromium/src/+/main:net/base/port_util.cc;l=107?q=kRestrictedPorts&ss=chromium\n     */\n    const min = 10101;\n    const max = 20202;\n    return Math.floor(Math.random() * (max - min + 1) + min);\n  }\n\n  #routes: Record<string, (req: IncomingMessage, res: ServerResponse) => void> =\n    {};\n\n  constructor(port: number) {\n    this.#port = port;\n    this.#server = http.createServer((req, res) => this.#handle(req, res));\n  }\n\n  get baseUrl(): string {\n    return `http://localhost:${this.#port}`;\n  }\n\n  getRoute(path: string) {\n    if (!this.#routes[path]) {\n      throw new Error(`Route ${path} was not setup.`);\n    }\n    return `${this.baseUrl}${path}`;\n  }\n\n  addHtmlRoute(path: string, htmlContent: string) {\n    if (this.#routes[path]) {\n      throw new Error(`Route ${path} was already setup.`);\n    }\n    this.#routes[path] = (_req: IncomingMessage, res: ServerResponse) => {\n      res.setHeader('Content-Type', 'text/html; charset=utf-8');\n      res.statusCode = 200;\n      res.end(htmlContent);\n    };\n  }\n\n  addRoute(\n    path: string,\n    handler: (req: IncomingMessage, res: ServerResponse) => void,\n  ) {\n    if (this.#routes[path]) {\n      throw new Error(`Route ${path} was already setup.`);\n    }\n    this.#routes[path] = handler;\n  }\n\n  #handle(req: IncomingMessage, res: ServerResponse) {\n    const url = req.url ?? '';\n    const routeHandler = this.#routes[url];\n\n    if (routeHandler) {\n      routeHandler(req, res);\n    } else {\n      res.writeHead(404, {'Content-Type': 'text/html'});\n      res.end(\n        html`<h1>404 - Not Found</h1><p>The requested page does not exist.</p>`,\n      );\n    }\n  }\n\n  restore() {\n    this.#routes = {};\n  }\n\n  start(): Promise<void> {\n    return new Promise(res => {\n      this.#server.listen(this.#port, res);\n    });\n  }\n\n  stop(): Promise<void> {\n    return new Promise((res, rej) => {\n      this.#server.close(err => {\n        if (err) {\n          rej(err);\n        } else {\n          res();\n        }\n      });\n    });\n  }\n}\n\nexport function serverHooks() {\n  const server = new TestServer(TestServer.randomPort());\n  before(async () => {\n    await server.start();\n  });\n  after(async () => {\n    await server.stop();\n  });\n  afterEach(() => {\n    server.restore();\n  });\n\n  return server;\n}\n"
  },
  {
    "path": "tests/setup.ts",
    "content": "/**\n * @license\n * Copyright 2025 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport '../src/polyfill.js';\n\nimport path from 'node:path';\nimport {it} from 'node:test';\n\nif (!it.snapshot) {\n  it.snapshot = {\n    setResolveSnapshotPath: () => {\n      // Internally empty\n    },\n    setDefaultSnapshotSerializers: () => {\n      // Internally empty\n    },\n  };\n}\n\n// This is run by Node when we execute the tests via the --import flag.\nit.snapshot.setResolveSnapshotPath(testPath => {\n  // By default the snapshots go into the build directory, but we want them\n  // in the tests/ directory.\n  const correctPath = testPath?.replace(path.join('build', 'tests'), 'tests');\n  return correctPath + '.snapshot';\n});\n\n// The default serializer is JSON.stringify which outputs a very hard to read\n// snapshot. So we override it to one that shows new lines literally rather\n// than via `\\n`.\nit.snapshot.setDefaultSnapshotSerializers([String]);\n"
  },
  {
    "path": "tests/snapshot.ts",
    "content": "/**\n * @license\n * Copyright 2025 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\ninterface ScreenshotData {\n  html: string;\n}\n\nexport const screenshots: Record<string, ScreenshotData> = {\n  basic: {\n    html: '<div>Hello MCP</div>',\n  },\n  viewportOverflow: {\n    html: '<div style=\"height: 120vh; background-color: rebeccapurple;\">View Port overflow</div>',\n  },\n  button: {\n    html: '<button>I am button click me</button>',\n  },\n};\n"
  },
  {
    "path": "tests/telemetry/ClearcutLogger.test.ts",
    "content": "/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport assert from 'node:assert';\nimport {describe, it, afterEach, beforeEach} from 'node:test';\n\nimport sinon from 'sinon';\n\nimport {ClearcutLogger} from '../../src/telemetry/ClearcutLogger.js';\nimport type {Persistence} from '../../src/telemetry/persistence.js';\nimport {FilePersistence} from '../../src/telemetry/persistence.js';\nimport {WatchdogMessageType} from '../../src/telemetry/types.js';\nimport {WatchdogClient} from '../../src/telemetry/WatchdogClient.js';\n\ndescribe('ClearcutLogger', () => {\n  let mockPersistence: sinon.SinonStubbedInstance<Persistence>;\n  let mockWatchdogClient: sinon.SinonStubbedInstance<WatchdogClient>;\n\n  beforeEach(() => {\n    mockPersistence = sinon.createStubInstance(FilePersistence, {\n      loadState: Promise.resolve({\n        lastActive: '',\n      }),\n    });\n    mockWatchdogClient = sinon.createStubInstance(WatchdogClient);\n  });\n\n  afterEach(() => {\n    sinon.restore();\n  });\n\n  describe('logToolInvocation', () => {\n    it('sends correct payload', async () => {\n      const logger = new ClearcutLogger({\n        persistence: mockPersistence,\n        appVersion: '1.0.0',\n        watchdogClient: mockWatchdogClient,\n      });\n      await logger.logToolInvocation({\n        toolName: 'test_tool',\n        success: true,\n        latencyMs: 123,\n      });\n\n      assert(mockWatchdogClient.send.calledOnce);\n      const msg = mockWatchdogClient.send.firstCall.args[0];\n      assert.strictEqual(msg.type, WatchdogMessageType.LOG_EVENT);\n      assert.strictEqual(msg.payload.tool_invocation?.tool_name, 'test_tool');\n      assert.strictEqual(msg.payload.tool_invocation?.success, true);\n      assert.strictEqual(msg.payload.tool_invocation?.latency_ms, 123);\n    });\n  });\n\n  describe('logServerStart', () => {\n    it('logs flag usage', async () => {\n      const logger = new ClearcutLogger({\n        persistence: mockPersistence,\n        appVersion: '1.0.0',\n        watchdogClient: mockWatchdogClient,\n      });\n\n      await logger.logServerStart({headless: true});\n\n      assert(mockWatchdogClient.send.calledOnce);\n      const msg = mockWatchdogClient.send.firstCall.args[0];\n      assert.strictEqual(msg.type, WatchdogMessageType.LOG_EVENT);\n      assert.strictEqual(msg.payload.server_start?.flag_usage?.headless, true);\n    });\n  });\n\n  describe('logDailyActiveIfNeeded', () => {\n    it('logs daily active if needed (lastActive > 24h ago)', async () => {\n      const yesterday = new Date();\n      yesterday.setDate(yesterday.getDate() - 1);\n\n      mockPersistence.loadState.resolves({\n        lastActive: yesterday.toISOString(),\n      });\n\n      const logger = new ClearcutLogger({\n        persistence: mockPersistence,\n        appVersion: '1.0.0',\n        watchdogClient: mockWatchdogClient,\n      });\n\n      await logger.logDailyActiveIfNeeded();\n\n      assert(mockWatchdogClient.send.calledOnce);\n      const msg = mockWatchdogClient.send.firstCall.args[0];\n      assert.strictEqual(msg.type, WatchdogMessageType.LOG_EVENT);\n      assert.ok(msg.payload.daily_active);\n\n      assert(mockPersistence.saveState.called);\n    });\n\n    it('does not log daily active if not needed (today)', async () => {\n      mockPersistence.loadState.resolves({\n        lastActive: new Date().toISOString(),\n      });\n\n      const logger = new ClearcutLogger({\n        persistence: mockPersistence,\n        appVersion: '1.0.0',\n        watchdogClient: mockWatchdogClient,\n      });\n\n      await logger.logDailyActiveIfNeeded();\n\n      assert(mockWatchdogClient.send.notCalled);\n      assert(mockPersistence.saveState.notCalled);\n    });\n\n    it('logs daily active with -1 if lastActive is missing', async () => {\n      mockPersistence.loadState.resolves({\n        lastActive: '',\n      });\n\n      const logger = new ClearcutLogger({\n        persistence: mockPersistence,\n        appVersion: '1.0.0',\n        watchdogClient: mockWatchdogClient,\n      });\n\n      await logger.logDailyActiveIfNeeded();\n\n      assert(mockWatchdogClient.send.calledOnce);\n      const msg = mockWatchdogClient.send.firstCall.args[0];\n      assert.strictEqual(msg.type, WatchdogMessageType.LOG_EVENT);\n      assert.strictEqual(msg.payload.daily_active?.days_since_last_active, -1);\n      assert(mockPersistence.saveState.called);\n    });\n  });\n});\n"
  },
  {
    "path": "tests/telemetry/WatchdogClient.test.ts",
    "content": "/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport assert from 'node:assert';\nimport {ChildProcess} from 'node:child_process';\nimport {Writable} from 'node:stream';\nimport {describe, it, afterEach, beforeEach} from 'node:test';\n\nimport sinon from 'sinon';\n\nimport {OsType, WatchdogMessageType} from '../../src/telemetry/types.js';\nimport {WatchdogClient} from '../../src/telemetry/WatchdogClient.js';\n\ndescribe('WatchdogClient', () => {\n  let spawnStub: sinon.SinonStub;\n  let stdinStub: sinon.SinonStubbedInstance<Writable>;\n  let mockChildProcess: sinon.SinonStubbedInstance<ChildProcess>;\n\n  beforeEach(() => {\n    stdinStub = sinon.createStubInstance(Writable);\n    mockChildProcess = sinon.createStubInstance(ChildProcess);\n    spawnStub = sinon.stub().returns(mockChildProcess);\n\n    Object.defineProperty(mockChildProcess, 'stdin', {\n      value: stdinStub,\n      writable: true,\n    });\n    Object.defineProperty(mockChildProcess, 'pid', {\n      value: 12345,\n      writable: true,\n    });\n  });\n\n  afterEach(() => {\n    sinon.restore();\n  });\n\n  it('spawns watchdog process with correct arguments', () => {\n    new WatchdogClient(\n      {\n        parentPid: 100,\n        appVersion: '1.2.3',\n        osType: OsType.OS_TYPE_MACOS,\n      },\n      {spawn: spawnStub},\n    );\n\n    assert.ok(spawnStub.calledOnce, 'Expected `spawn` to be called');\n    const args = spawnStub.firstCall.args;\n    const cmdArgs = args[1];\n\n    assert.match(\n      cmdArgs[0],\n      /watchdog[/\\\\]main\\.js$/,\n      'First argument should be path to watchdog/main.js',\n    );\n    assert.ok(\n      cmdArgs.includes('--parent-pid=100'),\n      'Arguments should include parent PID',\n    );\n    assert.ok(\n      cmdArgs.includes('--app-version=1.2.3'),\n      'Arguments should include app version',\n    );\n    assert.ok(\n      cmdArgs.includes('--os-type=2'),\n      'Arguments should include OS type',\n    );\n    assert.strictEqual(\n      spawnStub.firstCall.args[2].detached,\n      true,\n      'Process should be spawned as detached',\n    );\n  });\n\n  it('passes log-file argument if provided', () => {\n    new WatchdogClient(\n      {\n        parentPid: 100,\n        appVersion: '1.0.0',\n        osType: OsType.OS_TYPE_LINUX,\n        logFile: '/tmp/test.log',\n      },\n      {spawn: spawnStub},\n    );\n\n    const cmdArgs = spawnStub.firstCall.args[1];\n    assert.ok(\n      cmdArgs.includes('--log-file=/tmp/test.log'),\n      'Arguments should include log file path',\n    );\n  });\n\n  it('sends IPC messages via stdin', () => {\n    const client = new WatchdogClient(\n      {\n        parentPid: 100,\n        appVersion: '1.0.0',\n        osType: OsType.OS_TYPE_LINUX,\n      },\n      {spawn: spawnStub},\n    );\n\n    const msg = {type: WatchdogMessageType.LOG_EVENT, payload: {}};\n    client.send(msg);\n\n    assert.ok(\n      stdinStub.write.calledOnce,\n      'Expected `stdin.write` to be called',\n    );\n\n    const writtenData = stdinStub.write.firstCall.args[0];\n    assert.strictEqual(\n      writtenData.trim(),\n      JSON.stringify(msg),\n      'Written data should match expected JSON message',\n    );\n  });\n\n  it('handles write errors gracefully', () => {\n    const client = new WatchdogClient(\n      {\n        parentPid: 100,\n        appVersion: '1.0.0',\n        osType: OsType.OS_TYPE_LINUX,\n      },\n      {spawn: spawnStub},\n    );\n\n    stdinStub.write.throws(new Error('EPIPE'));\n\n    assert.doesNotThrow(() => {\n      client.send({type: WatchdogMessageType.LOG_EVENT, payload: {}});\n    }, 'Client should catch and ignore write errors');\n  });\n});\n"
  },
  {
    "path": "tests/telemetry/flagUtils.test.ts",
    "content": "/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport assert from 'node:assert/strict';\nimport {describe, it} from 'node:test';\n\nimport type {cliOptions} from '../../src/bin/chrome-devtools-mcp-cli-options.js';\nimport {computeFlagUsage} from '../../src/telemetry/flagUtils.js';\n\ndescribe('computeFlagUsage', () => {\n  const mockOptions = {\n    boolFlag: {\n      type: 'boolean' as const,\n      description: 'A boolean flag',\n    },\n    stringFlag: {\n      type: 'string' as const,\n      description: 'A string flag',\n    },\n    enumFlag: {\n      type: 'string' as const,\n      description: 'An enum flag',\n      choices: ['a', 'b'],\n    },\n    flagWithDefault: {\n      type: 'boolean' as const,\n      description: 'A flag with a default value',\n      default: false,\n    },\n  } as unknown as typeof cliOptions;\n\n  it('logs boolean flags directly with snake_case keys', () => {\n    const args = {boolFlag: true};\n    const usage = computeFlagUsage(args, mockOptions);\n    assert.equal(usage.bool_flag, true);\n  });\n\n  it('logs boolean flags as false when false', () => {\n    const args = {boolFlag: false};\n    const usage = computeFlagUsage(args, mockOptions);\n    assert.equal(usage.bool_flag, false);\n  });\n\n  it('logs enum flags as uppercase strings prefixed by snake case flag name', () => {\n    const args = {enumFlag: 'a'};\n    const usage = computeFlagUsage(args, mockOptions);\n    assert.equal(usage.enum_flag, 'ENUM_FLAG_A');\n  });\n\n  it('logs other flags as present with snake_case keys', () => {\n    const args = {stringFlag: 'value'};\n    const usage = computeFlagUsage(args, mockOptions);\n    assert.equal(usage.string_flag, undefined);\n    assert.equal(usage.string_flag_present, true);\n  });\n\n  it('handles undefined/null values', () => {\n    const args = {stringFlag: undefined};\n    const usage = computeFlagUsage(args, mockOptions);\n    assert.equal(usage.string_flag_present, false);\n  });\n\n  describe('defaults behavior', () => {\n    it('logs presence when default exists and user provides different value', () => {\n      // Case 1: Default exists, and a value is provided by the user.\n      // default is false, user provides true.\n      const args = {flagWithDefault: true};\n      const usage = computeFlagUsage(args, mockOptions);\n      assert.equal(usage.flag_with_default, true);\n      assert.equal(usage.flag_with_default_present, true);\n    });\n\n    it('does not log presence when default exists and user provides no value', () => {\n      // Case 2a: Default exists, and a value is not provided by the user.\n      // Argument parsing would populate with default.\n      const args = {flagWithDefault: false};\n      const usage = computeFlagUsage(args, mockOptions);\n      assert.equal(usage.flag_with_default, false);\n      assert.equal(usage.flag_with_default_present, undefined);\n    });\n\n    it('does not log presence when default exists and user explicitly provides the default value', () => {\n      // Case 2b: User explicitly provides 'false', which matches default.\n      const args = {flagWithDefault: false};\n      const usage = computeFlagUsage(args, mockOptions);\n      assert.equal(usage.flag_with_default, false);\n      assert.equal(usage.flag_with_default_present, undefined);\n    });\n\n    it('logs presence when no default exists and user provides value', () => {\n      // Case 3: No default, user provides value.\n      const args = {stringFlag: 'value'};\n      const usage = computeFlagUsage(args, mockOptions);\n      assert.equal(usage.string_flag_present, true);\n    });\n\n    it('logs non-presence when no default exists and user provides no value', () => {\n      // Case 4: No default, user provides nothing.\n      const args = {};\n      const usage = computeFlagUsage(args, mockOptions);\n      assert.equal(usage.string_flag_present, false);\n    });\n  });\n});\n"
  },
  {
    "path": "tests/telemetry/metricUtils.test.ts",
    "content": "/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport assert from 'node:assert';\nimport {describe, it} from 'node:test';\n\nimport {bucketizeLatency} from '../../src/telemetry/metricUtils.js';\n\ndescribe('bucketizeLatency', () => {\n  it('should bucketize values correctly', () => {\n    assert.strictEqual(bucketizeLatency(0), 50);\n    assert.strictEqual(bucketizeLatency(25), 50);\n    assert.strictEqual(bucketizeLatency(50), 50);\n\n    assert.strictEqual(bucketizeLatency(51), 100);\n    assert.strictEqual(bucketizeLatency(100), 100);\n\n    assert.strictEqual(bucketizeLatency(101), 250);\n    assert.strictEqual(bucketizeLatency(250), 250);\n\n    assert.strictEqual(bucketizeLatency(499), 500);\n    assert.strictEqual(bucketizeLatency(500), 500);\n\n    assert.strictEqual(bucketizeLatency(900), 1000);\n    assert.strictEqual(bucketizeLatency(1000), 1000);\n\n    assert.strictEqual(bucketizeLatency(2000), 2500);\n    assert.strictEqual(bucketizeLatency(2500), 2500);\n\n    assert.strictEqual(bucketizeLatency(4000), 5000);\n    assert.strictEqual(bucketizeLatency(5000), 5000);\n\n    assert.strictEqual(bucketizeLatency(6000), 10000);\n    assert.strictEqual(bucketizeLatency(10000), 10000);\n\n    assert.strictEqual(bucketizeLatency(10001), 10000);\n    assert.strictEqual(bucketizeLatency(99999), 10000);\n  });\n});\n"
  },
  {
    "path": "tests/telemetry/persistence.test.ts",
    "content": "/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport assert from 'node:assert';\nimport crypto from 'node:crypto';\nimport fs from 'node:fs/promises';\nimport os from 'node:os';\nimport path from 'node:path';\nimport {describe, it, afterEach, beforeEach} from 'node:test';\n\nimport * as persistence from '../../src/telemetry/persistence.js';\n\ndescribe('FilePersistence', () => {\n  let tmpDir: string;\n\n  beforeEach(async () => {\n    tmpDir = path.join(\n      await fs.realpath(os.tmpdir()),\n      `telemetry-test-${crypto.randomUUID()}`,\n    );\n    await fs.mkdir(tmpDir, {recursive: true});\n  });\n\n  afterEach(async () => {\n    await fs.rm(tmpDir, {recursive: true, force: true});\n  });\n\n  describe('loadState', () => {\n    it('returns default state if file does not exist', async () => {\n      const filePersistence = new persistence.FilePersistence(tmpDir);\n      const state = await filePersistence.loadState();\n      assert.deepStrictEqual(state, {\n        lastActive: '',\n      });\n    });\n\n    it('returns stored state if file exists', async () => {\n      const expectedState = {\n        lastActive: '2023-01-01T00:00:00.000Z',\n      };\n      await fs.writeFile(\n        path.join(tmpDir, 'telemetry_state.json'),\n        JSON.stringify(expectedState),\n      );\n\n      const filePersistence = new persistence.FilePersistence(tmpDir);\n      const state = await filePersistence.loadState();\n      assert.deepStrictEqual(state, expectedState);\n    });\n  });\n\n  describe('saveState', () => {\n    it('saves state to file', async () => {\n      const state = {\n        lastActive: '2023-01-01T00:00:00.000Z',\n      };\n      const filePersistence = new persistence.FilePersistence(tmpDir);\n      await filePersistence.saveState(state);\n\n      const content = await fs.readFile(\n        path.join(tmpDir, 'telemetry_state.json'),\n        'utf-8',\n      );\n      assert.deepStrictEqual(JSON.parse(content), state);\n    });\n  });\n});\n"
  },
  {
    "path": "tests/telemetry/watchdog/ClearcutSender.test.ts",
    "content": "/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport assert from 'node:assert';\nimport crypto from 'node:crypto';\nimport {describe, it, afterEach, beforeEach} from 'node:test';\n\nimport sinon from 'sinon';\n\nimport {OsType} from '../../../src/telemetry/types.js';\nimport type {LogRequest} from '../../../src/telemetry/types.js';\nimport {ClearcutSender} from '../../../src/telemetry/watchdog/ClearcutSender.js';\n\nconst FLUSH_INTERVAL_MS = 15 * 1000;\n\ndescribe('ClearcutSender', () => {\n  let randomUUIDStub: sinon.SinonStub;\n  let fetchStub: sinon.SinonStub;\n  let clock: sinon.SinonFakeTimers;\n\n  beforeEach(() => {\n    clock = sinon.useFakeTimers({\n      now: Date.now(),\n      toFake: ['setTimeout', 'clearTimeout', 'Date'],\n    });\n\n    let uuidCounter = 0;\n    randomUUIDStub = sinon.stub(crypto, 'randomUUID').callsFake(() => {\n      return `uuid-${++uuidCounter}` as ReturnType<typeof crypto.randomUUID>;\n    });\n    fetchStub = sinon.stub(global, 'fetch');\n    fetchStub.resolves(new Response(JSON.stringify({}), {status: 200}));\n  });\n\n  afterEach(() => {\n    randomUUIDStub.restore();\n    fetchStub.restore();\n    clock.restore();\n    sinon.restore();\n  });\n\n  it('enriches events with app version, os type, and session id', async () => {\n    const sender = new ClearcutSender({\n      appVersion: '1.0.0',\n      osType: OsType.OS_TYPE_MACOS,\n      forceFlushIntervalMs: FLUSH_INTERVAL_MS,\n    });\n\n    sender.enqueueEvent({mcp_client: undefined});\n    assert.strictEqual(sender.bufferSizeForTesting, 1);\n\n    await clock.tickAsync(FLUSH_INTERVAL_MS);\n    sender.stopForTesting();\n\n    assert.strictEqual(fetchStub.callCount, 1);\n    const requestBody = JSON.parse(\n      fetchStub.firstCall.args[1].body,\n    ) as LogRequest;\n    const event = JSON.parse(requestBody.log_event[0].source_extension_json);\n\n    assert.strictEqual(event.session_id, 'uuid-1');\n    assert.strictEqual(event.app_version, '1.0.0');\n    assert.strictEqual(event.os_type, OsType.OS_TYPE_MACOS);\n  });\n\n  it('accumulates events in buffer without immediate send', async () => {\n    const sender = new ClearcutSender({\n      appVersion: '1.0.0',\n      osType: OsType.OS_TYPE_MACOS,\n      forceFlushIntervalMs: FLUSH_INTERVAL_MS,\n    });\n\n    sender.enqueueEvent({\n      tool_invocation: {tool_name: 'test1', success: true, latency_ms: 100},\n    });\n    sender.enqueueEvent({\n      tool_invocation: {tool_name: 'test2', success: true, latency_ms: 200},\n    });\n\n    assert.strictEqual(sender.bufferSizeForTesting, 2);\n    assert.strictEqual(fetchStub.callCount, 0);\n\n    sender.stopForTesting();\n  });\n\n  it('sends correct LogRequest format', async () => {\n    const sender = new ClearcutSender({\n      appVersion: '1.0.0',\n      osType: OsType.OS_TYPE_MACOS,\n      forceFlushIntervalMs: FLUSH_INTERVAL_MS,\n    });\n\n    sender.enqueueEvent({\n      tool_invocation: {tool_name: 'test', success: true, latency_ms: 100},\n    });\n\n    await clock.tickAsync(FLUSH_INTERVAL_MS);\n    sender.stopForTesting();\n\n    const [url, options] = fetchStub.firstCall.args;\n    assert.strictEqual(\n      url,\n      'https://play.googleapis.com/log?format=json_proto',\n    );\n    assert.strictEqual(options.method, 'POST');\n    assert.strictEqual(options.headers['Content-Type'], 'application/json');\n\n    const body = JSON.parse(options.body) as LogRequest;\n    assert.strictEqual(body.log_source, 2839);\n    assert.strictEqual(body.client_info.client_type, 47);\n    assert.ok(body.request_time_ms);\n  });\n\n  it('clears buffer on successful send', async () => {\n    const sender = new ClearcutSender({\n      appVersion: '1.0.0',\n      osType: OsType.OS_TYPE_MACOS,\n      forceFlushIntervalMs: FLUSH_INTERVAL_MS,\n    });\n\n    sender.enqueueEvent({});\n    sender.enqueueEvent({});\n    assert.strictEqual(sender.bufferSizeForTesting, 2);\n\n    await clock.tickAsync(FLUSH_INTERVAL_MS);\n    sender.stopForTesting();\n    assert.strictEqual(sender.bufferSizeForTesting, 0);\n  });\n\n  it('keeps events in buffer on transient 5xx error', async () => {\n    const sender = new ClearcutSender({\n      appVersion: '1.0.0',\n      osType: OsType.OS_TYPE_MACOS,\n      forceFlushIntervalMs: FLUSH_INTERVAL_MS,\n    });\n    fetchStub.resolves(new Response('Server Error', {status: 500}));\n\n    sender.enqueueEvent({});\n    await clock.tickAsync(FLUSH_INTERVAL_MS);\n    sender.stopForTesting();\n\n    assert.strictEqual(sender.bufferSizeForTesting, 1);\n  });\n\n  it('keeps events in buffer on transient 429 error', async () => {\n    const sender = new ClearcutSender({\n      appVersion: '1.0.0',\n      osType: OsType.OS_TYPE_MACOS,\n      forceFlushIntervalMs: FLUSH_INTERVAL_MS,\n    });\n    fetchStub.resolves(new Response('Too Many Requests', {status: 429}));\n\n    sender.enqueueEvent({});\n    await clock.tickAsync(FLUSH_INTERVAL_MS);\n    sender.stopForTesting();\n\n    assert.strictEqual(sender.bufferSizeForTesting, 1);\n  });\n\n  it('drops batch on permanent 4xx error', async () => {\n    const sender = new ClearcutSender({\n      appVersion: '1.0.0',\n      osType: OsType.OS_TYPE_MACOS,\n      forceFlushIntervalMs: FLUSH_INTERVAL_MS,\n    });\n    fetchStub.resolves(new Response('Bad Request', {status: 400}));\n\n    sender.enqueueEvent({});\n    await clock.tickAsync(FLUSH_INTERVAL_MS);\n    sender.stopForTesting();\n\n    assert.strictEqual(sender.bufferSizeForTesting, 0);\n  });\n\n  it('keeps events in buffer on network error', async () => {\n    const sender = new ClearcutSender({\n      appVersion: '1.0.0',\n      osType: OsType.OS_TYPE_MACOS,\n      forceFlushIntervalMs: FLUSH_INTERVAL_MS,\n    });\n    fetchStub.rejects(new Error('Network error'));\n\n    sender.enqueueEvent({});\n    await clock.tickAsync(FLUSH_INTERVAL_MS);\n    sender.stopForTesting();\n\n    assert.strictEqual(sender.bufferSizeForTesting, 1);\n  });\n\n  it('sendShutdownEvent sends an immediate server_shutdown event', async () => {\n    const sender = new ClearcutSender({\n      appVersion: '1.0.0',\n      osType: OsType.OS_TYPE_MACOS,\n      forceFlushIntervalMs: FLUSH_INTERVAL_MS,\n    });\n\n    await sender.sendShutdownEvent();\n\n    assert.strictEqual(fetchStub.callCount, 1);\n    const requestBody = JSON.parse(\n      fetchStub.firstCall.args[1].body,\n    ) as LogRequest;\n    const event = JSON.parse(requestBody.log_event[0].source_extension_json);\n\n    assert.ok(event.server_shutdown);\n  });\n\n  it('shutdown includes buffered events', async () => {\n    const sender = new ClearcutSender({\n      appVersion: '1.0.0',\n      osType: OsType.OS_TYPE_MACOS,\n      forceFlushIntervalMs: FLUSH_INTERVAL_MS,\n    });\n\n    sender.enqueueEvent({\n      tool_invocation: {tool_name: 'test', success: true, latency_ms: 100},\n    });\n    await sender.sendShutdownEvent();\n\n    const requestBody = JSON.parse(\n      fetchStub.firstCall.args[1].body,\n    ) as LogRequest;\n    assert.strictEqual(requestBody.log_event.length, 2);\n  });\n\n  it('correctly handles buffer overflow during queued flush', async () => {\n    const sender = new ClearcutSender({\n      appVersion: '1.0.0',\n      osType: OsType.OS_TYPE_MACOS,\n      forceFlushIntervalMs: FLUSH_INTERVAL_MS,\n    });\n\n    sender.enqueueEvent({\n      tool_invocation: {tool_name: 'initial', success: true, latency_ms: 100},\n    });\n    let resolveRequest: (value: Response) => void;\n\n    fetchStub.onFirstCall().returns(\n      new Promise<Response>(resolve => {\n        resolveRequest = resolve;\n      }),\n    );\n\n    clock.tick(FLUSH_INTERVAL_MS);\n\n    for (let i = 0; i < 1100; i++) {\n      sender.enqueueEvent({\n        tool_invocation: {\n          tool_name: `overflow-${i}`,\n          success: true,\n          latency_ms: 100,\n        },\n      });\n    }\n\n    assert.strictEqual(sender.bufferSizeForTesting, 1000);\n\n    resolveRequest!(new Response(JSON.stringify({}), {status: 200}));\n\n    assert.strictEqual(sender.bufferSizeForTesting, 1000);\n\n    sender.stopForTesting();\n  });\n\n  it('does not duplicate events when shutdown occurs during an active flush', async () => {\n    const sender = new ClearcutSender({\n      appVersion: '1.0.0',\n      osType: OsType.OS_TYPE_MACOS,\n      forceFlushIntervalMs: FLUSH_INTERVAL_MS,\n    });\n    sender.enqueueEvent({\n      tool_invocation: {\n        tool_name: 'test-event',\n        success: true,\n        latency_ms: 100,\n      },\n    });\n\n    let resolveFirstRequest: (value: Response) => void;\n    fetchStub.onFirstCall().returns(\n      new Promise<Response>(resolve => {\n        resolveFirstRequest = resolve;\n      }),\n    );\n\n    clock.tick(FLUSH_INTERVAL_MS);\n\n    const shutdownPromise = sender.sendShutdownEvent();\n\n    resolveFirstRequest!(new Response(JSON.stringify({}), {status: 200}));\n    await shutdownPromise;\n\n    assert.strictEqual(fetchStub.callCount, 2);\n    const firstBody = JSON.parse(fetchStub.args[0][1].body) as LogRequest;\n    const secondBody = JSON.parse(fetchStub.args[1][1].body) as LogRequest;\n\n    const firstEvents = firstBody.log_event.map(e =>\n      JSON.parse(e.source_extension_json),\n    );\n    const secondEvents = secondBody.log_event.map(e =>\n      JSON.parse(e.source_extension_json),\n    );\n\n    assert.strictEqual(firstEvents.length, 1);\n    assert.strictEqual(firstEvents[0].tool_invocation?.tool_name, 'test-event');\n\n    assert.strictEqual(\n      secondEvents.length,\n      1,\n      'Shutdown request should only contain shutdown event',\n    );\n    assert.ok(\n      secondEvents[0].server_shutdown,\n      'Shutdown request should contain server_shutdown',\n    );\n\n    sender.stopForTesting();\n  });\n\n  it('rotates session id after 24 hours', async () => {\n    const sender = new ClearcutSender({\n      appVersion: '1.0.0',\n      osType: OsType.OS_TYPE_MACOS,\n      forceFlushIntervalMs: FLUSH_INTERVAL_MS,\n    });\n\n    sender.enqueueEvent({\n      tool_invocation: {tool_name: 'test1', success: true, latency_ms: 10},\n    });\n    await clock.tickAsync(FLUSH_INTERVAL_MS);\n\n    const firstCallBody = JSON.parse(\n      fetchStub.firstCall.args[1].body,\n    ) as LogRequest;\n    const firstEvent = JSON.parse(\n      firstCallBody.log_event[0].source_extension_json,\n    );\n    const firstSessionId = firstEvent.session_id;\n\n    const SESSION_ROTATION_INTERVAL_MS = 24 * 60 * 60 * 1000;\n    await clock.tickAsync(\n      SESSION_ROTATION_INTERVAL_MS - FLUSH_INTERVAL_MS + 1000,\n    );\n\n    sender.enqueueEvent({\n      tool_invocation: {tool_name: 'test2', success: true, latency_ms: 10},\n    });\n    await clock.tickAsync(FLUSH_INTERVAL_MS);\n\n    const secondCallBody = JSON.parse(\n      fetchStub.secondCall.args[1].body,\n    ) as LogRequest;\n    const secondEvent = JSON.parse(\n      secondCallBody.log_event[0].source_extension_json,\n    );\n    const secondSessionId = secondEvent.session_id;\n\n    assert.notStrictEqual(firstSessionId, secondSessionId);\n\n    sender.stopForTesting();\n  });\n\n  it('respects next_request_wait_millis from server', async () => {\n    const sender = new ClearcutSender({\n      appVersion: '1.0.0',\n      osType: OsType.OS_TYPE_MACOS,\n      forceFlushIntervalMs: FLUSH_INTERVAL_MS,\n    });\n\n    fetchStub.resolves(\n      new Response(\n        JSON.stringify({\n          next_request_wait_millis: 45000,\n        }),\n        {status: 200},\n      ),\n    );\n\n    sender.enqueueEvent({});\n    await clock.tickAsync(FLUSH_INTERVAL_MS);\n\n    fetchStub.resetHistory();\n\n    sender.enqueueEvent({});\n\n    await clock.tickAsync(44000);\n    assert.strictEqual(\n      fetchStub.callCount,\n      0,\n      'Should not flush before wait time',\n    );\n\n    await clock.tickAsync(1000);\n    assert.strictEqual(fetchStub.callCount, 1, 'Should flush after wait time');\n\n    sender.stopForTesting();\n  });\n\n  it('aborts request after timeout', async () => {\n    const sender = new ClearcutSender({\n      appVersion: '1.0.0',\n      osType: OsType.OS_TYPE_MACOS,\n      forceFlushIntervalMs: FLUSH_INTERVAL_MS,\n    });\n    const REQUEST_TIMEOUT_MS = 30000;\n\n    let fetchSignal: AbortSignal | undefined;\n    fetchStub.callsFake((_url, options) => {\n      fetchSignal = options.signal;\n      return new Promise(() => {\n        // Hangs forever\n      });\n    });\n\n    sender.enqueueEvent({});\n\n    await clock.tickAsync(FLUSH_INTERVAL_MS);\n    await clock.tickAsync(REQUEST_TIMEOUT_MS);\n\n    assert.ok(fetchSignal, 'Fetch should have been called with a signal');\n    assert.strictEqual(\n      fetchSignal.aborted,\n      true,\n      'Signal should be aborted after timeout',\n    );\n\n    sender.stopForTesting();\n  });\n\n  it('resolves sendShutdownEvent after timeout if flush hangs', async () => {\n    const sender = new ClearcutSender({\n      appVersion: '1.0.0',\n      osType: OsType.OS_TYPE_MACOS,\n      forceFlushIntervalMs: FLUSH_INTERVAL_MS,\n    });\n    fetchStub.returns(\n      new Promise(() => {\n        // Hangs forever\n      }),\n    );\n\n    const shutdownPromise = sender.sendShutdownEvent();\n\n    await clock.tickAsync(5000);\n\n    await shutdownPromise;\n  });\n});\n"
  },
  {
    "path": "tests/third_party_notices.test.js.snapshot",
    "content": "exports[`THIRD_PARTY_NOTICES > matches snapshot if exists 1`] = `\nName: core-js\nURL: https://core-js.io\nVersion: <VERSION>\nLicense: MIT\n\nCopyright (c) 2013–2025 Denis Pushkarev (zloirock.ru)\nCopyright (c) 2025–2026 CoreJS Company (core-js.io)\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\n\n-------------------- DEPENDENCY DIVIDER --------------------\n\nName: cliui\nURL: yargs/cliui\nVersion: <VERSION>\nLicense: ISC\n\nCopyright (c) 2015, Contributors\n\nPermission to use, copy, modify, and/or distribute this software\nfor any purpose with or without fee is hereby granted, provided\nthat the above copyright notice and this permission notice\nappear 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\nOF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE\nLIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES\nOR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,\nWHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,\nARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n\n\n-------------------- DEPENDENCY DIVIDER --------------------\n\nName: ansi-regex\nURL: chalk/ansi-regex\nVersion: <VERSION>\nLicense: MIT\n\nMIT License\n\nCopyright (c) Sindre Sorhus <sindresorhus@gmail.com> (https://sindresorhus.com)\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n\n-------------------- DEPENDENCY DIVIDER --------------------\n\nName: strip-ansi\nURL: chalk/strip-ansi\nVersion: <VERSION>\nLicense: MIT\n\nMIT License\n\nCopyright (c) Sindre Sorhus <sindresorhus@gmail.com> (https://sindresorhus.com)\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n\n-------------------- DEPENDENCY DIVIDER --------------------\n\nName: get-east-asian-width\nURL: sindresorhus/get-east-asian-width\nVersion: <VERSION>\nLicense: MIT\n\nMIT License\n\nCopyright (c) Sindre Sorhus <sindresorhus@gmail.com> (https://sindresorhus.com)\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n\n-------------------- DEPENDENCY DIVIDER --------------------\n\nName: emoji-regex\nURL: https://mths.be/emoji-regex\nVersion: <VERSION>\nLicense: MIT\n\nCopyright Mathias Bynens <https://mathiasbynens.be/>\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\n-------------------- DEPENDENCY DIVIDER --------------------\n\nName: string-width\nURL: sindresorhus/string-width\nVersion: <VERSION>\nLicense: MIT\n\nMIT License\n\nCopyright (c) Sindre Sorhus <sindresorhus@gmail.com> (https://sindresorhus.com)\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n\n-------------------- DEPENDENCY DIVIDER --------------------\n\nName: ansi-styles\nURL: chalk/ansi-styles\nVersion: <VERSION>\nLicense: MIT\n\nMIT License\n\nCopyright (c) Sindre Sorhus <sindresorhus@gmail.com> (https://sindresorhus.com)\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n\n-------------------- DEPENDENCY DIVIDER --------------------\n\nName: wrap-ansi\nURL: chalk/wrap-ansi\nVersion: <VERSION>\nLicense: MIT\n\nMIT License\n\nCopyright (c) Sindre Sorhus <sindresorhus@gmail.com> (https://sindresorhus.com)\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n\n-------------------- DEPENDENCY DIVIDER --------------------\n\nName: escalade\nURL: lukeed/escalade\nVersion: <VERSION>\nLicense: MIT\n\nMIT License\n\nCopyright (c) Luke Edwards <luke.edwards05@gmail.com> (lukeed.com)\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n\n-------------------- DEPENDENCY DIVIDER --------------------\n\nName: yargs-parser\nURL: https://github.com/yargs/yargs-parser.git\nVersion: <VERSION>\nLicense: ISC\n\nCopyright (c) 2016, Contributors\n\nPermission to use, copy, modify, and/or distribute this software\nfor any purpose with or without fee is hereby granted, provided\nthat the above copyright notice and this permission notice\nappear 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\nOF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE\nLIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES\nOR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,\nWHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,\nARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n\n\n-------------------- DEPENDENCY DIVIDER --------------------\n\nName: yargs\nURL: https://yargs.js.org/\nVersion: <VERSION>\nLicense: MIT\n\nMIT License\n\nCopyright 2010 James Halliday (mail@substack.net); Modified work Copyright 2014 Contributors (ben@npmjs.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\n\n-------------------- DEPENDENCY DIVIDER --------------------\n\nName: y18n\nURL: https://github.com/yargs/y18n\nVersion: <VERSION>\nLicense: ISC\n\nCopyright (c) 2015, Contributors\n\nPermission to use, copy, modify, and/or distribute this software for any purpose\nwith or without fee is hereby granted, provided that the above copyright notice\nand this permission notice appear in all copies.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH\nREGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND\nFITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,\nINDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS\nOF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER\nTORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF\nTHIS SOFTWARE.\n\n\n-------------------- DEPENDENCY DIVIDER --------------------\n\nName: get-caller-file\nURL: https://github.com/stefanpenner/get-caller-file#readme\nVersion: <VERSION>\nLicense: ISC\n\nISC License (ISC)\nCopyright 2018 Stefan Penner\n\nPermission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n\n\n-------------------- DEPENDENCY DIVIDER --------------------\n\nName: debug\nURL: git://github.com/debug-js/debug.git\nVersion: <VERSION>\nLicense: MIT\n\n(The MIT License)\n\nCopyright (c) 2014-2017 TJ Holowaychuk <tj@vision-media.ca>\nCopyright (c) 2018-2021 Josh Junon\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software\nand associated documentation files (the 'Software'), to deal in the Software without restriction,\nincluding without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,\nand/or sell copies of the 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 copies or substantial\nportions of the Software.\n\nTHE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT\nLIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\nWHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n\n\n-------------------- DEPENDENCY DIVIDER --------------------\n\nName: ms\nURL: vercel/ms\nVersion: <VERSION>\nLicense: MIT\n\nThe MIT License (MIT)\n\nCopyright (c) 2020 Vercel, Inc.\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\n-------------------- DEPENDENCY DIVIDER --------------------\n\nName: has-flag\nURL: sindresorhus/has-flag\nVersion: <VERSION>\nLicense: MIT\n\nMIT License\n\nCopyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com)\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n\n-------------------- DEPENDENCY DIVIDER --------------------\n\nName: supports-color\nURL: chalk/supports-color\nVersion: <VERSION>\nLicense: MIT\n\nMIT License\n\nCopyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com)\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n\n-------------------- DEPENDENCY DIVIDER --------------------\n\nName: zod\nURL: https://zod.dev\nVersion: <VERSION>\nLicense: MIT\n\nMIT License\n\nCopyright (c) 2025 Colin McDonnell\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\n-------------------- DEPENDENCY DIVIDER --------------------\n\nName: @modelcontextprotocol/sdk\nURL: https://modelcontextprotocol.io\nVersion: <VERSION>\nLicense: MIT\n\nMIT License\n\nCopyright (c) 2024 Anthropic, PBC\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\n-------------------- DEPENDENCY DIVIDER --------------------\n\nName: zod-to-json-schema\nURL: https://github.com/StefanTerdell/zod-to-json-schema\nVersion: <VERSION>\nLicense: ISC\n\nISC License\n\nCopyright (c) 2020, Stefan Terdell\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\n-------------------- DEPENDENCY DIVIDER --------------------\n\nName: ajv\nURL: https://ajv.js.org\nVersion: <VERSION>\nLicense: MIT\n\nThe MIT License (MIT)\n\nCopyright (c) 2015-2021 Evgeny Poberezkin\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\n\n-------------------- DEPENDENCY DIVIDER --------------------\n\nName: fast-deep-equal\nURL: https://github.com/epoberezkin/fast-deep-equal#readme\nVersion: <VERSION>\nLicense: MIT\n\nMIT License\n\nCopyright (c) 2017 Evgeny Poberezkin\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\n-------------------- DEPENDENCY DIVIDER --------------------\n\nName: json-schema-traverse\nURL: https://github.com/epoberezkin/json-schema-traverse#readme\nVersion: <VERSION>\nLicense: MIT\n\nMIT License\n\nCopyright (c) 2017 Evgeny Poberezkin\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\n-------------------- DEPENDENCY DIVIDER --------------------\n\nName: fast-uri\nURL: https://github.com/fastify/fast-uri\nVersion: <VERSION>\nLicense: BSD-3-Clause\n\nCopyright (c) 2011-2021, Gary Court until https://github.com/garycourt/uri-js/commit/a1acf730b4bba3f1097c9f52e7d9d3aba8cdcaae\nCopyright (c) 2021-present The Fastify team\nAll rights reserved.\n\nThe Fastify team members are listed at https://github.com/fastify/fastify#team.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\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 copyright\n      notice, this list of conditions and the following disclaimer in the\n      documentation and/or other materials provided with the distribution.\n    * The names of any contributors may not be used to endorse or promote\n      products derived from this software without specific prior written\n      permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\nANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\nWARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY\nDIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\nLOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\nON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\nSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n                                  *   *   *\n\nThe complete list of contributors can be found at:\n- https://github.com/garycourt/uri-js/graphs/contributors\n\n-------------------- DEPENDENCY DIVIDER --------------------\n\nName: ajv-formats\nURL: https://github.com/ajv-validator/ajv-formats#readme\nVersion: <VERSION>\nLicense: MIT\n\nMIT License\n\nCopyright (c) 2020 Evgeny Poberezkin\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\n-------------------- DEPENDENCY DIVIDER --------------------\n\nName: cross-spawn\nURL: https://github.com/moxystudio/node-cross-spawn\nVersion: <VERSION>\nLicense: MIT\n\nThe MIT License (MIT)\n\nCopyright (c) 2018 Made With MOXY Lda <hello@moxy.studio>\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\n\n-------------------- DEPENDENCY DIVIDER --------------------\n\nName: isexe\nURL: https://github.com/isaacs/isexe#readme\nVersion: <VERSION>\nLicense: ISC\n\nThe ISC License\n\nCopyright (c) Isaac Z. Schlueter and Contributors\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 OR\nIN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n\n\n-------------------- DEPENDENCY DIVIDER --------------------\n\nName: which\nURL: git://github.com/isaacs/node-which.git\nVersion: <VERSION>\nLicense: ISC\n\nThe ISC License\n\nCopyright (c) Isaac Z. Schlueter and Contributors\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 OR\nIN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n\n\n-------------------- DEPENDENCY DIVIDER --------------------\n\nName: path-key\nURL: sindresorhus/path-key\nVersion: <VERSION>\nLicense: MIT\n\nMIT License\n\nCopyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com)\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n\n-------------------- DEPENDENCY DIVIDER --------------------\n\nName: shebang-regex\nURL: sindresorhus/shebang-regex\nVersion: <VERSION>\nLicense: MIT\n\nMIT License\n\nCopyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com)\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n\n-------------------- DEPENDENCY DIVIDER --------------------\n\nName: shebang-command\nURL: kevva/shebang-command\nVersion: <VERSION>\nLicense: MIT\n\nMIT License\n\nCopyright (c) Kevin Mårtensson <kevinmartensson@gmail.com> (github.com/kevva)\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n\n-------------------- DEPENDENCY DIVIDER --------------------\n\nName: puppeteer-core\nURL: https://github.com/puppeteer/puppeteer/tree/main/packages/puppeteer-core\nVersion: <VERSION>\nLicense: Apache-2.0\n\n-------------------- DEPENDENCY DIVIDER --------------------\n\nName: @puppeteer/browsers\nURL: https://github.com/puppeteer/puppeteer/tree/main/packages/browsers\nVersion: <VERSION>\nLicense: Apache-2.0\n\n-------------------- DEPENDENCY DIVIDER --------------------\n\nName: semver\nURL: git+https://github.com/npm/node-semver.git\nVersion: <VERSION>\nLicense: ISC\n\nThe ISC License\n\nCopyright (c) Isaac Z. Schlueter and Contributors\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 OR\nIN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n\n\n-------------------- DEPENDENCY DIVIDER --------------------\n\nName: proxy-agent\nURL: https://github.com/TooTallNate/proxy-agents.git\nVersion: <VERSION>\nLicense: MIT\n\n(The MIT License)\n\nCopyright (c) 2013 Nathan Rajlich <nathan@tootallnate.net>\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 NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\nTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n-------------------- DEPENDENCY DIVIDER --------------------\n\nName: lru-cache\nURL: git://github.com/isaacs/node-lru-cache.git\nVersion: <VERSION>\nLicense: ISC\n\nThe ISC License\n\nCopyright (c) 2010-2023 Isaac Z. Schlueter and Contributors\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 OR\nIN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n\n\n-------------------- DEPENDENCY DIVIDER --------------------\n\nName: agent-base\nURL: https://github.com/TooTallNate/proxy-agents.git\nVersion: <VERSION>\nLicense: MIT\n\n(The MIT License)\n\nCopyright (c) 2013 Nathan Rajlich <nathan@tootallnate.net>\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 NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\nTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n-------------------- DEPENDENCY DIVIDER --------------------\n\nName: proxy-from-env\nURL: https://github.com/Rob--W/proxy-from-env#readme\nVersion: <VERSION>\nLicense: MIT\n\nThe MIT License\n\nCopyright (C) 2016-2018 Rob Wu <rob@robwu.nl>\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\nof the Software, and to permit persons to whom the Software is furnished to do\nso, 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, 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\n\n-------------------- DEPENDENCY DIVIDER --------------------\n\nName: http-proxy-agent\nURL: https://github.com/TooTallNate/proxy-agents.git\nVersion: <VERSION>\nLicense: MIT\n\n(The MIT License)\n\nCopyright (c) 2013 Nathan Rajlich <nathan@tootallnate.net>\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 NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\nTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n\n-------------------- DEPENDENCY DIVIDER --------------------\n\nName: https-proxy-agent\nURL: https://github.com/TooTallNate/proxy-agents.git\nVersion: <VERSION>\nLicense: MIT\n\n(The MIT License)\n\nCopyright (c) 2013 Nathan Rajlich <nathan@tootallnate.net>\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 NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\nTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n-------------------- DEPENDENCY DIVIDER --------------------\n\nName: socks-proxy-agent\nURL: https://github.com/TooTallNate/proxy-agents.git\nVersion: <VERSION>\nLicense: MIT\n\n(The MIT License)\n\nCopyright (c) 2013 Nathan Rajlich <nathan@tootallnate.net>\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 NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\nTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n-------------------- DEPENDENCY DIVIDER --------------------\n\nName: socks\nURL: https://github.com/JoshGlazebrook/socks/\nVersion: <VERSION>\nLicense: MIT\n\nThe MIT License (MIT)\n\nCopyright (c) 2013 Josh Glazebrook\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\n\n-------------------- DEPENDENCY DIVIDER --------------------\n\nName: smart-buffer\nURL: https://github.com/JoshGlazebrook/smart-buffer/\nVersion: <VERSION>\nLicense: MIT\n\nThe MIT License (MIT)\n\nCopyright (c) 2013-2017 Josh Glazebrook\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\n\n-------------------- DEPENDENCY DIVIDER --------------------\n\nName: ip-address\nURL: git://github.com/beaugunderson/ip-address.git\nVersion: <VERSION>\nLicense: MIT\n\nCopyright (C) 2011 by Beau Gunderson\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\n\n-------------------- DEPENDENCY DIVIDER --------------------\n\nName: pac-proxy-agent\nURL: https://github.com/TooTallNate/proxy-agents.git\nVersion: <VERSION>\nLicense: MIT\n\n(The MIT License)\n\nCopyright (c) 2014 Nathan Rajlich <nathan@tootallnate.net>\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 NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\nTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n\n-------------------- DEPENDENCY DIVIDER --------------------\n\nName: get-uri\nURL: https://github.com/TooTallNate/proxy-agents.git\nVersion: <VERSION>\nLicense: MIT\n\n(The MIT License)\n\nCopyright (c) 2014 Nathan Rajlich <nathan@tootallnate.net>\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 NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\nTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n-------------------- DEPENDENCY DIVIDER --------------------\n\nName: data-uri-to-buffer\nURL: https://github.com/TooTallNate/proxy-agents.git\nVersion: <VERSION>\nLicense: MIT\n\n(The MIT License)\n\nCopyright (c) 2014 Nathan Rajlich <nathan@tootallnate.net>\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 NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\nTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n-------------------- DEPENDENCY DIVIDER --------------------\n\nName: basic-ftp\nURL: https://github.com/patrickjuchli/basic-ftp.git\nVersion: <VERSION>\nLicense: MIT\n\nCopyright (c) 2019 Patrick Juchli\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-------------------- DEPENDENCY DIVIDER --------------------\n\nName: pac-resolver\nURL: https://github.com/TooTallNate/proxy-agents.git\nVersion: <VERSION>\nLicense: MIT\n\n(The MIT License)\n\nCopyright (c) 2013 Nathan Rajlich <nathan@tootallnate.net>\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 NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\nTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n-------------------- DEPENDENCY DIVIDER --------------------\n\nName: degenerator\nURL: https://github.com/TooTallNate/proxy-agents.git\nVersion: <VERSION>\nLicense: MIT\n\n-------------------- DEPENDENCY DIVIDER --------------------\n\nName: escodegen\nURL: http://github.com/estools/escodegen\nVersion: <VERSION>\nLicense: BSD-2-Clause\n\nCopyright (C) 2012 Yusuke Suzuki (twitter: @Constellation) and other contributors.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are 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 copyright\n    notice, this list of conditions and the following disclaimer in the\n    documentation and/or other materials provided with the distribution.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\nARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY\nDIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\nLOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\nON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\nTHIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n\n-------------------- DEPENDENCY DIVIDER --------------------\n\nName: estraverse\nURL: https://github.com/estools/estraverse\nVersion: <VERSION>\nLicense: BSD-2-Clause\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are 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 copyright\n    notice, this list of conditions and the following disclaimer in the\n    documentation and/or other materials provided with the distribution.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\nARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY\nDIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\nLOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\nON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\nTHIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n\n-------------------- DEPENDENCY DIVIDER --------------------\n\nName: esutils\nURL: https://github.com/estools/esutils\nVersion: <VERSION>\nLicense: BSD-2-Clause\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are 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 copyright\n    notice, this list of conditions and the following disclaimer in the\n    documentation and/or other materials provided with the distribution.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\nARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY\nDIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\nLOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\nON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\nTHIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n\n-------------------- DEPENDENCY DIVIDER --------------------\n\nName: source-map\nURL: https://github.com/mozilla/source-map\nVersion: <VERSION>\nLicense: BSD-3-Clause\n\n\nCopyright (c) 2009-2011, Mozilla Foundation and contributors\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the names of the Mozilla Foundation nor the names of project\n  contributors may be used to endorse or promote products derived from this\n  software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\nANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\nWARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (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\n-------------------- DEPENDENCY DIVIDER --------------------\n\nName: esprima\nURL: http://esprima.org\nVersion: <VERSION>\nLicense: BSD-2-Clause\n\nCopyright JS Foundation and other contributors, https://js.foundation/\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are 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 copyright\n    notice, this list of conditions and the following disclaimer in the\n    documentation and/or other materials provided with the distribution.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\nARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY\nDIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\nLOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\nON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\nTHIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n\n-------------------- DEPENDENCY DIVIDER --------------------\n\nName: ast-types\nURL: http://github.com/benjamn/ast-types\nVersion: <VERSION>\nLicense: MIT\n\nCopyright (c) 2013 Ben Newman <bn@cs.stanford.edu>\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 NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\nTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n\n-------------------- DEPENDENCY DIVIDER --------------------\n\nName: tslib\nURL: https://www.typescriptlang.org/\nVersion: <VERSION>\nLicense: 0BSD\n\nCopyright (c) Microsoft Corporation.\n\nPermission to use, copy, modify, and/or distribute this software for any\npurpose with or without fee is hereby granted.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH\nREGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY\nAND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,\nINDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM\nLOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR\nOTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR\nPERFORMANCE OF THIS SOFTWARE.\n\n-------------------- DEPENDENCY DIVIDER --------------------\n\nName: netmask\nURL: https://github.com/rs/node-netmask\nVersion: <VERSION>\nLicense: MIT\n\n-------------------- DEPENDENCY DIVIDER --------------------\n\nName: @tootallnate/quickjs-emscripten\nURL: https://github.com/justjake/quickjs-emscripten\nVersion: <VERSION>\nLicense: MIT\n\nMIT License\n\nquickjs-emscripten copyright (c) 2019 Jake Teton-Landis\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\n-------------------- DEPENDENCY DIVIDER --------------------\n\nName: progress\nURL: git://github.com/visionmedia/node-progress\nVersion: <VERSION>\nLicense: MIT\n\n(The MIT License)\n\nCopyright (c) 2017 TJ Holowaychuk <tj@vision-media.ca>\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 NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\nTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n\n-------------------- DEPENDENCY DIVIDER --------------------\n\nName: ws\nURL: https://github.com/websockets/ws\nVersion: <VERSION>\nLicense: MIT\n\nCopyright (c) 2011 Einar Otto Stangvik <einaros@gmail.com>\nCopyright (c) 2013 Arnout Kazemier and contributors\nCopyright (c) 2016 Luigi Pinca and contributors\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\n\n-------------------- DEPENDENCY DIVIDER --------------------\n\nName: chrome-devtools-frontend\nLicense: Apache-2.0\n\n// Copyright 2014 The Chromium Authors\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\n\n-------------------- DEPENDENCY DIVIDER --------------------\n\nName: lighthouse\nLicense: Apache-2.0\n\n\n                                 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 [yyyy] [name of copyright owner]\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-------------------- DEPENDENCY DIVIDER --------------------\n\nName: i18n\nLicense:\n\n\n                                 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 2014 Google 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\n-------------------- DEPENDENCY DIVIDER --------------------\n\nName: intl-messageformat\nLicense:\n\nCopyright (c) 2019, Oath Inc.\n\nLicensed under the terms of the New BSD license. See below for terms.\n\nRedistribution and use of this software in source and binary forms,\nwith or without modification, are permitted provided that the following\nconditions are met:\n\n- Redistributions of source code must retain the above\n  copyright notice, this list of conditions and the\n  following disclaimer.\n\n- Redistributions in binary form must reproduce the above\n  copyright notice, this list of conditions and the\n  following disclaimer in the documentation and/or other\n  materials provided with the distribution.\n\n- Neither the name of Oath Inc. nor the names of its\n  contributors may be used to endorse or promote products\n  derived from this software without specific prior\n  written permission of Oath Inc.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS\nIS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED\nTO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A\nPARTICULAR 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\n-------------------- DEPENDENCY DIVIDER --------------------\n\nName: legacy-javascript\nLicense:\n\n\n                                 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 [yyyy] [name of copyright owner]\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-------------------- DEPENDENCY DIVIDER --------------------\n\nName: marked\nLicense:\n\n## Marked\n\nCopyright (c) 2011-2018, Christopher Jeffrey (https://github.com/chjj/)\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\n## Markdown\n\nCopyright © 2004, John Gruber\nhttp://daringfireball.net/\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* 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* Neither the name “Markdown” nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.\n\nThis software is provided by the copyright holders and contributors “as is” and any express or implied warranties, including, but not limited to,\nthe implied warranties of merchantability and fitness for a particular purpose are disclaimed. In no event shall the copyright owner or contributors be liable for any direct,\nindirect, incidental, special, exemplary, or consequential damages (including, but not limited to, procurement of substitute goods or services; loss of use, data, or profits;\nor 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\nout of the use of this software, even if advised of the possibility of such damage.\n\n\n-------------------- DEPENDENCY DIVIDER --------------------\n\nName: source-map-scopes-codec\nLicense:\n\nCopyright 2025 The Chromium Authors\n\nRedistribution and use in source and binary forms, with or without modification,\nare permitted provided that the following conditions are met:\n\n1. Redistributions of source code must retain the above copyright notice, this\n   list of conditions and the following disclaimer.\n\n2. Redistributions in binary form must reproduce the above copyright notice,\n   this list of conditions and the following disclaimer in the documentation\n   and/or other materials provided with the distribution.\n\n3. Neither the name of the copyright holder nor the names of its contributors\n   may be used to endorse or promote products derived from this software without\n   specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\nANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\nWARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR\nANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\nLOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON\nANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\nSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n-------------------- DEPENDENCY DIVIDER --------------------\n\nName: third-party-web\nLicense:\n\nThe MIT License (MIT)\nCopyright (c) 2019 Patrick Hulce\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-------------------- DEPENDENCY DIVIDER --------------------\n\nName: ms\nURL: N/A\nVersion: <VERSION>\nLicense: MIT\n\nThe MIT License (MIT)\n\nCopyright (c) 2016 Zeit, Inc.\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\n-------------------- DEPENDENCY DIVIDER --------------------\n\nName: debug\nURL: git://github.com/debug-js/debug.git\nVersion: <VERSION>\nLicense: MIT\n\n(The MIT License)\n\nCopyright (c) 2014-2017 TJ Holowaychuk <tj@vision-media.ca>\nCopyright (c) 2018-2021 Josh Junon\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software\nand associated documentation files (the 'Software'), to deal in the Software without restriction,\nincluding without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,\nand/or sell copies of the 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 copies or substantial\nportions of the Software.\n\nTHE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT\nLIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\nWHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n\n\n-------------------- DEPENDENCY DIVIDER --------------------\n\nName: marky\nURL: N/A\nVersion: <VERSION>\nLicense: Apache-2.0\n\nApache License\nVersion 2.0, January 2004\nhttp://www.apache.org/licenses/\n\nTERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n1. Definitions.\n\n    \"License\" shall mean the terms and conditions for use, reproduction, and\n    distribution as defined by Sections 1 through 9 of this document.\n\n    \"Licensor\" shall mean the copyright owner or entity authorized by the\n    copyright owner that is granting the License.\n\n    \"Legal Entity\" shall mean the union of the acting entity and all other\n    entities that control, are controlled by, or are under common control with\n    that entity. For the purposes of this definition, \"control\" means (i) the\n    power, direct or indirect, to cause the direction or management of such\n    entity, whether by contract or otherwise, or (ii) ownership of\n    fifty percent (50%) or more of the outstanding shares, or (iii) beneficial\n    ownership of such entity.\n\n    \"You\" (or \"Your\") shall mean an individual or Legal Entity exercising\n    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 source,\n    and configuration files.\n\n    \"Object\" form shall mean any form resulting from mechanical transformation\n    or translation of a Source form, including but not limited to compiled\n    object code, generated documentation, and conversions to\n    other media types.\n\n    \"Work\" shall mean the work of authorship, whether in Source or Object\n    form, made available under the License, as indicated by a copyright notice\n    that is included in or attached to the work (an example is provided in the\n    Appendix below).\n\n    \"Derivative Works\" shall mean any work, whether in Source or Object form,\n    that is based on (or derived from) the Work and for which the editorial\n    revisions, annotations, elaborations, or other modifications represent,\n    as a whole, an original work of authorship. For the purposes of this\n    License, Derivative Works shall not include works that remain separable\n    from, or merely link (or bind by name) to the interfaces of, the Work and\n    Derivative Works thereof.\n\n    \"Contribution\" shall mean any work of authorship, including the original\n    version of the Work and any modifications or additions to that Work or\n    Derivative Works thereof, that is intentionally submitted to Licensor for\n    inclusion in the Work by the copyright owner or by an individual or\n    Legal Entity authorized to submit on behalf of the copyright owner.\n    For the purposes of this definition, \"submitted\" means any form of\n    electronic, verbal, or written communication sent to the Licensor or its\n    representatives, including but not limited to communication on electronic\n    mailing lists, source code control systems, and issue tracking systems\n    that are managed by, or on behalf of, the Licensor for the purpose of\n    discussing and improving the Work, but excluding communication that is\n    conspicuously marked or otherwise designated in writing by the copyright\n    owner as \"Not a Contribution.\"\n\n    \"Contributor\" shall mean Licensor and any individual or Legal Entity on\n    behalf of whom a Contribution has been received by Licensor and\n    subsequently incorporated within the Work.\n\n2. Grant of Copyright License.\n\n    Subject to the terms and conditions of this License, each Contributor\n    hereby grants to You a perpetual, worldwide, non-exclusive, no-charge,\n    royalty-free, irrevocable copyright license to reproduce, prepare\n    Derivative Works of, publicly display, publicly perform, sublicense,\n    and distribute the Work and such Derivative Works in\n    Source or Object form.\n\n3. Grant of Patent License.\n\n    Subject to the terms and conditions of this License, each Contributor\n    hereby grants to You a perpetual, worldwide, non-exclusive, no-charge,\n    royalty-free, irrevocable (except as stated in this section) patent\n    license to make, have made, use, offer to sell, sell, import, and\n    otherwise transfer the Work, where such license applies only to those\n    patent claims licensable by such Contributor that are necessarily\n    infringed by their Contribution(s) alone or by combination of their\n    Contribution(s) with the Work to which such Contribution(s) was submitted.\n    If You institute patent litigation against any entity (including a\n    cross-claim or counterclaim in a lawsuit) alleging that the Work or a\n    Contribution incorporated within the Work constitutes direct or\n    contributory patent infringement, then any patent licenses granted to\n    You under this License for that Work shall terminate as of the date such\n    litigation is filed.\n\n4. Redistribution.\n\n    You may reproduce and distribute copies of the Work or Derivative Works\n    thereof in any medium, with or without modifications, and in Source or\n    Object form, provided that You meet the following conditions:\n\n    1. You must give any other recipients of the Work or Derivative Works a\n    copy of this License; and\n\n    2. You must cause any modified files to carry prominent notices stating\n    that You changed the files; and\n\n    3. You must retain, in the Source form of any Derivative Works that You\n    distribute, all copyright, patent, trademark, and attribution notices from\n    the Source form of the Work, excluding those notices that do not pertain\n    to any part of the Derivative Works; and\n\n    4. If the Work includes a \"NOTICE\" text file as part of its distribution,\n    then any Derivative Works that You distribute must include a readable copy\n    of the attribution notices contained within such NOTICE file, excluding\n    those notices that do not pertain to any part of the Derivative Works,\n    in at least one of the following places: within a NOTICE text file\n    distributed as part of the Derivative Works; within the Source form or\n    documentation, if provided along with the Derivative Works; or, within a\n    display generated by the Derivative Works, if and wherever such\n    third-party notices normally appear. The contents of the NOTICE file are\n    for informational purposes only and do not modify the License.\n    You may add Your own attribution notices within Derivative Works that You\n    distribute, alongside or as an addendum to the NOTICE text from the Work,\n    provided 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 may\n    provide additional or different license terms and conditions for use,\n    reproduction, or distribution of Your modifications, or for any such\n    Derivative Works as a whole, provided Your use, reproduction, and\n    distribution of the Work otherwise complies with the conditions\n    stated in this License.\n\n5. Submission of Contributions.\n\n    Unless You explicitly state otherwise, any Contribution intentionally\n    submitted for inclusion in the Work by You to the Licensor shall be under\n    the terms and conditions of this License, without any additional\n    terms or conditions. Notwithstanding the above, nothing herein shall\n    supersede or modify the terms of any separate license agreement you may\n    have executed with Licensor regarding such Contributions.\n\n6. Trademarks.\n\n    This License does not grant permission to use the trade names, trademarks,\n    service marks, or product names of the Licensor, except as required for\n    reasonable and customary use in describing the origin of the Work and\n    reproducing the content of the NOTICE file.\n\n7. Disclaimer of Warranty.\n\n    Unless required by applicable law or agreed to in writing, Licensor\n    provides the Work (and each Contributor provides its Contributions)\n    on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,\n    either express or implied, including, without limitation, any warranties\n    or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS\n    FOR A PARTICULAR PURPOSE. You are solely responsible for determining the\n    appropriateness of using or redistributing the Work and assume any risks\n    associated with Your exercise of permissions under this License.\n\n8. Limitation of Liability.\n\n    In no event and under no legal theory, whether in tort\n    (including negligence), contract, or otherwise, unless required by\n    applicable law (such as deliberate and grossly negligent acts) or agreed\n    to in writing, shall any Contributor be liable to You for damages,\n    including any direct, indirect, special, incidental, or consequential\n    damages of any character arising as a result of this License or out of\n    the use or inability to use the Work (including but not limited to damages\n    for loss of goodwill, work stoppage, computer failure or malfunction,\n    or any and all other commercial damages or losses), even if such\n    Contributor has been advised of the possibility of such damages.\n\n9. Accepting Warranty or Additional Liability.\n\n    While redistributing the Work or Derivative Works thereof, You may choose\n    to offer, and charge a fee for, acceptance of support, warranty,\n    indemnity, or other liability obligations and/or rights consistent with\n    this License. However, in accepting such obligations, You may act only\n    on Your own behalf and on Your sole responsibility, not on behalf of any\n    other Contributor, and only if You agree to indemnify, defend, and hold\n    each Contributor harmless for any liability incurred by, or claims\n    asserted against, such Contributor by reason of your accepting any such\n    warranty or additional liability.\n\nEND OF TERMS AND CONDITIONS\n\nAPPENDIX: How to apply the Apache License to your work\n\n    To apply the Apache License to your work, attach the following boilerplate\n    notice, with the fields enclosed by brackets \"[]\" replaced with your own\n    identifying information. (Don't include the brackets!) The text should be\n    enclosed in the appropriate comment syntax for the file format. We also\n    recommend that a file or class name and description of purpose be included\n    on the same \"printed page\" as the copyright notice for easier\n    identification within third-party archives.\n\n        Copyright 2016 Nolan Lawson\n\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\n        or implied. See the License for the specific language governing\n        permissions and limitations under the License.\n\n\n\n-------------------- DEPENDENCY DIVIDER --------------------\n\nName: lodash-es\nURL: N/A\nVersion: <VERSION>\nLicense: MIT\n\nCopyright OpenJS Foundation and other contributors <https://openjsf.org/>\n\nBased on Underscore.js, copyright Jeremy Ashkenas,\nDocumentCloud and Investigative Reporters & Editors <http://underscorejs.org/>\n\nThis software consists of voluntary contributions made by many\nindividuals. For exact contribution history, see the revision history\navailable at https://github.com/lodash/lodash\n\nThe following license applies to all parts of this software except as\ndocumented below:\n\n====\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====\n\nCopyright and related rights for sample code are waived via CC0. Sample\ncode is defined as all source code displayed within the prose of the\ndocumentation.\n\nCC0: http://creativecommons.org/publicdomain/zero/1.0/\n\n====\n\nFiles located in the node_modules and vendor directories are externally\nmaintained libraries used by this software which have their own\nlicenses; we recommend you read them, as their terms may differ from the\nterms above.\n\n\n-------------------- DEPENDENCY DIVIDER --------------------\n\nName: tslib\nURL: N/A\nVersion: <VERSION>\nLicense: 0BSD\n\nCopyright (c) Microsoft Corporation.\n\nPermission to use, copy, modify, and/or distribute this software for any\npurpose with or without fee is hereby granted.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH\nREGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY\nAND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,\nINDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM\nLOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR\nOTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR\nPERFORMANCE OF THIS SOFTWARE.\n\n-------------------- DEPENDENCY DIVIDER --------------------\n\nName: @formatjs/icu-messageformat-parser\nURL: https://github.com/formatjs/formatjs.git\nVersion: <VERSION>\nLicense: MIT\n\nMIT License\n\nCopyright (c) 2021 FormatJS\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n\n-------------------- DEPENDENCY DIVIDER --------------------\n\nName: @formatjs/icu-skeleton-parser\nURL: https://github.com/formatjs/formatjs.git\nVersion: <VERSION>\nLicense: MIT\n\nMIT License\n\nCopyright (c) 2021 FormatJS\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n\n-------------------- DEPENDENCY DIVIDER --------------------\n\nName: @formatjs/fast-memoize\nURL: N/A\nVersion: <VERSION>\nLicense: MIT\n\nMIT License\n\nCopyright (c) 2021 FormatJS\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n\n-------------------- DEPENDENCY DIVIDER --------------------\n\nName: intl-messageformat\nURL: N/A\nVersion: <VERSION>\nLicense: BSD-3-Clause\n\nCopyright (c) 2021, Oath Inc.\n\nLicensed under the terms of the New BSD license. See below for terms.\n\nRedistribution and use of this software in source and binary forms,\nwith or without modification, are permitted provided that the following\nconditions are met:\n\n- Redistributions of source code must retain the above\n  copyright notice, this list of conditions and the\n  following disclaimer.\n\n- Redistributions in binary form must reproduce the above\n  copyright notice, this list of conditions and the\n  following disclaimer in the documentation and/or other\n  materials provided with the distribution.\n\n- Neither the name of Oath Inc. nor the names of its\n  contributors may be used to endorse or promote products\n  derived from this software without specific prior\n  written permission of Oath Inc.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS\nIS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED\nTO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A\nPARTICULAR 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\n-------------------- DEPENDENCY DIVIDER --------------------\n\nName: lighthouse-stack-packs\nURL: N/A\nVersion: <VERSION>\nLicense: Apache-2.0\n\n\n                                 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 [yyyy] [name of copyright owner]\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-------------------- DEPENDENCY DIVIDER --------------------\n\nName: lookup-closest-locale\nURL: N/A\nVersion: <VERSION>\nLicense: MIT\n\n-------------------- DEPENDENCY DIVIDER --------------------\n\nName: @paulirish/trace_engine\nURL: N/A\nVersion: <VERSION>\nLicense: BSD-3-Clause\n\n// Copyright 2014 The Chromium Authors\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\n\n-------------------- DEPENDENCY DIVIDER --------------------\n\nName: third-party-web\nURL: https://github.com/patrickhulce/third-party-web.git\nVersion: <VERSION>\nLicense: MIT\n\nThe MIT License (MIT)\nCopyright (c) 2019 Patrick Hulce\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\n-------------------- DEPENDENCY DIVIDER --------------------\n\nName: legacy-javascript\nURL: N/A\nVersion: <VERSION>\nLicense: Apache-2.0\n\n-------------------- DEPENDENCY DIVIDER --------------------\n\nName: tldts-icann\nURL: N/A\nVersion: <VERSION>\nLicense: MIT\n\nCopyright (c) 2017 Thomas Parisot, 2018 Rémi Berson\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and\nassociated documentation files (the \"Software\"), to deal in the Software without restriction,\nincluding without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,\nand/or sell copies of the 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 copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n\n-------------------- DEPENDENCY DIVIDER --------------------\n\nName: http-link-header\nURL: N/A\nVersion: <VERSION>\nLicense: MIT\n\n# The MIT License (MIT)\nCopyright (c) 2016 Jonas Hermsmeier\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,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,\nDAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\nOTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE\nOR OTHER DEALINGS IN THE SOFTWARE.\n\n\n-------------------- DEPENDENCY DIVIDER --------------------\n\nName: csp_evaluator\nURL: N/A\nVersion: <VERSION>\nLicense: Apache-2.0\n\n\n                                 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 [yyyy] [name of copyright owner]\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-------------------- DEPENDENCY DIVIDER --------------------\n\nName: robots-parser\nURL: N/A\nVersion: <VERSION>\nLicense: MIT\n\nThe MIT License (MIT)\n\nCopyright (c) 2014 Sam Clarke\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\n`;\n"
  },
  {
    "path": "tests/third_party_notices.test.ts",
    "content": "/**\n * @license\n * Copyright 2025 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport {describe, it} from 'node:test';\n\ndescribe('THIRD_PARTY_NOTICES', () => {\n  it('matches snapshot if exists', t => {\n    const noticesPath = path.join(\n      process.cwd(),\n      'build/src/third_party/THIRD_PARTY_NOTICES',\n    );\n    if (fs.existsSync(noticesPath)) {\n      const content = fs.readFileSync(noticesPath, 'utf-8');\n      const normalizedContent = content\n        .replace(/^Version: .*$/gm, 'Version: <VERSION>')\n        .replaceAll('\\r', '');\n      t.assert.snapshot?.(normalizedContent);\n    }\n  });\n});\n"
  },
  {
    "path": "tests/tools/console.test.js.snapshot",
    "content": "exports[`console > get_console_message > applies source maps to stack traces of Error object (with cause) console.log arguments 1`] = `\nID: 1\nMessage: log> foo failed Error: bar failed\n### Arguments\nArg #0: foo failed\nArg #1: Error: bar failed\nat foo (main.js:10:11)\nat Iife (main.js:16:5)\nat <anonymous> (main.js:14:1)\nCaused by: Error: b00m!\nat bar (main.js:3:9)\nat foo (main.js:8:5)\nat Iife (main.js:16:5)\nat <anonymous> (main.js:14:1)\nNote: line and column numbers use 1-based indexing\n### Stack trace\nat Iife (main.js:18:13)\nat <anonymous> (main.js:14:1)\nNote: line and column numbers use 1-based indexing\n`;\n\nexports[`console > get_console_message > applies source maps to stack traces of Error object console.log arguments 1`] = `\nID: 1\nMessage: log> An error happened: Error: b00m!\n### Arguments\nArg #0: An error happened:\nArg #1: Error: b00m!\nat bar (main.js:3:9)\nat foo (main.js:7:3)\nat Iife (main.js:12:5)\nat <anonymous> (main.js:10:1)\nNote: line and column numbers use 1-based indexing\n### Stack trace\nat Iife (main.js:14:13)\nat <anonymous> (main.js:10:1)\nNote: line and column numbers use 1-based indexing\n`;\n\nexports[`console > get_console_message > applies source maps to stack traces of console messages 1`] = `\nID: 1\nMessage: warn> hello world\n### Arguments\nArg #0: hello world\n### Stack trace\nat bar (main.js:3:11)\nat foo (main.js:7:3)\nat Iife (main.js:11:3)\nat <anonymous> (main.js:10:1)\nNote: line and column numbers use 1-based indexing\n`;\n\nexports[`console > get_console_message > applies source maps to stack traces of uncaught exceptions 1`] = `\nID: 1\nMessage: error> Uncaught Error: b00m!\n### Stack trace\nat bar (main.js:3:9)\nat foo (main.js:7:3)\nat Iife (main.js:11:3)\nat <anonymous> (main.js:10:1)\nNote: line and column numbers use 1-based indexing\n`;\n\nexports[`console > get_console_message > applies source maps to stack traces of uncaught exceptions with cause 1`] = `\nID: 1\nMessage: error> Uncaught Error: foo failed\n### Stack trace\nat Iife (main.js:18:11)\nat <anonymous> (main.js:14:1)\nCaused by: Error: bar failed\nat foo (main.js:10:11)\nat Iife (main.js:16:5)\nat <anonymous> (main.js:14:1)\nCaused by: Error: b00m!\nat bar (main.js:3:9)\nat foo (main.js:8:5)\nat Iife (main.js:16:5)\nat <anonymous> (main.js:14:1)\nNote: line and column numbers use 1-based indexing\n`;\n\nexports[`console > get_console_message > ignores frames from ignore listed URLs 1`] = `\nID: 1\nMessage: log> hello from callback\n### Arguments\nArg #0: hello from callback\n### Stack trace\nat callback ('main.js':3:21)\nat callIt ('main.js':7:13)\nat  ('main.js':8:13)\nNote: line and column numbers use 1-based indexing\n`;\n\nexports[`console > get_console_message > issues type > gets issue details with node id parsing 1`] = `\nID: 1\nMessage: issue> An element doesn't have an autocomplete attribute\n\nA form field has an \\`id\\` or \\`name\\` attribute that the browser's autofill recognizes. However, it doesn't have an \\`autocomplete\\` attribute assigned. This might prevent the browser from correctly autofilling the form.\n\nTo fix this issue, provide an \\`autocomplete\\` attribute.\nLearn more:\n[HTML attribute: autocomplete](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/autocomplete#values)\n### Affected resources\nuid=1_1 data={\"violatingNodeAttribute\":\"name\"}\n`;\n\nexports[`console > get_console_message > issues type > gets issue details with request id parsing 1`] = `\nID: <ID>\nMessage: issue> Ensure CORS response header values are valid\n\nA cross-origin resource sharing (CORS) request was blocked because of invalid or missing response headers of the request or the associated [preflight request](issueCorsPreflightRequest).\n\nTo fix this issue, ensure the response to the CORS request and/or the associated [preflight request](issueCorsPreflightRequest) are not missing headers and use valid header values.\n\nNote that if an opaque response is sufficient, the request's mode can be set to \\`no-cors\\` to fetch the resource with CORS disabled; that way CORS headers are not required but the response content is inaccessible (opaque).\nLearn more:\n[Cross-Origin Resource Sharing (\\`CORS\\`)](https://web.dev/cross-origin-resource-sharing)\n### Affected resources\nreqid=<reqid> data={\"corsErrorStatus\":{\"corsError\":\"PreflightMissingAllowOriginHeader\",\"failedParameter\":\"\"},\"isWarning\":false,\"request\":{\"url\":\"http://hostname:port/data.json\"},\"initiatorOrigin\":\"\",\"clientSecurityState\":{\"initiatorIsSecureContext\":false,\"initiatorIPAddressSpace\":\"Loopback\",\"localNetworkAccessRequestPolicy\":\"BlockFromInsecureToMorePrivate\"}}\n`;\n\nexports[`console > list_console_messages > lists error objects 1`] = `\n## Console messages\nShowing 1-1 of 1 (Page 1 of 1).\nmsgid=1 [error] Error: This is an error (1 args)\n`;\n"
  },
  {
    "path": "tests/tools/console.test.ts",
    "content": "/**\n * @license\n * Copyright 2025 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport assert from 'node:assert';\nimport {before, describe, it} from 'node:test';\n\nimport type {ParsedArguments} from '../../src/bin/chrome-devtools-mcp-cli-options.js';\nimport {loadIssueDescriptions} from '../../src/issue-descriptions.js';\nimport {McpResponse} from '../../src/McpResponse.js';\nimport {DevTools} from '../../src/third_party/index.js';\nimport {\n  getConsoleMessage,\n  listConsoleMessages,\n} from '../../src/tools/console.js';\nimport {serverHooks} from '../server.js';\nimport {getTextContent, withMcpContext} from '../utils.js';\n\ndescribe('console', () => {\n  before(async () => {\n    await loadIssueDescriptions();\n  });\n  describe('list_console_messages', () => {\n    it('list messages', async () => {\n      await withMcpContext(async (response, context) => {\n        await listConsoleMessages.handler(\n          {params: {}, page: context.getSelectedMcpPage()},\n          response,\n          context,\n        );\n        assert.ok(response.includeConsoleData);\n      });\n    });\n\n    it('lists error messages', async () => {\n      await withMcpContext(async (response, context) => {\n        const page = context.getSelectedMcpPage();\n        await page.pptrPage.setContent(\n          '<script>console.error(\"This is an error\")</script>',\n        );\n        await listConsoleMessages.handler(\n          {params: {}, page: context.getSelectedMcpPage()},\n          response,\n          context,\n        );\n        const formattedResponse = await response.handle('test', context);\n        const textContent = getTextContent(formattedResponse.content[0]);\n        assert.ok(textContent.includes('msgid=1 [error] This is an error'));\n      });\n    });\n\n    it('lists error objects', async t => {\n      await withMcpContext(async (response, context) => {\n        const page = context.getSelectedMcpPage();\n        await page.pptrPage.setContent(\n          '<script>console.error(new Error(\"This is an error\"))</script>',\n        );\n        await listConsoleMessages.handler(\n          {params: {}, page: context.getSelectedMcpPage()},\n          response,\n          context,\n        );\n        const formattedResponse = await response.handle('test', context);\n        const textContent = getTextContent(formattedResponse.content[0]);\n        t.assert.snapshot?.(textContent);\n      });\n    });\n\n    it('work with primitive unhandled errors', async () => {\n      await withMcpContext(async (response, context) => {\n        const page = context.getSelectedMcpPage();\n        await page.pptrPage.setContent('<script>throw undefined;</script>');\n        await listConsoleMessages.handler(\n          {params: {}, page: context.getSelectedMcpPage()},\n          response,\n          context,\n        );\n        const formattedResponse = await response.handle('test', context);\n        const textContent = getTextContent(formattedResponse.content[0]);\n        assert.ok(textContent.includes('msgid=1 [error] Uncaught  (0 args)'));\n      });\n    });\n\n    describe('issues', () => {\n      it('lists issues', async () => {\n        await withMcpContext(async (response, context) => {\n          const page = context.getSelectedMcpPage();\n          const issuePromise = new Promise<void>(resolve => {\n            page.pptrPage.once('issue', () => {\n              resolve();\n            });\n          });\n          await page.pptrPage.setContent(\n            '<input type=\"text\" name=\"username\" />',\n          );\n          await issuePromise;\n          await listConsoleMessages.handler(\n            {params: {}, page: context.getSelectedMcpPage()},\n            response,\n            context,\n          );\n          const formattedResponse = await response.handle('test', context);\n          const textContent = getTextContent(formattedResponse.content[0]);\n          assert.ok(\n            textContent.includes(\n              `msgid=1 [issue] An element doesn't have an autocomplete attribute (count: 1)`,\n            ),\n          );\n        });\n      });\n\n      it('lists issues after a page reload', async () => {\n        await withMcpContext(async (response, context) => {\n          const page = await context.newPage();\n          response.setPage(page);\n          const issuePromise = new Promise<void>(resolve => {\n            page.pptrPage.once('issue', () => {\n              resolve();\n            });\n          });\n\n          await page.pptrPage.setContent(\n            '<input type=\"text\" name=\"username\" />',\n          );\n          await issuePromise;\n          await listConsoleMessages.handler(\n            {params: {}, page: context.getSelectedMcpPage()},\n            response,\n            context,\n          );\n          {\n            const formattedResponse = await response.handle('test', context);\n            const textContent = getTextContent(formattedResponse.content[0]);\n            assert.ok(\n              textContent.includes(\n                `msgid=1 [issue] An element doesn't have an autocomplete attribute (count: 1)`,\n              ),\n            );\n          }\n\n          const anotherIssuePromise = new Promise<void>(resolve => {\n            page.pptrPage.once('issue', () => {\n              resolve();\n            });\n          });\n          await page.pptrPage.reload();\n          await page.pptrPage.setContent(\n            '<input type=\"text\" name=\"username\" />',\n          );\n          await anotherIssuePromise;\n          {\n            const formattedResponse = await response.handle('test', context);\n            const textContent = getTextContent(formattedResponse.content[0]);\n            assert.ok(\n              textContent.includes(\n                `msgid=2 [issue] An element doesn't have an autocomplete attribute (count: 1)`,\n              ),\n            );\n          }\n        });\n      });\n    });\n  });\n\n  describe('get_console_message', () => {\n    const server = serverHooks();\n\n    it('gets a specific console message', async () => {\n      await withMcpContext(async (response, context) => {\n        const page = context.getSelectedMcpPage();\n        await page.pptrPage.setContent(\n          '<script>console.error(\"This is an error\")</script>',\n        );\n        // The list is needed to populate the console messages in the context.\n        await listConsoleMessages.handler(\n          {params: {}, page: context.getSelectedMcpPage()},\n          response,\n          context,\n        );\n        await getConsoleMessage.handler(\n          {params: {msgid: 1}, page: context.getSelectedMcpPage()},\n          response,\n          context,\n        );\n        const formattedResponse = await response.handle('test', context);\n        const textContent = getTextContent(formattedResponse.content[0]);\n        assert.ok(\n          textContent.includes('msgid=1 [error] This is an error'),\n          'Should contain console message body',\n        );\n      });\n    });\n\n    describe('issues type', () => {\n      it('gets issue details with node id parsing', async t => {\n        await withMcpContext(async (response, context) => {\n          const page = context.getSelectedMcpPage();\n          const issuePromise = new Promise<void>(resolve => {\n            page.pptrPage.once('issue', () => {\n              resolve();\n            });\n          });\n          await page.pptrPage.setContent(\n            '<input type=\"text\" name=\"username\" />',\n          );\n          await context.createTextSnapshot(page);\n          await issuePromise;\n          await listConsoleMessages.handler(\n            {params: {}, page: context.getSelectedMcpPage()},\n            response,\n            context,\n          );\n          const response2 = new McpResponse({} as ParsedArguments);\n          response2.setPage(context.getSelectedMcpPage());\n          await getConsoleMessage.handler(\n            {params: {msgid: 1}, page: context.getSelectedMcpPage()},\n            response2,\n            context,\n          );\n          const formattedResponse = await response2.handle('test', context);\n          t.assert.snapshot?.(getTextContent(formattedResponse.content[0]));\n        });\n      });\n      it('gets issue details with request id parsing', async t => {\n        server.addRoute('/data.json', (_req, res) => {\n          res.setHeader('Content-Type', 'application/json');\n          res.statusCode = 200;\n          res.end(JSON.stringify({data: 'test data'}));\n        });\n\n        await withMcpContext(async (response, context) => {\n          const page = context.getSelectedMcpPage();\n          const issuePromise = new Promise<void>(resolve => {\n            page.pptrPage.once('issue', () => {\n              resolve();\n            });\n          });\n\n          const url = server.getRoute('/data.json');\n          await page.pptrPage.setContent(`\n            <script>\n              fetch('${url}', {\n                  method: 'GET',\n                  headers: {\n                      'Content-Type': 'application/json',\n                      'X-Custom-Header': 'MyValue'\n                  }\n              });\n            </script>\n          `);\n          await context.createTextSnapshot(page);\n          await issuePromise;\n          const messages = context.getConsoleData(page);\n          let issueMsg;\n          for (const message of messages) {\n            if (message instanceof DevTools.AggregatedIssue) {\n              issueMsg = message;\n              break;\n            }\n          }\n          assert.ok(issueMsg);\n          const id = context.getConsoleMessageStableId(issueMsg);\n          assert.ok(id);\n          await listConsoleMessages.handler(\n            {params: {types: ['issue']}, page: context.getSelectedMcpPage()},\n            response,\n            context,\n          );\n          const response2 = new McpResponse({} as ParsedArguments);\n          response2.setPage(context.getSelectedMcpPage());\n          await getConsoleMessage.handler(\n            {params: {msgid: id}, page: context.getSelectedMcpPage()},\n            response2,\n            context,\n          );\n          const formattedResponse = await response2.handle('test', context);\n          const rawText = getTextContent(formattedResponse.content[0]);\n          const sanitizedText = rawText\n            .replaceAll(/ID: \\d+/g, 'ID: <ID>')\n            .replaceAll(/reqid=\\d+/g, 'reqid=<reqid>')\n            .replaceAll(/localhost:\\d+/g, 'hostname:port');\n          t.assert.snapshot?.(sanitizedText);\n        });\n      });\n    });\n\n    it('applies source maps to stack traces of console messages', async t => {\n      server.addRoute('/main.min.js', (_req, res) => {\n        res.setHeader('Content-Type', 'text/javascript');\n        res.statusCode = 200;\n        res.end(`function n(){console.warn(\"hello world\")}function o(){n()}(function n(){o()})();\n          //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJiYXIiLCJjb25zb2xlIiwid2FybiIsImZvbyIsIklpZmUiXSwic291cmNlcyI6WyIuL21haW4uanMiXSwic291cmNlc0NvbnRlbnQiOlsiXG5mdW5jdGlvbiBiYXIoKSB7XG4gIGNvbnNvbGUud2FybignaGVsbG8gd29ybGQnKTtcbn1cblxuZnVuY3Rpb24gZm9vKCkge1xuICBiYXIoKTtcbn1cblxuKGZ1bmN0aW9uIElpZmUoKSB7XG4gIGZvbygpO1xufSkoKTtcblxuIl0sIm1hcHBpbmdzIjoiQUFDQSxTQUFTQSxJQUNQQyxRQUFRQyxLQUFLLGNBQ2YsQ0FFQSxTQUFTQyxJQUNQSCxHQUNGLEVBRUEsU0FBVUksSUFDUkQsR0FDRCxFQUZEIiwiaWdub3JlTGlzdCI6W119\n          `);\n      });\n      server.addHtmlRoute(\n        '/index.html',\n        `<script src=\"${server.getRoute('/main.min.js')}\"></script>`,\n      );\n\n      await withMcpContext(async (response, context) => {\n        const page = context.getSelectedMcpPage();\n        await page.pptrPage.goto(server.getRoute('/index.html'));\n\n        await getConsoleMessage.handler(\n          {params: {msgid: 1}, page: context.getSelectedMcpPage()},\n          response,\n          context,\n        );\n        const formattedResponse = await response.handle('test', context);\n        const rawText = getTextContent(formattedResponse.content[0]);\n\n        t.assert.snapshot?.(rawText);\n      });\n    });\n\n    it('applies source maps to stack traces of uncaught exceptions', async t => {\n      server.addRoute('/main.min.js', (_req, res) => {\n        res.setHeader('Content-Type', 'text/javascript');\n        res.statusCode = 200;\n        res.end(`function n(){throw new Error(\"b00m!\")}function o(){n()}(function n(){o()})();\n          //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJiYXIiLCJFcnJvciIsImZvbyIsIklpZmUiXSwic291cmNlcyI6WyIuL21haW4uanMiXSwic291cmNlc0NvbnRlbnQiOlsiXG5mdW5jdGlvbiBiYXIoKSB7XG4gIHRocm93IG5ldyBFcnJvcignYjAwbSEnKTtcbn1cblxuZnVuY3Rpb24gZm9vKCkge1xuICBiYXIoKTtcbn1cblxuKGZ1bmN0aW9uIElpZmUoKSB7XG4gIGZvbygpO1xufSkoKTtcblxuIl0sIm1hcHBpbmdzIjoiQUFDQSxTQUFTQSxJQUNQLE1BQU0sSUFBSUMsTUFBTSxRQUNsQixDQUVBLFNBQVNDLElBQ1BGLEdBQ0YsRUFFQSxTQUFVRyxJQUNSRCxHQUNELEVBRkQiLCJpZ25vcmVMaXN0IjpbXX0=\n        `);\n      });\n      server.addHtmlRoute(\n        '/index.html',\n        `<script src=\"${server.getRoute('/main.min.js')}\"></script>`,\n      );\n\n      await withMcpContext(async (response, context) => {\n        const page = context.getSelectedMcpPage();\n        await page.pptrPage.goto(server.getRoute('/index.html'));\n\n        await getConsoleMessage.handler(\n          {params: {msgid: 1}, page: context.getSelectedMcpPage()},\n          response,\n          context,\n        );\n        const formattedResponse = await response.handle('test', context);\n        const rawText = getTextContent(formattedResponse.content[0]);\n\n        t.assert.snapshot?.(rawText);\n      });\n    });\n\n    it('applies source maps to stack traces of Error object console.log arguments', async t => {\n      server.addRoute('/main.min.js', (_req, res) => {\n        res.setHeader('Content-Type', 'text/javascript');\n        res.statusCode = 200;\n        res.end(`function n(){throw new Error(\"b00m!\")}function o(){n()}(function n(){try{o()}catch(n){console.log(\"An error happened:\",n)}})();\n          //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJiYXIiLCJFcnJvciIsImZvbyIsIklpZmUiLCJlIiwiY29uc29sZSIsImxvZyJdLCJzb3VyY2VzIjpbIi4vbWFpbi5qcyJdLCJzb3VyY2VzQ29udGVudCI6WyJcbmZ1bmN0aW9uIGJhcigpIHtcbiAgdGhyb3cgbmV3IEVycm9yKCdiMDBtIScpO1xufVxuXG5mdW5jdGlvbiBmb28oKSB7XG4gIGJhcigpO1xufVxuXG4oZnVuY3Rpb24gSWlmZSgpIHtcbiAgdHJ5IHtcbiAgICBmb28oKTtcbiAgfSBjYXRjaCAoZSkge1xuICAgIGNvbnNvbGUubG9nKCdBbiBlcnJvciBoYXBwZW5lZDonLCBlKTtcbiAgfVxufSkoKTtcblxuIl0sIm1hcHBpbmdzIjoiQUFDQSxTQUFTQSxJQUNQLE1BQU0sSUFBSUMsTUFBTSxRQUNsQixDQUVBLFNBQVNDLElBQ1BGLEdBQ0YsRUFFQSxTQUFVRyxJQUNSLElBQ0VELEdBQ0YsQ0FBRSxNQUFPRSxHQUNQQyxRQUFRQyxJQUFJLHFCQUFzQkYsRUFDcEMsQ0FDRCxFQU5EIiwiaWdub3JlTGlzdCI6W119\n        `);\n      });\n      server.addHtmlRoute(\n        '/index.html',\n        `<script src=\"${server.getRoute('/main.min.js')}\"></script>`,\n      );\n\n      await withMcpContext(async (response, context) => {\n        const page = context.getSelectedMcpPage();\n        await page.pptrPage.goto(server.getRoute('/index.html'));\n\n        await getConsoleMessage.handler(\n          {params: {msgid: 1}, page: context.getSelectedMcpPage()},\n          response,\n          context,\n        );\n        const formattedResponse = await response.handle('test', context);\n        const rawText = getTextContent(formattedResponse.content[0]);\n\n        t.assert.snapshot?.(rawText);\n      });\n    });\n\n    it('applies source maps to stack traces of uncaught exceptions with cause', async t => {\n      server.addRoute('/main.min.js', (_req, res) => {\n        res.setHeader('Content-Type', 'text/javascript');\n        res.statusCode = 200;\n        res.end(`function r(){throw new Error(\"b00m!\")}function o(){try{r()}catch(r){throw new Error(\"bar failed\",{cause:r})}}(function r(){try{o()}catch(r){throw new Error(\"foo failed\",{cause:r})}})();\n          //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJiYXIiLCJFcnJvciIsImZvbyIsImUiLCJjYXVzZSIsIklpZmUiXSwic291cmNlcyI6WyIuL21haW4uanMiXSwic291cmNlc0NvbnRlbnQiOlsiXG5mdW5jdGlvbiBiYXIoKSB7XG4gIHRocm93IG5ldyBFcnJvcignYjAwbSEnKTtcbn1cblxuZnVuY3Rpb24gZm9vKCkge1xuICB0cnkge1xuICAgIGJhcigpO1xuICB9IGNhdGNoIChlKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdiYXIgZmFpbGVkJywgeyBjYXVzZTogZSB9KTtcbiAgfVxufVxuXG4oZnVuY3Rpb24gSWlmZSgpIHtcbiAgdHJ5IHtcbiAgICBmb28oKTtcbiAgfSBjYXRjaCAoZSkge1xuICAgIHRocm93IG5ldyBFcnJvcignZm9vIGZhaWxlZCcsIHsgY2F1c2U6IGUgfSk7XG4gIH1cbn0pKCk7XG5cbiJdLCJtYXBwaW5ncyI6IkFBQ0EsU0FBU0EsSUFDUCxNQUFNLElBQUlDLE1BQU0sUUFDbEIsQ0FFQSxTQUFTQyxJQUNQLElBQ0VGLEdBQ0YsQ0FBRSxNQUFPRyxHQUNQLE1BQU0sSUFBSUYsTUFBTSxhQUFjLENBQUVHLE1BQU9ELEdBQ3pDLENBQ0YsRUFFQSxTQUFVRSxJQUNSLElBQ0VILEdBQ0YsQ0FBRSxNQUFPQyxHQUNQLE1BQU0sSUFBSUYsTUFBTSxhQUFjLENBQUVHLE1BQU9ELEdBQ3pDLENBQ0QsRUFORCIsImlnbm9yZUxpc3QiOltdfQ==\n        `);\n      });\n      server.addHtmlRoute(\n        '/index.html',\n        `<script src=\"${server.getRoute('/main.min.js')}\"></script>`,\n      );\n\n      await withMcpContext(async (response, context) => {\n        const page = context.getSelectedMcpPage();\n        await page.pptrPage.goto(server.getRoute('/index.html'));\n\n        await getConsoleMessage.handler(\n          {params: {msgid: 1}, page: context.getSelectedMcpPage()},\n          response,\n          context,\n        );\n        const formattedResponse = await response.handle('test', context);\n        const rawText = getTextContent(formattedResponse.content[0]);\n\n        t.assert.snapshot?.(rawText);\n      });\n    });\n\n    it('applies source maps to stack traces of Error object (with cause) console.log arguments', async t => {\n      server.addRoute('/main.min.js', (_req, res) => {\n        res.setHeader('Content-Type', 'text/javascript');\n        res.statusCode = 200;\n        res.end(`function o(){throw new Error(\"b00m!\")}function r(){try{o()}catch(o){throw new Error(\"bar failed\",{cause:o})}}(function o(){try{r()}catch(o){console.log(\"foo failed\",o)}})();\n          //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJiYXIiLCJFcnJvciIsImZvbyIsImUiLCJjYXVzZSIsIklpZmUiLCJjb25zb2xlIiwibG9nIl0sInNvdXJjZXMiOlsiLi9tYWluLmpzIl0sInNvdXJjZXNDb250ZW50IjpbIlxuZnVuY3Rpb24gYmFyKCkge1xuICB0aHJvdyBuZXcgRXJyb3IoJ2IwMG0hJyk7XG59XG5cbmZ1bmN0aW9uIGZvbygpIHtcbiAgdHJ5IHtcbiAgICBiYXIoKTtcbiAgfSBjYXRjaCAoZSkge1xuICAgIHRocm93IG5ldyBFcnJvcignYmFyIGZhaWxlZCcsIHsgY2F1c2U6IGUgfSk7XG4gIH1cbn1cblxuKGZ1bmN0aW9uIElpZmUoKSB7XG4gIHRyeSB7XG4gICAgZm9vKCk7XG4gIH0gY2F0Y2ggKGUpIHtcbiAgICBjb25zb2xlLmxvZygnZm9vIGZhaWxlZCcsIGUpO1xuICB9XG59KSgpO1xuXG4iXSwibWFwcGluZ3MiOiJBQUNBLFNBQVNBLElBQ1AsTUFBTSxJQUFJQyxNQUFNLFFBQ2xCLENBRUEsU0FBU0MsSUFDUCxJQUNFRixHQUNGLENBQUUsTUFBT0csR0FDUCxNQUFNLElBQUlGLE1BQU0sYUFBYyxDQUFFRyxNQUFPRCxHQUN6QyxDQUNGLEVBRUEsU0FBVUUsSUFDUixJQUNFSCxHQUNGLENBQUUsTUFBT0MsR0FDUEcsUUFBUUMsSUFBSSxhQUFjSixFQUM1QixDQUNELEVBTkQiLCJpZ25vcmVMaXN0IjpbXX0=\n        `);\n      });\n      server.addHtmlRoute(\n        '/index.html',\n        `<script src=\"${server.getRoute('/main.min.js')}\"></script>`,\n      );\n\n      await withMcpContext(async (response, context) => {\n        const page = context.getSelectedMcpPage();\n        await page.pptrPage.goto(server.getRoute('/index.html'));\n\n        await getConsoleMessage.handler(\n          {params: {msgid: 1}, page: context.getSelectedMcpPage()},\n          response,\n          context,\n        );\n        const formattedResponse = await response.handle('test', context);\n        const rawText = getTextContent(formattedResponse.content[0]);\n\n        t.assert.snapshot?.(rawText);\n      });\n    });\n\n    it('ignores frames from ignore listed URLs', async t => {\n      server.addHtmlRoute(\n        '/index.html',\n        `<!DOCTYPE html>\n         <script>\n         function ignoredFn1(cb) {\n          ignoredFn2(cb);\n         }\n\n         function ignoredFn2(cb) {\n          cb();\n         }\n         //# sourceURL=./node_modules/foo.js\n         </script>\n         <script>\n          function callback() {\n            console.log('hello from callback');\n          }\n\n          (function callIt() {\n            ignoredFn1(callback);\n          })();\n         //# sourceURL='main.js'\n         </script>\n        `,\n      );\n\n      await withMcpContext(async (response, context) => {\n        const page = context.getSelectedMcpPage();\n        await page.pptrPage.goto(server.getRoute('/index.html'));\n\n        await getConsoleMessage.handler(\n          {params: {msgid: 1}, page: context.getSelectedMcpPage()},\n          response,\n          context,\n        );\n        const formattedResponse = await response.handle('test', context);\n        const rawText = getTextContent(formattedResponse.content[0]);\n\n        t.assert.snapshot?.(rawText);\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "tests/tools/emulation.test.ts",
    "content": "/**\n * @license\n * Copyright 2025 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport assert from 'node:assert';\nimport {beforeEach, describe, it} from 'node:test';\n\nimport {emulate} from '../../src/tools/emulation.js';\nimport {\n  geolocationTransform,\n  viewportTransform,\n} from '../../src/tools/ToolDefinition.js';\nimport {serverHooks} from '../server.js';\nimport {html, withMcpContext} from '../utils.js';\n\ndescribe('emulation', () => {\n  const server = serverHooks();\n\n  describe('transforms', () => {\n    describe('viewportTransform', () => {\n      it('returns undefined for undefined input', () => {\n        assert.strictEqual(viewportTransform(undefined), undefined);\n      });\n\n      it('parses basic dimensions', () => {\n        assert.deepStrictEqual(viewportTransform('800x600'), {\n          width: 800,\n          height: 600,\n          deviceScaleFactor: undefined,\n          isMobile: false,\n          isLandscape: false,\n          hasTouch: false,\n        });\n      });\n\n      it('parses dimensions with devicePixelRatio', () => {\n        assert.deepStrictEqual(viewportTransform('1024x768x2'), {\n          width: 1024,\n          height: 768,\n          deviceScaleFactor: 2,\n          isMobile: false,\n          isLandscape: false,\n          hasTouch: false,\n        });\n      });\n\n      it('parses mobile and touch tags', () => {\n        assert.deepStrictEqual(viewportTransform('375x667x2,mobile,touch'), {\n          width: 375,\n          height: 667,\n          deviceScaleFactor: 2,\n          isMobile: true,\n          hasTouch: true,\n          isLandscape: false,\n        });\n      });\n\n      it('parses landscape tag', () => {\n        assert.deepStrictEqual(viewportTransform('1024x768x1,landscape'), {\n          width: 1024,\n          height: 768,\n          deviceScaleFactor: 1,\n          isMobile: false,\n          hasTouch: false,\n          isLandscape: true,\n        });\n      });\n    });\n\n    describe('geolocationTransform', () => {\n      it('returns undefined for undefined input', () => {\n        assert.strictEqual(geolocationTransform(undefined), undefined);\n      });\n\n      it('parses latitude and longitude', () => {\n        assert.deepStrictEqual(geolocationTransform('48.137154x11.576124'), {\n          latitude: 48.137154,\n          longitude: 11.576124,\n        });\n      });\n    });\n  });\n\n  describe('network', () => {\n    it('emulates offline network conditions', async () => {\n      await withMcpContext(async (response, context) => {\n        await emulate.handler(\n          {\n            params: {\n              networkConditions: 'Offline',\n            },\n            page: context.getSelectedMcpPage(),\n          },\n          response,\n          context,\n        );\n\n        assert.strictEqual(\n          context.getSelectedMcpPage().networkConditions,\n          'Offline',\n        );\n      });\n    });\n    it('emulates network throttling when the throttling option is valid', async () => {\n      await withMcpContext(async (response, context) => {\n        await emulate.handler(\n          {\n            params: {\n              networkConditions: 'Slow 3G',\n            },\n            page: context.getSelectedMcpPage(),\n          },\n          response,\n          context,\n        );\n\n        assert.strictEqual(\n          context.getSelectedMcpPage().networkConditions,\n          'Slow 3G',\n        );\n      });\n    });\n\n    it('disables network emulation', async () => {\n      await withMcpContext(async (response, context) => {\n        await emulate.handler(\n          {\n            params: {},\n            page: context.getSelectedMcpPage(),\n          },\n          response,\n          context,\n        );\n\n        assert.strictEqual(\n          context.getSelectedMcpPage().networkConditions,\n          null,\n        );\n      });\n    });\n\n    it('does not set throttling when the network throttling is not one of the predefined options', async () => {\n      await withMcpContext(async (response, context) => {\n        await emulate.handler(\n          {\n            params: {\n              networkConditions: 'Slow 11G',\n            },\n            page: context.getSelectedMcpPage(),\n          },\n          response,\n          context,\n        );\n\n        assert.strictEqual(\n          context.getSelectedMcpPage().networkConditions,\n          null,\n        );\n      });\n    });\n\n    it('report correctly for the currently selected page', async () => {\n      await withMcpContext(async (response, context) => {\n        await emulate.handler(\n          {\n            params: {\n              networkConditions: 'Slow 3G',\n            },\n            page: context.getSelectedMcpPage(),\n          },\n          response,\n          context,\n        );\n\n        assert.strictEqual(\n          context.getSelectedMcpPage().networkConditions,\n          'Slow 3G',\n        );\n\n        const page = await context.newPage();\n        context.selectPage(page);\n\n        assert.strictEqual(\n          context.getSelectedMcpPage().networkConditions,\n          null,\n        );\n      });\n    });\n  });\n\n  describe('cpu', () => {\n    it('emulates cpu throttling when the rate is valid (1-20x)', async () => {\n      await withMcpContext(async (response, context) => {\n        await emulate.handler(\n          {\n            params: {\n              cpuThrottlingRate: 4,\n            },\n            page: context.getSelectedMcpPage(),\n          },\n          response,\n          context,\n        );\n\n        assert.strictEqual(context.getSelectedMcpPage().cpuThrottlingRate, 4);\n      });\n    });\n\n    it('disables cpu throttling', async () => {\n      await withMcpContext(async (response, context) => {\n        await context.emulate({\n          cpuThrottlingRate: 4,\n        });\n        await emulate.handler(\n          {\n            params: {\n              cpuThrottlingRate: 1,\n            },\n            page: context.getSelectedMcpPage(),\n          },\n          response,\n          context,\n        );\n\n        assert.strictEqual(context.getSelectedMcpPage().cpuThrottlingRate, 1);\n      });\n    });\n\n    it('report correctly for the currently selected page', async () => {\n      await withMcpContext(async (response, context) => {\n        await emulate.handler(\n          {\n            params: {\n              cpuThrottlingRate: 4,\n            },\n            page: context.getSelectedMcpPage(),\n          },\n          response,\n          context,\n        );\n\n        assert.strictEqual(context.getSelectedMcpPage().cpuThrottlingRate, 4);\n\n        const page = await context.newPage();\n        context.selectPage(page);\n\n        assert.strictEqual(context.getSelectedMcpPage().cpuThrottlingRate, 1);\n      });\n    });\n  });\n\n  describe('geolocation', () => {\n    it('emulates geolocation with latitude and longitude', async () => {\n      await withMcpContext(async (response, context) => {\n        await emulate.handler(\n          {\n            params: {\n              geolocation: {\n                latitude: 48.137154,\n                longitude: 11.576124,\n              },\n            },\n            page: context.getSelectedMcpPage(),\n          },\n          response,\n          context,\n        );\n\n        const geolocation = context.getSelectedMcpPage().geolocation;\n        assert.strictEqual(geolocation?.latitude, 48.137154);\n        assert.strictEqual(geolocation?.longitude, 11.576124);\n      });\n    });\n\n    it('clears geolocation override when geolocation is set to null', async () => {\n      await withMcpContext(async (response, context) => {\n        // First set a geolocation\n        await emulate.handler(\n          {\n            params: {\n              geolocation: {\n                latitude: 48.137154,\n                longitude: 11.576124,\n              },\n            },\n            page: context.getSelectedMcpPage(),\n          },\n          response,\n          context,\n        );\n\n        assert.notStrictEqual(context.getSelectedMcpPage().geolocation, null);\n\n        // Then clear it by setting geolocation to null\n        await emulate.handler(\n          {\n            params: {},\n            page: context.getSelectedMcpPage(),\n          },\n          response,\n          context,\n        );\n\n        assert.strictEqual(context.getSelectedMcpPage().geolocation, null);\n      });\n    });\n\n    it('reports correctly for the currently selected page', async () => {\n      await withMcpContext(async (response, context) => {\n        await emulate.handler(\n          {\n            params: {\n              geolocation: {\n                latitude: 48.137154,\n                longitude: 11.576124,\n              },\n            },\n            page: context.getSelectedMcpPage(),\n          },\n          response,\n          context,\n        );\n\n        const geolocation = context.getSelectedMcpPage().geolocation;\n        assert.strictEqual(geolocation?.latitude, 48.137154);\n        assert.strictEqual(geolocation?.longitude, 11.576124);\n\n        const page = await context.newPage();\n        context.selectPage(page);\n\n        assert.strictEqual(context.getSelectedMcpPage().geolocation, null);\n      });\n    });\n  });\n  describe('viewport', () => {\n    beforeEach(() => {\n      server.addHtmlRoute('/viewport', html`Test page`);\n    });\n\n    it('emulates viewport', async () => {\n      await withMcpContext(async (response, context) => {\n        const page = context.getSelectedPptrPage();\n        await page.goto(server.baseUrl + '/viewport');\n        await emulate.handler(\n          {\n            params: {\n              viewport: {\n                width: 400,\n                height: 400,\n                deviceScaleFactor: 2,\n                isMobile: true,\n                hasTouch: true,\n                isLandscape: false,\n              },\n            },\n            page: context.getSelectedMcpPage(),\n          },\n          response,\n          context,\n        );\n\n        const viewportData = await page.evaluate(() => {\n          return {\n            width: window.innerWidth,\n            height: window.innerHeight,\n            deviceScaleFactor: window.devicePixelRatio,\n            hasTouch: navigator.maxTouchPoints > 0,\n          };\n        });\n\n        assert.deepStrictEqual(viewportData, {\n          width: 400,\n          height: 400,\n          deviceScaleFactor: 2,\n          hasTouch: true,\n        });\n      });\n    });\n\n    it('clears viewport override when viewport is set to null', async () => {\n      await withMcpContext(async (response, context) => {\n        const page = context.getSelectedPptrPage();\n        // First set a viewport\n        await emulate.handler(\n          {\n            params: {\n              viewport: {\n                width: 400,\n                height: 400,\n              },\n            },\n            page: context.getSelectedMcpPage(),\n          },\n          response,\n          context,\n        );\n\n        const viewportData = await page.evaluate(() => {\n          return {\n            width: window.innerWidth,\n            height: window.innerHeight,\n          };\n        });\n\n        assert.deepStrictEqual(viewportData, {\n          width: 400,\n          height: 400,\n        });\n\n        // Then clear it by setting viewport to null\n        await emulate.handler(\n          {\n            params: {},\n            page: context.getSelectedMcpPage(),\n          },\n          response,\n          context,\n        );\n\n        assert.strictEqual(context.getSelectedMcpPage().viewport, null);\n\n        // Somehow reset of the viewport seems to be async.\n        await context.getSelectedPptrPage().waitForFunction(() => {\n          return window.innerWidth !== 400 && window.innerHeight !== 400;\n        });\n      });\n    });\n\n    it('reports correctly for the currently selected page', async () => {\n      await withMcpContext(async (response, context) => {\n        await emulate.handler(\n          {\n            params: {\n              viewport: {\n                width: 400,\n                height: 400,\n              },\n            },\n            page: context.getSelectedMcpPage(),\n          },\n          response,\n          context,\n        );\n\n        assert.ok(context.getSelectedMcpPage().viewport);\n\n        const page = await context.newPage();\n        context.selectPage(page);\n\n        assert.strictEqual(context.getSelectedMcpPage().viewport, null);\n        assert.ok(\n          await context.getSelectedPptrPage().evaluate(() => {\n            return window.innerWidth !== 400 && window.innerHeight !== 400;\n          }),\n        );\n      });\n    });\n  });\n\n  describe('userAgent', () => {\n    it('emulates userAgent', async () => {\n      await withMcpContext(async (response, context) => {\n        await emulate.handler(\n          {\n            params: {\n              userAgent: 'MyUA',\n            },\n            page: context.getSelectedMcpPage(),\n          },\n          response,\n          context,\n        );\n\n        assert.strictEqual(context.getSelectedMcpPage().userAgent, 'MyUA');\n        const page = context.getSelectedPptrPage();\n        const ua = await page.evaluate(() => navigator.userAgent);\n        assert.strictEqual(ua, 'MyUA');\n      });\n    });\n\n    it('updates userAgent', async () => {\n      await withMcpContext(async (response, context) => {\n        await emulate.handler(\n          {\n            params: {\n              userAgent: 'UA1',\n            },\n            page: context.getSelectedMcpPage(),\n          },\n          response,\n          context,\n        );\n        assert.strictEqual(context.getSelectedMcpPage().userAgent, 'UA1');\n\n        await emulate.handler(\n          {\n            params: {\n              userAgent: 'UA2',\n            },\n            page: context.getSelectedMcpPage(),\n          },\n          response,\n          context,\n        );\n        assert.strictEqual(context.getSelectedMcpPage().userAgent, 'UA2');\n        const page = context.getSelectedPptrPage();\n        const ua = await page.evaluate(() => navigator.userAgent);\n        assert.strictEqual(ua, 'UA2');\n      });\n    });\n\n    it('clears userAgent override when userAgent is set to null', async () => {\n      await withMcpContext(async (response, context) => {\n        await emulate.handler(\n          {\n            params: {\n              userAgent: 'MyUA',\n            },\n            page: context.getSelectedMcpPage(),\n          },\n          response,\n          context,\n        );\n\n        assert.strictEqual(context.getSelectedMcpPage().userAgent, 'MyUA');\n\n        await emulate.handler(\n          {\n            params: {},\n            page: context.getSelectedMcpPage(),\n          },\n          response,\n          context,\n        );\n\n        assert.strictEqual(context.getSelectedMcpPage().userAgent, null);\n        const page = context.getSelectedPptrPage();\n        const ua = await page.evaluate(() => navigator.userAgent);\n        assert.notStrictEqual(ua, 'MyUA');\n        assert.ok(ua.length > 0);\n      });\n    });\n\n    it('reports correctly for the currently selected page', async () => {\n      await withMcpContext(async (response, context) => {\n        await emulate.handler(\n          {\n            params: {\n              userAgent: 'MyUA',\n            },\n            page: context.getSelectedMcpPage(),\n          },\n          response,\n          context,\n        );\n\n        assert.strictEqual(context.getSelectedMcpPage().userAgent, 'MyUA');\n\n        const page = await context.newPage();\n        context.selectPage(page);\n\n        assert.strictEqual(context.getSelectedMcpPage().userAgent, null);\n        assert.ok(\n          await context.getSelectedPptrPage().evaluate(() => {\n            return navigator.userAgent !== 'MyUA';\n          }),\n        );\n      });\n    });\n  });\n\n  describe('colorScheme', () => {\n    it('emulates color scheme', async () => {\n      await withMcpContext(async (response, context) => {\n        await emulate.handler(\n          {\n            params: {\n              colorScheme: 'dark',\n            },\n            page: context.getSelectedMcpPage(),\n          },\n          response,\n          context,\n        );\n\n        assert.strictEqual(context.getSelectedMcpPage().colorScheme, 'dark');\n        const page = context.getSelectedPptrPage();\n        const scheme = await page.evaluate(() =>\n          window.matchMedia('(prefers-color-scheme: dark)').matches\n            ? 'dark'\n            : 'light',\n        );\n        assert.strictEqual(scheme, 'dark');\n      });\n    });\n\n    it('updates color scheme', async () => {\n      await withMcpContext(async (response, context) => {\n        await emulate.handler(\n          {\n            params: {\n              colorScheme: 'dark',\n            },\n            page: context.getSelectedMcpPage(),\n          },\n          response,\n          context,\n        );\n        assert.strictEqual(context.getSelectedMcpPage().colorScheme, 'dark');\n\n        await emulate.handler(\n          {\n            params: {\n              colorScheme: 'light',\n            },\n            page: context.getSelectedMcpPage(),\n          },\n          response,\n          context,\n        );\n        assert.strictEqual(context.getSelectedMcpPage().colorScheme, 'light');\n        const page = context.getSelectedPptrPage();\n        const scheme = await page.evaluate(() =>\n          window.matchMedia('(prefers-color-scheme: light)').matches\n            ? 'light'\n            : 'dark',\n        );\n        assert.strictEqual(scheme, 'light');\n      });\n    });\n\n    it('resets color scheme when set to auto', async () => {\n      await withMcpContext(async (response, context) => {\n        const page = context.getSelectedPptrPage();\n\n        const initial = await page.evaluate(\n          () => window.matchMedia('(prefers-color-scheme: dark)').matches,\n        );\n\n        await emulate.handler(\n          {\n            params: {\n              colorScheme: 'dark',\n            },\n            page: context.getSelectedMcpPage(),\n          },\n          response,\n          context,\n        );\n        assert.strictEqual(context.getSelectedMcpPage().colorScheme, 'dark');\n        // Check manually that it is dark\n\n        assert.strictEqual(\n          await page.evaluate(\n            () => window.matchMedia('(prefers-color-scheme: dark)').matches,\n          ),\n          true,\n        );\n\n        await emulate.handler(\n          {\n            params: {\n              colorScheme: 'auto',\n            },\n            page: context.getSelectedMcpPage(),\n          },\n          response,\n          context,\n        );\n\n        assert.strictEqual(context.getSelectedMcpPage().colorScheme, null);\n        assert.strictEqual(\n          await page.evaluate(\n            () => window.matchMedia('(prefers-color-scheme: dark)').matches,\n          ),\n          initial,\n        );\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "tests/tools/extensions.test.ts",
    "content": "/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport assert from 'node:assert';\nimport path from 'node:path';\nimport {afterEach, describe, it} from 'node:test';\n\nimport sinon from 'sinon';\n\nimport type {ParsedArguments} from '../../src/bin/chrome-devtools-mcp-cli-options.js';\nimport {\n  installExtension,\n  uninstallExtension,\n  listExtensions,\n  reloadExtension,\n  triggerExtensionAction,\n} from '../../src/tools/extensions.js';\nimport {extractExtensionId, withMcpContext} from '../utils.js';\n\nconst EXTENSION_WITH_SW_PATH = path.join(\n  import.meta.dirname,\n  '../../../tests/tools/fixtures/extension-sw',\n);\nconst EXTENSION_PATH = path.join(\n  import.meta.dirname,\n  '../../../tests/tools/fixtures/extension',\n);\n\ndescribe('extension', () => {\n  afterEach(() => {\n    sinon.restore();\n  });\n\n  it('installs and uninstalls an extension and verifies it in chrome://extensions', async () => {\n    await withMcpContext(async (response, context) => {\n      // Install the extension\n      await installExtension.handler(\n        {params: {path: EXTENSION_PATH}},\n        response,\n        context,\n      );\n\n      const extensionId = extractExtensionId(response);\n      const page = context.getSelectedPptrPage();\n      await page.goto('chrome://extensions');\n\n      const element = await page.waitForSelector(\n        `extensions-manager >>> extensions-item[id=\"${extensionId}\"]`,\n      );\n      assert.ok(\n        element,\n        `Extension with ID \"${extensionId}\" should be visible on chrome://extensions`,\n      );\n\n      // Uninstall the extension\n      await uninstallExtension.handler(\n        {params: {id: extensionId!}},\n        response,\n        context,\n      );\n\n      const uninstallResponseLine = response.responseLines[1];\n      assert.ok(\n        uninstallResponseLine.includes('Extension uninstalled'),\n        'Response should indicate uninstallation',\n      );\n\n      await page.waitForSelector('extensions-manager');\n\n      const elementAfterUninstall = await page.$(\n        `extensions-manager >>> extensions-item[id=\"${extensionId}\"]`,\n      );\n      assert.strictEqual(\n        elementAfterUninstall,\n        null,\n        `Extension with ID \"${extensionId}\" should NOT be visible on chrome://extensions`,\n      );\n    });\n  });\n  it('lists installed extensions', async () => {\n    await withMcpContext(async (response, context) => {\n      const setListExtensionsSpy = sinon.spy(response, 'setListExtensions');\n      await listExtensions.handler({params: {}}, response, context);\n      assert.ok(\n        setListExtensionsSpy.calledOnce,\n        'setListExtensions should be called',\n      );\n    });\n  });\n  it('reloads an extension', async () => {\n    await withMcpContext(async (response, context) => {\n      await installExtension.handler(\n        {params: {path: EXTENSION_PATH}},\n        response,\n        context,\n      );\n\n      const extensionId = extractExtensionId(response);\n      const installSpy = sinon.spy(context, 'installExtension');\n      response.resetResponseLineForTesting();\n\n      await reloadExtension.handler(\n        {params: {id: extensionId!}},\n        response,\n        context,\n      );\n      assert.ok(\n        installSpy.calledOnceWithExactly(EXTENSION_PATH),\n        'installExtension should be called with the extension path',\n      );\n\n      const reloadResponseLine = response.responseLines[0];\n      assert.ok(\n        reloadResponseLine.includes('Extension reloaded'),\n        'Response should indicate reload',\n      );\n\n      const list = context.listExtensions();\n      assert.ok(list.length === 1, 'List should have only one extension');\n      const reinstalled = list.find(e => e.id === extensionId);\n      assert.ok(reinstalled, 'Extension should be present after reload');\n    });\n  });\n  it('triggers an extension action', async () => {\n    await withMcpContext(\n      async (response, context) => {\n        const extensionId = await context.installExtension(\n          EXTENSION_WITH_SW_PATH,\n        );\n\n        const targetsBefore = context.browser.targets();\n        const pageTargetBefore = targetsBefore.find(\n          t => t.type() === 'page' && t.url().includes(extensionId),\n        );\n        assert.ok(!pageTargetBefore, 'Page should not exist before action');\n\n        await triggerExtensionAction.handler(\n          {params: {id: extensionId}},\n          response,\n          context,\n        );\n\n        const pageTargetAfter = await context.browser.waitForTarget(\n          t => t.type() === 'page' && t.url().includes(extensionId),\n        );\n        assert.ok(pageTargetAfter, 'Page should exist after action');\n      },\n      {\n        executablePath: process.env.CHROME_M146_EXECUTABLE_PATH,\n      },\n      {\n        categoryExtensions: true,\n      } as ParsedArguments,\n    );\n  });\n});\n"
  },
  {
    "path": "tests/tools/fixtures/extension/manifest.json",
    "content": "{\n  \"manifest_version\": 3,\n  \"name\": \"Test Extension\",\n  \"version\": \"1.0\",\n  \"action\": {\n    \"default_popup\": \"popup.html\"\n  }\n}\n"
  },
  {
    "path": "tests/tools/fixtures/extension/popup.html",
    "content": "<!doctype html>\n<html>\n  <body>\n    <h1>Test Popup</h1>\n  </body>\n</html>\n"
  },
  {
    "path": "tests/tools/fixtures/extension-side-panel/manifest.json",
    "content": "{\n  \"name\": \"Test Extension Side Panel\",\n  \"version\": \"1.0.0\",\n  \"manifest_version\": 3,\n  \"permissions\": [\"sidePanel\"],\n  \"action\": {\n    \"default_title\": \"Click to open panel\"\n  },\n  \"background\": {\n    \"service_worker\": \"sw.js\"\n  },\n  \"side_panel\": {\n    \"default_path\": \"sidepanel.html\"\n  }\n}\n"
  },
  {
    "path": "tests/tools/fixtures/extension-side-panel/sidepanel.html",
    "content": "<!doctype html>\n<html>\n  <head>\n    <title>Side Panel</title>\n  </head>\n  <body>\n    <h1>Side Panel</h1>\n  </body>\n</html>\n"
  },
  {
    "path": "tests/tools/fixtures/extension-side-panel/sw.js",
    "content": "chrome.sidePanel\n  .setPanelBehavior({openPanelOnActionClick: true})\n  .catch(console.error);\n"
  },
  {
    "path": "tests/tools/fixtures/extension-sw/manifest.json",
    "content": "{\n  \"manifest_version\": 3,\n  \"name\": \"Test Extension with SW\",\n  \"version\": \"1.0\",\n  \"background\": {\n    \"service_worker\": \"sw.js\"\n  },\n  \"action\": {\n    \"default_popup\": \"popup.html\"\n  }\n}\n"
  },
  {
    "path": "tests/tools/fixtures/extension-sw/popup.html",
    "content": "<!doctype html>\n<html>\n  <body>\n    <h1>Extension With Service Worker</h1>\n  </body>\n</html>\n"
  },
  {
    "path": "tests/tools/fixtures/extension-sw/sw.js",
    "content": "chrome.action.onClicked.addListener(tab => {\n  console.log('Action clicked');\n});\n"
  },
  {
    "path": "tests/tools/input.test.ts",
    "content": "/**\n * @license\n * Copyright 2025 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport assert from 'node:assert';\nimport fs from 'node:fs/promises';\nimport path from 'node:path';\nimport {describe, it} from 'node:test';\n\nimport type {ParsedArguments} from '../../src/bin/chrome-devtools-mcp-cli-options.js';\nimport {McpResponse} from '../../src/McpResponse.js';\nimport {\n  click,\n  hover,\n  fill,\n  drag,\n  fillForm,\n  uploadFile,\n  pressKey,\n  clickAt,\n  typeText,\n} from '../../src/tools/input.js';\nimport {parseKey} from '../../src/utils/keyboard.js';\nimport {serverHooks} from '../server.js';\nimport {html, withMcpContext} from '../utils.js';\n\ndescribe('input', () => {\n  const server = serverHooks();\n\n  describe('click', () => {\n    it('clicks', async () => {\n      await withMcpContext(async (response, context) => {\n        const page = context.getSelectedPptrPage();\n        await page.setContent(\n          html`<button onclick=\"this.innerText = 'clicked';\">test</button>`,\n        );\n        await context.createTextSnapshot(context.getSelectedMcpPage());\n        await click.handler(\n          {\n            params: {\n              uid: '1_1',\n            },\n            page: context.getSelectedMcpPage(),\n          },\n          response,\n          context,\n        );\n        assert.strictEqual(\n          response.responseLines[0],\n          'Successfully clicked on the element',\n        );\n        assert.ok(response.includeSnapshot);\n        assert.ok(await page.$('text/clicked'));\n      });\n    });\n    it('double clicks', async () => {\n      await withMcpContext(async (response, context) => {\n        const page = context.getSelectedPptrPage();\n        await page.setContent(\n          html`<button ondblclick=\"this.innerText = 'dblclicked';\"\n            >test</button\n          >`,\n        );\n        await context.createTextSnapshot(context.getSelectedMcpPage());\n        await click.handler(\n          {\n            params: {\n              uid: '1_1',\n              dblClick: true,\n            },\n            page: context.getSelectedMcpPage(),\n          },\n          response,\n          context,\n        );\n        assert.strictEqual(\n          response.responseLines[0],\n          'Successfully double clicked on the element',\n        );\n        assert.ok(response.includeSnapshot);\n        assert.ok(await page.$('text/dblclicked'));\n      });\n    });\n    it('waits for navigation', async () => {\n      const resolveNavigation = Promise.withResolvers<void>();\n      server.addHtmlRoute(\n        '/link',\n        html`<a href=\"/navigated\">Navigate page</a>`,\n      );\n      server.addRoute('/navigated', async (_req, res) => {\n        await resolveNavigation.promise;\n        res.write(html`<main>I was navigated</main>`);\n        res.end();\n      });\n\n      await withMcpContext(async (response, context) => {\n        const page = context.getSelectedPptrPage();\n        await page.goto(server.getRoute('/link'));\n        await context.createTextSnapshot(context.getSelectedMcpPage());\n        const clickPromise = click.handler(\n          {\n            params: {\n              uid: '1_1',\n            },\n            page: context.getSelectedMcpPage(),\n          },\n          response,\n          context,\n        );\n        const [t1, t2] = await Promise.all([\n          clickPromise.then(() => Date.now()),\n          new Promise<number>(res => {\n            setTimeout(() => {\n              resolveNavigation.resolve();\n              res(Date.now());\n            }, 300);\n          }),\n        ]);\n\n        assert(t1 > t2, 'Waited for navigation');\n      });\n    });\n\n    it('waits for stable DOM', async () => {\n      server.addHtmlRoute(\n        '/unstable',\n        html`\n          <button>Click to change to see time</button>\n          <script>\n            const button = document.querySelector('button');\n            button.addEventListener('click', () => {\n              setTimeout(() => {\n                button.textContent = Date.now();\n              }, 50);\n            });\n          </script>\n        `,\n      );\n      await withMcpContext(async (response, context) => {\n        const page = context.getSelectedPptrPage();\n        await page.goto(server.getRoute('/unstable'));\n        await context.createTextSnapshot(context.getSelectedMcpPage());\n        const handlerResolveTime = await click\n          .handler(\n            {\n              params: {\n                uid: '1_1',\n              },\n              page: context.getSelectedMcpPage(),\n            },\n            response,\n            context,\n          )\n          .then(() => Date.now());\n        const buttonChangeTime = await page.evaluate(() => {\n          const button = document.querySelector('button');\n          return Number(button?.textContent);\n        });\n\n        assert(handlerResolveTime > buttonChangeTime, 'Waited for navigation');\n      });\n    });\n\n    it('does not include snapshot by default', async () => {\n      await withMcpContext(async (response, context) => {\n        const page = context.getSelectedPptrPage();\n        await page.setContent(\n          html`<button onclick=\"this.innerText = 'clicked';\">test</button>`,\n        );\n        await context.createTextSnapshot(context.getSelectedMcpPage());\n        await click.handler(\n          {\n            params: {\n              uid: '1_1',\n            },\n            page: context.getSelectedMcpPage(),\n          },\n          response,\n          context,\n        );\n        assert.strictEqual(\n          response.responseLines[0],\n          'Successfully clicked on the element',\n        );\n        assert.strictEqual(response.snapshotParams, undefined);\n      });\n    });\n\n    it('includes snapshot if includeSnapshot is true', async () => {\n      await withMcpContext(async (response, context) => {\n        const page = context.getSelectedPptrPage();\n        await page.setContent(\n          html`<button onclick=\"this.innerText = 'clicked';\">test</button>`,\n        );\n        await context.createTextSnapshot(context.getSelectedMcpPage());\n        await click.handler(\n          {\n            params: {\n              uid: '1_1',\n              includeSnapshot: true,\n            },\n            page: context.getSelectedMcpPage(),\n          },\n          response,\n          context,\n        );\n        assert.strictEqual(\n          response.responseLines[0],\n          'Successfully clicked on the element',\n        );\n        assert.notStrictEqual(response.snapshotParams, undefined);\n      });\n    });\n  });\n\n  describe('hover', () => {\n    it('hovers', async () => {\n      await withMcpContext(async (response, context) => {\n        const page = context.getSelectedPptrPage();\n        await page.setContent(\n          html`<button onmouseover=\"this.innerText = 'hovered';\">test</button>`,\n        );\n        await context.createTextSnapshot(context.getSelectedMcpPage());\n        await hover.handler(\n          {\n            params: {\n              uid: '1_1',\n            },\n            page: context.getSelectedMcpPage(),\n          },\n          response,\n          context,\n        );\n        assert.strictEqual(\n          response.responseLines[0],\n          'Successfully hovered over the element',\n        );\n        assert.ok(response.includeSnapshot);\n        assert.ok(await page.$('text/hovered'));\n      });\n    });\n  });\n\n  describe('click_at', () => {\n    it('clicks at coordinates', async () => {\n      await withMcpContext(async (response, context) => {\n        const page = context.getSelectedPptrPage();\n        await page.setContent(\n          html`<div\n            style=\"width: 100px; height: 100px; background: red;\"\n            onclick=\"this.innerText = 'clicked'\"\n          ></div>`,\n        );\n        await context.createTextSnapshot(context.getSelectedMcpPage());\n        await clickAt.handler(\n          {\n            params: {\n              x: 50,\n              y: 50,\n            },\n            page: context.getSelectedMcpPage(),\n          },\n          response,\n          context,\n        );\n        assert.strictEqual(\n          response.responseLines[0],\n          'Successfully clicked at the coordinates',\n        );\n        assert.ok(response.includeSnapshot);\n        assert.ok(await page.$('text/clicked'));\n      });\n    });\n\n    it('double clicks at coordinates', async () => {\n      await withMcpContext(async (response, context) => {\n        const page = context.getSelectedPptrPage();\n        await page.setContent(\n          html`<div\n            style=\"width: 100px; height: 100px; background: red;\"\n            ondblclick=\"this.innerText = 'dblclicked'\"\n          ></div>`,\n        );\n        await context.createTextSnapshot(context.getSelectedMcpPage());\n        await clickAt.handler(\n          {\n            params: {\n              x: 50,\n              y: 50,\n              dblClick: true,\n            },\n            page: context.getSelectedMcpPage(),\n          },\n          response,\n          context,\n        );\n        assert.strictEqual(\n          response.responseLines[0],\n          'Successfully double clicked at the coordinates',\n        );\n        assert.ok(response.includeSnapshot);\n        assert.ok(await page.$('text/dblclicked'));\n      });\n    });\n  });\n\n  describe('fill', () => {\n    it('fills out an input', async () => {\n      await withMcpContext(async (response, context) => {\n        const page = context.getSelectedPptrPage();\n        await page.setContent(html`<input />`);\n        await context.createTextSnapshot(context.getSelectedMcpPage());\n        await fill.handler(\n          {\n            params: {\n              uid: '1_1',\n              value: 'test',\n            },\n            page: context.getSelectedMcpPage(),\n          },\n          response,\n          context,\n        );\n        assert.strictEqual(\n          response.responseLines[0],\n          'Successfully filled out the element',\n        );\n        assert.ok(response.includeSnapshot);\n        assert.ok(await page.$('text/test'));\n      });\n    });\n\n    it('fills out a select by text', async () => {\n      await withMcpContext(async (response, context) => {\n        const page = context.getSelectedPptrPage();\n        await page.setContent(\n          html`<select\n            ><option value=\"v1\">one</option\n            ><option value=\"v2\">two</option></select\n          >`,\n        );\n        await context.createTextSnapshot(context.getSelectedMcpPage());\n        await fill.handler(\n          {\n            params: {\n              uid: '1_1',\n              value: 'two',\n            },\n            page: context.getSelectedMcpPage(),\n          },\n          response,\n          context,\n        );\n        assert.strictEqual(\n          response.responseLines[0],\n          'Successfully filled out the element',\n        );\n        assert.ok(response.includeSnapshot);\n        const selectedValue = await page.evaluate(\n          () => document.querySelector('select')!.value,\n        );\n        assert.strictEqual(selectedValue, 'v2');\n      });\n    });\n\n    it('fills out a textarea marked as combobox', async () => {\n      await withMcpContext(async (response, context) => {\n        const page = context.getSelectedPptrPage();\n        await page.setContent(html`<textarea role=\"combobox\"></textarea>`);\n        await context.createTextSnapshot(context.getSelectedMcpPage());\n        await fill.handler(\n          {\n            params: {\n              uid: '1_1',\n              value: '1',\n            },\n            page: context.getSelectedMcpPage(),\n          },\n          response,\n          context,\n        );\n        assert.strictEqual(\n          response.responseLines[0],\n          'Successfully filled out the element',\n        );\n        assert.ok(response.includeSnapshot);\n        assert.ok(\n          await page.evaluate(() => {\n            return document.body.querySelector('textarea')?.value === '1';\n          }),\n        );\n      });\n    });\n\n    it('fills out a textarea with long text', async () => {\n      await withMcpContext(async (response, context) => {\n        const page = context.getSelectedPptrPage();\n        await page.setContent(html`<textarea></textarea>`);\n        await context.createTextSnapshot(context.getSelectedMcpPage());\n        page.setDefaultTimeout(1000);\n        await fill.handler(\n          {\n            params: {\n              uid: '1_1',\n              value: '1'.repeat(3000),\n            },\n            page: context.getSelectedMcpPage(),\n          },\n          response,\n          context,\n        );\n        assert.strictEqual(\n          response.responseLines[0],\n          'Successfully filled out the element',\n        );\n        assert.ok(response.includeSnapshot);\n        assert.ok(\n          await page.evaluate(() => {\n            return (\n              document.body.querySelector('textarea')?.value.length === 3_000\n            );\n          }),\n        );\n      });\n    });\n\n    it('types text', async () => {\n      await withMcpContext(async (response, context) => {\n        const page = context.getSelectedPptrPage();\n        await page.setContent(html`<textarea></textarea>`);\n        await page.click('textarea');\n        await context.createTextSnapshot(context.getSelectedMcpPage());\n        await typeText.handler(\n          {\n            params: {\n              text: 'test',\n            },\n            page: context.getSelectedMcpPage(),\n          },\n          response,\n          context,\n        );\n        assert.strictEqual(response.responseLines[0], 'Typed text \"test\"');\n        assert.strictEqual(\n          await page.evaluate(() => {\n            return document.body.querySelector('textarea')?.value;\n          }),\n          'test',\n        );\n      });\n    });\n\n    it('types text with submit key', async () => {\n      await withMcpContext(async (response, context) => {\n        const page = context.getSelectedPptrPage();\n        await page.setContent(html`<textarea></textarea>`);\n        await page.click('textarea');\n        await context.createTextSnapshot(context.getSelectedMcpPage());\n        await typeText.handler(\n          {\n            params: {\n              text: 'test',\n              submitKey: 'Tab',\n            },\n            page: context.getSelectedMcpPage(),\n          },\n          response,\n          context,\n        );\n        assert.strictEqual(\n          response.responseLines[0],\n          'Typed text \"test + Tab\"',\n        );\n        assert.strictEqual(\n          await page.evaluate(() => {\n            return document.body.querySelector('textarea')?.value;\n          }),\n          'test',\n        );\n        assert.ok(\n          await page.evaluate(() => {\n            return (\n              document.body.querySelector('textarea') !== document.activeElement\n            );\n          }),\n        );\n      });\n    });\n\n    it('errors on invalid submit key', async () => {\n      await withMcpContext(async (response, context) => {\n        const page = context.getSelectedPptrPage();\n        await page.setContent(html`<textarea></textarea>`);\n        await page.click('textarea');\n        await context.createTextSnapshot(context.getSelectedMcpPage());\n        try {\n          await typeText.handler(\n            {\n              params: {\n                text: 'test',\n                submitKey: 'XXX',\n              },\n              page: context.getSelectedMcpPage(),\n            },\n            response,\n            context,\n          );\n        } catch (err) {\n          assert.strictEqual(err.message, 'Unknown key: \"XXX\"');\n        }\n      });\n    });\n\n    it('reproduction: fill isolation', async () => {\n      await withMcpContext(async (_response, context) => {\n        const page = context.getSelectedPptrPage();\n        await page.setContent(\n          html`<form>\n            <input\n              id=\"email\"\n              value=\"user@test.com\"\n            />\n            <input\n              id=\"password\"\n              type=\"password\"\n            />\n          </form>`,\n        );\n        await context.createTextSnapshot(context.getSelectedMcpPage());\n\n        // Fill email\n        const response1 = new McpResponse({} as ParsedArguments);\n        await fill.handler(\n          {\n            params: {\n              uid: '1_1', // email input\n              value: 'new@test.com',\n            },\n            page: context.getSelectedMcpPage(),\n          },\n          response1,\n          context,\n        );\n        assert.strictEqual(\n          response1.responseLines[0],\n          'Successfully filled out the element',\n        );\n\n        // Fill password\n        const response2 = new McpResponse({} as ParsedArguments);\n        await fill.handler(\n          {\n            params: {\n              uid: '1_2', // password input\n              value: 'secret',\n            },\n            page: context.getSelectedMcpPage(),\n          },\n          response2,\n          context,\n        );\n        assert.strictEqual(\n          response2.responseLines[0],\n          'Successfully filled out the element',\n        );\n\n        // Verify values\n        const values = await page.evaluate(() => {\n          return {\n            email: (document.getElementById('email') as HTMLInputElement).value,\n            password: (document.getElementById('password') as HTMLInputElement)\n              .value,\n          };\n        });\n\n        assert.strictEqual(\n          values.email,\n          'new@test.com',\n          'Email should be updated correctly',\n        );\n        assert.strictEqual(\n          values.password,\n          'secret',\n          'Password should be updated correctly',\n        );\n      });\n    });\n  });\n\n  describe('drags', () => {\n    it('drags one element onto another', async () => {\n      await withMcpContext(async (response, context) => {\n        const page = context.getSelectedPptrPage();\n        await page.setContent(\n          html`<div\n              role=\"button\"\n              id=\"drag\"\n              draggable=\"true\"\n              >drag me</div\n            >\n            <div\n              id=\"drop\"\n              aria-label=\"drop\"\n              style=\"width: 100px; height: 100px; border: 1px solid black;\"\n              ondrop=\"this.innerText = 'dropped';\"\n            >\n            </div>\n            <script>\n              drag.addEventListener('dragstart', event => {\n                event.dataTransfer.setData('text/plain', event.target.id);\n              });\n              drop.addEventListener('dragover', event => {\n                event.preventDefault();\n                event.dataTransfer.dropEffect = 'move';\n              });\n              drop.addEventListener('drop', event => {\n                event.preventDefault();\n                const data = event.dataTransfer.getData('text/plain');\n                event.target.appendChild(document.getElementById(data));\n              });\n            </script>`,\n        );\n        await context.createTextSnapshot(context.getSelectedMcpPage());\n        await drag.handler(\n          {\n            params: {\n              from_uid: '1_1',\n              to_uid: '1_2',\n            },\n            page: context.getSelectedMcpPage(),\n          },\n          response,\n          context,\n        );\n        assert.ok(response.includeSnapshot);\n        assert.strictEqual(\n          response.responseLines[0],\n          'Successfully dragged an element',\n        );\n        assert.ok(await page.$('text/dropped'));\n      });\n    });\n  });\n\n  describe('fill form', () => {\n    it('successfully fills out the form', async () => {\n      await withMcpContext(async (response, context) => {\n        const page = context.getSelectedPptrPage();\n        await page.setContent(\n          html`<form>\n            <label\n              >username<input\n                name=\"username\"\n                type=\"text\"\n            /></label>\n            <label\n              >email<input\n                name=\"email\"\n                type=\"text\"\n            /></label>\n            <input\n              type=\"submit\"\n              value=\"Submit\"\n            />\n          </form>`,\n        );\n        await context.createTextSnapshot(context.getSelectedMcpPage());\n        await fillForm.handler(\n          {\n            params: {\n              elements: [\n                {\n                  uid: '1_2',\n                  value: 'test',\n                },\n                {\n                  uid: '1_4',\n                  value: 'test2',\n                },\n              ],\n            },\n            page: context.getSelectedMcpPage(),\n          },\n          response,\n          context,\n        );\n        assert.ok(response.includeSnapshot);\n        assert.strictEqual(\n          response.responseLines[0],\n          'Successfully filled out the form',\n        );\n        assert.deepStrictEqual(\n          await page.evaluate(() => {\n            return [\n              // @ts-expect-error missing types\n              document.querySelector('input[name=username]').value,\n              // @ts-expect-error missing types\n              document.querySelector('input[name=email]').value,\n            ];\n          }),\n          ['test', 'test2'],\n        );\n      });\n    });\n  });\n\n  describe('uploadFile', () => {\n    it('uploads a file to a file input', async () => {\n      const testFilePath = path.join(process.cwd(), 'test.txt');\n      await fs.writeFile(testFilePath, 'test file content');\n\n      await withMcpContext(async (response, context) => {\n        const page = context.getSelectedPptrPage();\n        await page.setContent(\n          html`<form>\n            <input\n              type=\"file\"\n              id=\"file-input\"\n            />\n          </form>`,\n        );\n        await context.createTextSnapshot(context.getSelectedMcpPage());\n        await uploadFile.handler(\n          {\n            params: {\n              uid: '1_1',\n              filePath: testFilePath,\n            },\n            page: context.getSelectedMcpPage(),\n          },\n          response,\n          context,\n        );\n        assert.ok(response.includeSnapshot);\n        assert.strictEqual(\n          response.responseLines[0],\n          `File uploaded from ${testFilePath}.`,\n        );\n      });\n\n      await fs.unlink(testFilePath);\n    });\n\n    it('uploads a file when clicking an element opens a file uploader', async () => {\n      const testFilePath = path.join(process.cwd(), 'test.txt');\n      await fs.writeFile(testFilePath, 'test file content');\n\n      await withMcpContext(async (response, context) => {\n        const page = context.getSelectedPptrPage();\n        await page.setContent(\n          html`<button id=\"file-chooser-button\">Upload file</button>\n            <input\n              type=\"file\"\n              id=\"file-input\"\n              style=\"display: none;\"\n            />\n            <script>\n              document\n                .getElementById('file-chooser-button')\n                .addEventListener('click', () => {\n                  document.getElementById('file-input').click();\n                });\n            </script>`,\n        );\n        await context.createTextSnapshot(context.getSelectedMcpPage());\n        await uploadFile.handler(\n          {\n            params: {\n              uid: '1_1',\n              filePath: testFilePath,\n            },\n            page: context.getSelectedMcpPage(),\n          },\n          response,\n          context,\n        );\n        assert.ok(response.includeSnapshot);\n        assert.strictEqual(\n          response.responseLines[0],\n          `File uploaded from ${testFilePath}.`,\n        );\n        const uploadedFileName = await page.$eval('#file-input', el => {\n          const input = el as HTMLInputElement;\n          return input.files?.[0]?.name;\n        });\n        assert.strictEqual(uploadedFileName, 'test.txt');\n\n        await fs.unlink(testFilePath);\n      });\n    });\n\n    it('throws an error if the element is not a file input and does not open a file chooser', async () => {\n      const testFilePath = path.join(process.cwd(), 'test.txt');\n      await fs.writeFile(testFilePath, 'test file content');\n\n      await withMcpContext(async (response, context) => {\n        const page = context.getSelectedPptrPage();\n        await page.setContent(html`<div>Not a file input</div>`);\n        await context.createTextSnapshot(context.getSelectedMcpPage());\n\n        await assert.rejects(\n          uploadFile.handler(\n            {\n              params: {\n                uid: '1_1',\n                filePath: testFilePath,\n              },\n              page: context.getSelectedMcpPage(),\n            },\n            response,\n            context,\n          ),\n          {\n            message:\n              'Failed to upload file. The element could not accept the file directly, and clicking it did not trigger a file chooser.',\n          },\n        );\n\n        assert.strictEqual(response.responseLines.length, 0);\n        assert.strictEqual(response.snapshotParams, undefined);\n\n        await fs.unlink(testFilePath);\n      });\n    });\n  });\n\n  describe('press_key', () => {\n    it('parses keys', () => {\n      assert.deepStrictEqual(parseKey('Shift+A'), ['A', 'Shift']);\n      assert.deepStrictEqual(parseKey('Shift++'), ['+', 'Shift']);\n      assert.deepStrictEqual(parseKey('Control+Shift++'), [\n        '+',\n        'Control',\n        'Shift',\n      ]);\n      assert.deepStrictEqual(parseKey('Shift'), ['Shift']);\n      assert.deepStrictEqual(parseKey('KeyA'), ['KeyA']);\n    });\n    it('throws on empty key', () => {\n      assert.throws(() => {\n        parseKey('');\n      });\n    });\n    it('throws on invalid key', () => {\n      assert.throws(() => {\n        parseKey('aaaaa');\n      });\n    });\n    it('throws on multiple keys', () => {\n      assert.throws(() => {\n        parseKey('Shift+Shift');\n      });\n    });\n\n    it('processes press_key', async () => {\n      await withMcpContext(async (response, context) => {\n        const page = context.getSelectedPptrPage();\n        await page.setContent(\n          html`<script>\n            logs = [];\n            document.addEventListener('keydown', e => logs.push('d' + e.key));\n            document.addEventListener('keyup', e => logs.push('u' + e.key));\n          </script>`,\n        );\n        await context.createTextSnapshot(context.getSelectedMcpPage());\n\n        await pressKey.handler(\n          {\n            params: {\n              key: 'Control+Shift+C',\n            },\n            page: context.getSelectedMcpPage(),\n          },\n          response,\n          context,\n        );\n\n        assert.deepStrictEqual(await page.evaluate('logs'), [\n          'dControl',\n          'dShift',\n          'dC',\n          'uC',\n          'uShift',\n          'uControl',\n        ]);\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "tests/tools/lighthouse.test.js.snapshot",
    "content": "exports[`lighthouse > lighthouse_audit > runs Lighthouse accessibility audit 1`] = `\n{\n  \"Accessibility\": {\n    \"score\": 0.94,\n    \"failedAudits\": [\n      {\n        \"id\": \"landmark-one-main\",\n        \"title\": \"Document does not have a main landmark.\",\n        \"description\": \"One main landmark helps screen reader users navigate a web page. [Learn more about landmarks](https://dequeuniversity.com/rules/axe/4.11/landmark-one-main).\",\n        \"score\": 0,\n        \"scoreDisplayMode\": \"binary\",\n        \"details\": {\n          \"type\": \"table\",\n          \"headings\": [\n            {\n              \"key\": \"node\",\n              \"valueType\": \"node\",\n              \"subItemsHeading\": {\n                \"key\": \"relatedNode\",\n                \"valueType\": \"node\"\n              },\n              \"label\": \"Failing Elements\"\n            }\n          ],\n          \"items\": [\n            {\n              \"node\": {\n                \"type\": \"node\",\n                \"lhId\": \"1-0-HTML\",\n                \"path\": \"1,HTML\",\n                \"selector\": \"html\",\n                \"boundingRect\": {\n                  \"top\": 0,\n                  \"bottom\": 34,\n                  \"left\": 0,\n                  \"right\": 1200,\n                  \"width\": 1200,\n                  \"height\": 34\n                },\n                \"snippet\": \"<html lang=\\\\\"en\\\\\">\",\n                \"nodeLabel\": \"html\",\n                \"explanation\": \"Fix all of the following:\\\\n  Document does not have a main landmark\"\n              }\n            }\n          ],\n          \"debugData\": {\n            \"type\": \"debugdata\",\n            \"impact\": \"moderate\",\n            \"tags\": [\n              \"cat.semantics\",\n              \"best-practice\"\n            ]\n          }\n        }\n      }\n    ],\n    \"passedAudits\": [\n      {\n        \"id\": \"aria-hidden-body\",\n        \"title\": \"\\`[aria-hidden=\\\\\"true\\\\\"]\\` is not present on the document \\`<body>\\`\",\n        \"description\": \"Assistive technologies, like screen readers, work inconsistently when \\`aria-hidden=\\\\\"true\\\\\"\\` is set on the document \\`<body>\\`. [Learn how \\`aria-hidden\\` affects the document body](https://dequeuniversity.com/rules/axe/4.11/aria-hidden-body).\",\n        \"score\": 1,\n        \"scoreDisplayMode\": \"binary\",\n        \"details\": {\n          \"type\": \"table\",\n          \"headings\": [\n            {\n              \"key\": \"node\",\n              \"valueType\": \"node\",\n              \"subItemsHeading\": {\n                \"key\": \"relatedNode\",\n                \"valueType\": \"node\"\n              },\n              \"label\": \"Failing Elements\"\n            }\n          ],\n          \"items\": []\n        }\n      },\n      {\n        \"id\": \"color-contrast\",\n        \"title\": \"Background and foreground colors have a sufficient contrast ratio\",\n        \"description\": \"Low-contrast text is difficult or impossible for many users to read. [Learn how to provide sufficient color contrast](https://dequeuniversity.com/rules/axe/4.11/color-contrast).\",\n        \"score\": 1,\n        \"scoreDisplayMode\": \"binary\",\n        \"details\": {\n          \"type\": \"table\",\n          \"headings\": [\n            {\n              \"key\": \"node\",\n              \"valueType\": \"node\",\n              \"subItemsHeading\": {\n                \"key\": \"relatedNode\",\n                \"valueType\": \"node\"\n              },\n              \"label\": \"Failing Elements\"\n            }\n          ],\n          \"items\": []\n        }\n      },\n      {\n        \"id\": \"document-title\",\n        \"title\": \"Document has a \\`<title>\\` element\",\n        \"description\": \"The title gives screen reader users an overview of the page, and search engine users rely on it heavily to determine if a page is relevant to their search. [Learn more about document titles](https://dequeuniversity.com/rules/axe/4.11/document-title).\",\n        \"score\": 1,\n        \"scoreDisplayMode\": \"binary\",\n        \"details\": {\n          \"type\": \"table\",\n          \"headings\": [\n            {\n              \"key\": \"node\",\n              \"valueType\": \"node\",\n              \"subItemsHeading\": {\n                \"key\": \"relatedNode\",\n                \"valueType\": \"node\"\n              },\n              \"label\": \"Failing Elements\"\n            }\n          ],\n          \"items\": []\n        }\n      },\n      {\n        \"id\": \"html-has-lang\",\n        \"title\": \"\\`<html>\\` element has a \\`[lang]\\` attribute\",\n        \"description\": \"If a page doesn't specify a \\`lang\\` attribute, a screen reader assumes that the page is in the default language that the user chose when setting up the screen reader. If the page isn't actually in the default language, then the screen reader might not announce the page's text correctly. [Learn more about the \\`lang\\` attribute](https://dequeuniversity.com/rules/axe/4.11/html-has-lang).\",\n        \"score\": 1,\n        \"scoreDisplayMode\": \"binary\",\n        \"details\": {\n          \"type\": \"table\",\n          \"headings\": [\n            {\n              \"key\": \"node\",\n              \"valueType\": \"node\",\n              \"subItemsHeading\": {\n                \"key\": \"relatedNode\",\n                \"valueType\": \"node\"\n              },\n              \"label\": \"Failing Elements\"\n            }\n          ],\n          \"items\": []\n        }\n      },\n      {\n        \"id\": \"html-lang-valid\",\n        \"title\": \"\\`<html>\\` element has a valid value for its \\`[lang]\\` attribute\",\n        \"description\": \"Specifying a valid [BCP 47 language](https://www.w3.org/International/questions/qa-choosing-language-tags#question) helps screen readers announce text properly. [Learn how to use the \\`lang\\` attribute](https://dequeuniversity.com/rules/axe/4.11/html-lang-valid).\",\n        \"score\": 1,\n        \"scoreDisplayMode\": \"binary\",\n        \"details\": {\n          \"type\": \"table\",\n          \"headings\": [\n            {\n              \"key\": \"node\",\n              \"valueType\": \"node\",\n              \"subItemsHeading\": {\n                \"key\": \"relatedNode\",\n                \"valueType\": \"node\"\n              },\n              \"label\": \"Failing Elements\"\n            }\n          ],\n          \"items\": []\n        }\n      },\n      {\n        \"id\": \"meta-viewport\",\n        \"title\": \"\\`[user-scalable=\\\\\"no\\\\\"]\\` is not used in the \\`<meta name=\\\\\"viewport\\\\\">\\` element and the \\`[maximum-scale]\\` attribute is not less than 5.\",\n        \"description\": \"Disabling zooming is problematic for users with low vision who rely on screen magnification to properly see the contents of a web page. [Learn more about the viewport meta tag](https://dequeuniversity.com/rules/axe/4.11/meta-viewport).\",\n        \"score\": 1,\n        \"scoreDisplayMode\": \"binary\",\n        \"details\": {\n          \"type\": \"table\",\n          \"headings\": [\n            {\n              \"key\": \"node\",\n              \"valueType\": \"node\",\n              \"subItemsHeading\": {\n                \"key\": \"relatedNode\",\n                \"valueType\": \"node\"\n              },\n              \"label\": \"Failing Elements\"\n            }\n          ],\n          \"items\": []\n        }\n      }\n    ]\n  }\n}\n`;\n"
  },
  {
    "path": "tests/tools/lighthouse.test.ts",
    "content": "/**\n * @license\n * Copyright 2025 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport assert from 'node:assert/strict';\nimport fs from 'node:fs/promises';\nimport os from 'node:os';\nimport path from 'node:path';\nimport {describe, it} from 'node:test';\n\nimport {lighthouseAudit} from '../../src/tools/lighthouse.js';\nimport {serverHooks} from '../server.js';\nimport {html, withMcpContext} from '../utils.js';\n\ndescribe('lighthouse', () => {\n  const server = serverHooks();\n  describe('lighthouse_audit', () => {\n    it('runs Lighthouse audit by default (navigation, desktop)', async () => {\n      server.addHtmlRoute('/test', html`<div>Test</div>`);\n\n      await withMcpContext(async (response, context) => {\n        const page = context.getSelectedPptrPage();\n        await page.goto(server.getRoute('/test'));\n\n        await lighthouseAudit.handler(\n          {\n            params: {\n              mode: 'navigation',\n              device: 'desktop',\n            },\n            page: context.getSelectedMcpPage(),\n          },\n          response,\n          context,\n        );\n\n        const data = response.attachedLighthouseResult;\n        assert.ok(data);\n\n        assert.ok(data.summary);\n        assert.equal(data.summary.mode, 'navigation');\n        assert.equal(data.summary.device, 'desktop');\n        assert.ok(data.reports.length === 2); // json, html\n\n        // Verify files exist\n        for (const reportPath of data.reports) {\n          const stats = await fs.stat(reportPath);\n          assert.ok(stats.isFile());\n        }\n      });\n    });\n\n    it('restores emulation', async () => {\n      server.addHtmlRoute('/test-mobile', html`<div>Test Mobile</div>`);\n\n      await withMcpContext(async (response, context) => {\n        const page = context.getSelectedPptrPage();\n        await page.goto(server.getRoute('/test-mobile'));\n        await context.emulate({\n          viewport: {\n            width: 400,\n            height: 400,\n            deviceScaleFactor: 1,\n            hasTouch: true,\n          },\n        });\n\n        {\n          const viewportData = await page.evaluate(() => {\n            return {\n              width: window.innerWidth,\n              height: window.innerHeight,\n              deviceScaleFactor: window.devicePixelRatio,\n              hasTouch: navigator.maxTouchPoints > 0,\n            };\n          });\n\n          assert.deepStrictEqual(viewportData, {\n            width: 400,\n            height: 400,\n            deviceScaleFactor: 1,\n            hasTouch: true,\n          });\n        }\n\n        await lighthouseAudit.handler(\n          {\n            params: {\n              mode: 'snapshot',\n              device: 'mobile',\n            },\n            page: context.getSelectedMcpPage(),\n          },\n          response,\n          context,\n        );\n\n        {\n          const viewportData = await page.evaluate(() => {\n            return {\n              width: window.innerWidth,\n              height: window.innerHeight,\n              deviceScaleFactor: window.devicePixelRatio,\n              hasTouch: navigator.maxTouchPoints > 0,\n            };\n          });\n\n          assert.deepStrictEqual(viewportData, {\n            width: 400,\n            height: 400,\n            deviceScaleFactor: 1,\n            hasTouch: true,\n          });\n        }\n      });\n    });\n\n    it('runs Lighthouse in snapshot mode with mobile device', async () => {\n      server.addHtmlRoute('/test-mobile', html`<div>Test Mobile</div>`);\n\n      await withMcpContext(async (response, context) => {\n        const page = context.getSelectedPptrPage();\n        await page.goto(server.getRoute('/test-mobile'));\n\n        await lighthouseAudit.handler(\n          {\n            params: {\n              mode: 'snapshot',\n              device: 'mobile',\n            },\n            page: context.getSelectedMcpPage(),\n          },\n          response,\n          context,\n        );\n\n        const data = response.attachedLighthouseResult;\n        assert.ok(data);\n\n        assert.equal(data.summary.mode, 'snapshot');\n        assert.equal(data.summary.device, 'mobile');\n        assert.ok(data.reports.length === 2);\n      });\n    });\n\n    it('runs Lighthouse with custom output dir', async () => {\n      server.addHtmlRoute('/test-mobile', html`<div>Test Mobile</div>`);\n\n      const tmpDir = os.tmpdir();\n      const folderPath = path.join(\n        tmpDir,\n        `temp-folder-${crypto.randomUUID()}`,\n      );\n\n      try {\n        await withMcpContext(async (response, context) => {\n          const page = context.getSelectedPptrPage();\n          await page.goto(server.getRoute('/test-mobile'));\n\n          await lighthouseAudit.handler(\n            {\n              params: {\n                mode: 'snapshot',\n                device: 'mobile',\n                outputDirPath: folderPath,\n              },\n              page: context.getSelectedMcpPage(),\n            },\n            response,\n            context,\n          );\n\n          const data = response.attachedLighthouseResult;\n          assert.ok(data);\n          assert.equal(data.summary.mode, 'snapshot');\n          assert.equal(data.summary.device, 'mobile');\n          assert.ok(data.reports.length === 2);\n          for (const report of data.reports) {\n            assert.ok(report.startsWith(folderPath));\n          }\n        });\n      } finally {\n        await fs.rm(folderPath, {recursive: true, force: true});\n      }\n    });\n  });\n});\n"
  },
  {
    "path": "tests/tools/memory.test.ts",
    "content": "/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport assert from 'node:assert';\nimport {existsSync} from 'node:fs';\nimport {rm} from 'node:fs/promises';\nimport {tmpdir} from 'node:os';\nimport {join} from 'node:path';\nimport {describe, it} from 'node:test';\n\nimport {takeMemorySnapshot} from '../../src/tools/memory.js';\nimport {withMcpContext} from '../utils.js';\n\ndescribe('memory', () => {\n  describe('take_memory_snapshot', () => {\n    it('with default options', async () => {\n      await withMcpContext(async (response, context) => {\n        const filePath = join(tmpdir(), 'test-screenshot.heapsnapshot');\n        try {\n          await takeMemorySnapshot.handler(\n            {params: {filePath}, page: context.getSelectedMcpPage()},\n            response,\n            context,\n          );\n          assert.equal(\n            response.responseLines.at(0),\n            `Heap snapshot saved to ${filePath}`,\n          );\n          assert.ok(existsSync(filePath));\n        } finally {\n          await rm(filePath, {force: true});\n        }\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "tests/tools/network.test.js.snapshot",
    "content": "exports[`network > network_get_request > should get request from previous navigations 1`] = `\n## Request http://localhost:<port>/one\nStatus: 200\n### Request Headers\n- accept-language:<lang>\n- upgrade-insecure-requests:1\n- user-agent:<user-agent>\n- sec-ch-ua:\"Not-A.Brand\";v=\"24\", \"Chromium\";v=\"146\"\n- sec-ch-ua-mobile:?0\n- sec-ch-ua-platform:\"<os>\"\n- accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7\n- accept-encoding:gzip, deflate, br, zstd\n- connection:keep-alive\n- host:localhost:<port>\n- sec-fetch-dest:document\n- sec-fetch-mode:navigate\n- sec-fetch-site:none\n- sec-fetch-user:?1\n### Response Headers\n- connection:keep-alive\n- content-length:239\n- content-type:text/html; charset=utf-8\n- date:<long date>\n- keep-alive:timeout=5\n### Response Body\n<not available anymore>\n`;\n\nexports[`network > network_list_requests > list requests form current navigations only 1`] = `\n## Network requests\nShowing 1-1 of 1 (Page 1 of 1).\nreqid=3 GET http://localhost:<port>/three [200]\n`;\n\nexports[`network > network_list_requests > list requests from previous navigations 1`] = `\n## Network requests\nShowing 1-3 of 3 (Page 1 of 1).\nreqid=1 GET http://localhost:<port>/one [200]\nreqid=2 GET http://localhost:<port>/two [200]\nreqid=3 GET http://localhost:<port>/three [200]\n`;\n\nexports[`network > network_list_requests > list requests from previous navigations from redirects 1`] = `\n## Network requests\nShowing 1-3 of 3 (Page 1 of 1).\nreqid=1 GET http://localhost:<port>/redirect [302]\nreqid=2 GET http://localhost:<port>/redirected [200]\nreqid=3 GET http://localhost:<port>/redirected-page [200]\n`;\n"
  },
  {
    "path": "tests/tools/network.test.ts",
    "content": "/**\n * @license\n * Copyright 2025 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport assert from 'node:assert';\nimport {describe, it} from 'node:test';\n\nimport {\n  getNetworkRequest,\n  listNetworkRequests,\n} from '../../src/tools/network.js';\nimport {serverHooks} from '../server.js';\nimport {\n  getTextContent,\n  html,\n  stabilizeResponseOutput,\n  withMcpContext,\n} from '../utils.js';\n\ndescribe('network', () => {\n  const server = serverHooks();\n  describe('network_list_requests', () => {\n    it('list requests', async () => {\n      await withMcpContext(async (response, context) => {\n        await listNetworkRequests.handler(\n          {params: {}, page: context.getSelectedMcpPage()},\n          response,\n          context,\n        );\n        assert.ok(response.includeNetworkRequests);\n        assert.strictEqual(response.networkRequestsPageIdx, undefined);\n      });\n    });\n\n    it('list requests form current navigations only', async t => {\n      server.addHtmlRoute('/one', html`<main>First</main>`);\n      server.addHtmlRoute('/two', html`<main>Second</main>`);\n      server.addHtmlRoute('/three', html`<main>Third</main>`);\n\n      await withMcpContext(async (response, context) => {\n        await context.setUpNetworkCollectorForTesting();\n        const page = context.getSelectedPptrPage();\n        await page.goto(server.getRoute('/one'));\n        await page.goto(server.getRoute('/two'));\n        await page.goto(server.getRoute('/three'));\n        await listNetworkRequests.handler(\n          {\n            params: {},\n\n            page: context.getSelectedMcpPage(),\n          },\n          response,\n          context,\n        );\n        const responseData = await response.handle('list_request', context);\n        t.assert.snapshot?.(\n          stabilizeResponseOutput(getTextContent(responseData.content[0])),\n        );\n      });\n    });\n\n    it('list requests from previous navigations', async t => {\n      server.addHtmlRoute('/one', html`<main>First</main>`);\n      server.addHtmlRoute('/two', html`<main>Second</main>`);\n      server.addHtmlRoute('/three', html`<main>Third</main>`);\n\n      await withMcpContext(async (response, context) => {\n        await context.setUpNetworkCollectorForTesting();\n        const page = context.getSelectedPptrPage();\n        await page.goto(server.getRoute('/one'));\n        await page.goto(server.getRoute('/two'));\n        await page.goto(server.getRoute('/three'));\n        await listNetworkRequests.handler(\n          {\n            params: {\n              includePreservedRequests: true,\n            },\n            page: context.getSelectedMcpPage(),\n          },\n          response,\n          context,\n        );\n        const responseData = await response.handle('list_request', context);\n        t.assert.snapshot?.(\n          stabilizeResponseOutput(getTextContent(responseData.content[0])),\n        );\n      });\n    });\n\n    it('list requests from previous navigations from redirects', async t => {\n      server.addRoute('/redirect', async (_req, res) => {\n        res.writeHead(302, {\n          Location: server.getRoute('/redirected'),\n        });\n        res.end();\n      });\n\n      server.addHtmlRoute(\n        '/redirected',\n        html`<script>\n          document.location.href = '/redirected-page';\n        </script>`,\n      );\n\n      server.addHtmlRoute(\n        '/redirected-page',\n        html`<main>I was redirected 2 times</main>`,\n      );\n\n      await withMcpContext(async (response, context) => {\n        await context.setUpNetworkCollectorForTesting();\n        const page = context.getSelectedPptrPage();\n        await page.goto(server.getRoute('/redirect'), {\n          waitUntil: 'networkidle0',\n        });\n        await listNetworkRequests.handler(\n          {\n            params: {\n              includePreservedRequests: true,\n            },\n            page: context.getSelectedMcpPage(),\n          },\n          response,\n          context,\n        );\n        const responseData = await response.handle('list_request', context);\n        t.assert.snapshot?.(\n          stabilizeResponseOutput(getTextContent(responseData.content[0])),\n        );\n      });\n    });\n  });\n  describe('network_get_request', () => {\n    it('attaches request', async () => {\n      await withMcpContext(async (response, context) => {\n        const page = context.getSelectedPptrPage();\n        await page.goto('data:text/html,<div>Hello MCP</div>');\n        await getNetworkRequest.handler(\n          {params: {reqid: 1}, page: context.getSelectedMcpPage()},\n          response,\n          context,\n        );\n\n        assert.equal(response.attachedNetworkRequestId, 1);\n      });\n    });\n    it('should not add the request list', async () => {\n      await withMcpContext(async (response, context) => {\n        const page = context.getSelectedPptrPage();\n        await page.goto('data:text/html,<div>Hello MCP</div>');\n        await getNetworkRequest.handler(\n          {params: {reqid: 1}, page: context.getSelectedMcpPage()},\n          response,\n          context,\n        );\n        assert(!response.includeNetworkRequests);\n      });\n    });\n    it('should get request from previous navigations', async t => {\n      server.addHtmlRoute('/one', html`<main>First</main>`);\n      server.addHtmlRoute('/two', html`<main>Second</main>`);\n      server.addHtmlRoute('/three', html`<main>Third</main>`);\n\n      await withMcpContext(async (response, context) => {\n        await context.setUpNetworkCollectorForTesting();\n        const page = context.getSelectedPptrPage();\n        await page.goto(server.getRoute('/one'));\n        await page.goto(server.getRoute('/two'));\n        await page.goto(server.getRoute('/three'));\n        await getNetworkRequest.handler(\n          {\n            params: {\n              reqid: 1,\n            },\n            page: context.getSelectedMcpPage(),\n          },\n          response,\n          context,\n        );\n        const responseData = await response.handle('get_request', context);\n\n        t.assert.snapshot?.(\n          stabilizeResponseOutput(getTextContent(responseData.content[0])),\n        );\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "tests/tools/pages.test.js.snapshot",
    "content": "exports[`pages > list_pages > list pages for extension pages with --category-extensions 1`] = `\n## Pages\n1: about:blank [selected]\n## Extension Pages\n2: chrome-extension://<extension-id>/popup.html\n`;\n\nexports[`pages > list_pages > list pages for extension service workers with --category-extensions 1`] = `\n## Pages\n1: about:blank [selected]\n## Extension Service Workers\nsw-1: chrome-extension://<extension-id>/sw.js\n`;\n\nexports[`pages > list_pages > list pages for extension service workers without --category-extensions 1`] = `\n## Pages\n1: about:blank [selected]\n`;\n\nexports[`pages > list_pages > list pages for side panels with --category-extensions 1`] = `\n## Pages\n1: about:blank\n## Extension Pages\n2: chrome-extension://<extension-id>/sidepanel.html [selected]\n## Extension Service Workers\nsw-1: chrome-extension://<extension-id>/sw.js\n`;\n"
  },
  {
    "path": "tests/tools/pages.test.ts",
    "content": "/**\n * @license\n * Copyright 2025 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport assert from 'node:assert';\nimport path from 'node:path';\nimport {afterEach, describe, it} from 'node:test';\n\nimport type {Dialog} from 'puppeteer-core';\nimport sinon from 'sinon';\n\nimport type {ParsedArguments} from '../../src/bin/chrome-devtools-mcp-cli-options.js';\nimport {\n  listPages,\n  newPage,\n  closePage,\n  selectPage,\n  navigatePage,\n  resizePage,\n  handleDialog,\n  getTabId,\n} from '../../src/tools/pages.js';\nimport {html, withMcpContext} from '../utils.js';\n\nconst EXTENSION_SW_PATH = path.join(\n  import.meta.dirname,\n  '../../../tests/tools/fixtures/extension-sw',\n);\nconst EXTENSION_PATH = path.join(\n  import.meta.dirname,\n  '../../../tests/tools/fixtures/extension',\n);\nconst EXTENSION_SIDE_PANEL_PATH = path.join(\n  import.meta.dirname,\n  '../../../tests/tools/fixtures/extension-side-panel',\n);\n\ndescribe('pages', () => {\n  afterEach(() => {\n    sinon.restore();\n  });\n\n  describe('list_pages', () => {\n    it('list pages', async () => {\n      await withMcpContext(async (response, context) => {\n        await listPages().handler(\n          {params: {}, page: context.getSelectedMcpPage()},\n          response,\n          context,\n        );\n        assert.ok(response.includePages);\n      });\n    });\n    it(`list pages for extension pages with --category-extensions`, async t => {\n      await withMcpContext(\n        async (response, context) => {\n          const extensionId = await context.installExtension(EXTENSION_PATH);\n\n          assert.ok(extensionId);\n\n          await context.triggerExtensionAction(extensionId);\n\n          const _popupTarget = await context.browser.waitForTarget(\n            t => t.type() === 'page' && t.url().includes('chrome-extension://'),\n          );\n\n          response.resetResponseLineForTesting();\n          const listPageDef = listPages({\n            categoryExtensions: true,\n          } as ParsedArguments);\n          await listPageDef.handler(\n            {params: {}, page: context.getSelectedMcpPage()},\n            response,\n            context,\n          );\n\n          const result = await response.handle(listPageDef.name, context);\n          const textContent = result.content.find(c => c.type === 'text') as {\n            type: 'text';\n            text: string;\n          };\n          assert.ok(textContent);\n\n          const text = textContent.text.replaceAll(\n            extensionId,\n            '<extension-id>',\n          );\n          t.assert.snapshot?.(text);\n        },\n        {\n          executablePath: process.env.CHROME_M146_EXECUTABLE_PATH,\n        },\n        {\n          categoryExtensions: true,\n        } as ParsedArguments,\n      );\n    });\n\n    for (const categoryExtensions of [true, false]) {\n      it(`list pages for extension service workers ${categoryExtensions ? 'with' : 'without'} --category-extensions`, async t => {\n        await withMcpContext(\n          async (response, context) => {\n            const extensionId =\n              await context.installExtension(EXTENSION_SW_PATH);\n            assert.ok(extensionId);\n\n            const swTarget = await context.browser.waitForTarget(\n              target =>\n                target.type() === 'service_worker' &&\n                target.url().includes('chrome-extension://'),\n            );\n            const swUrl = swTarget.url();\n\n            const listPageDef = listPages({\n              categoryExtensions,\n            } as ParsedArguments);\n            await listPageDef.handler(\n              {params: {}, page: context.getSelectedMcpPage()},\n              response,\n              context,\n            );\n\n            const result = await response.handle(listPageDef.name, context);\n            const textContent = result.content.find(c => c.type === 'text') as {\n              type: 'text';\n              text: string;\n            };\n            assert.ok(textContent);\n\n            if (categoryExtensions) {\n              const structured = result.structuredContent as {\n                extensionServiceWorkers: Array<{url: string}>;\n              };\n              assert.deepStrictEqual(\n                structured.extensionServiceWorkers.map(sw => sw.url),\n                [swUrl],\n              );\n            }\n\n            const text = textContent.text.replaceAll(\n              extensionId,\n              '<extension-id>',\n            );\n            t.assert.snapshot?.(text);\n          },\n          {},\n          {\n            categoryExtensions,\n          } as ParsedArguments,\n        );\n      });\n    }\n\n    it('list pages for side panels with --category-extensions', async t => {\n      await withMcpContext(\n        async (response, context) => {\n          const extensionId = await context.installExtension(\n            EXTENSION_SIDE_PANEL_PATH,\n          );\n\n          assert.ok(extensionId);\n\n          const sidePanelPage = await context.newPage();\n          await sidePanelPage.pptrPage.goto(\n            `chrome-extension://${extensionId}/sidepanel.html`,\n          );\n\n          await context.waitForTextOnPage(['Side Panel']);\n\n          // Wait for service worker used in the snapshot.\n          await context.browser.waitForTarget(\n            target => target.type() === 'service_worker',\n          );\n\n          const listPageDef = listPages({\n            categoryExtensions: true,\n          } as ParsedArguments);\n          await listPageDef.handler(\n            {params: {}, page: context.getSelectedMcpPage()},\n            response,\n            context,\n          );\n\n          const result = await response.handle(listPageDef.name, context);\n          const textContent = result.content.find(c => c.type === 'text') as {\n            type: 'text';\n            text: string;\n          };\n          assert.ok(textContent);\n\n          const text = textContent.text.replaceAll(\n            extensionId,\n            '<extension-id>',\n          );\n          t.assert.snapshot?.(text);\n        },\n        {\n          executablePath: process.env.CHROME_M146_EXECUTABLE_PATH,\n        },\n        {\n          categoryExtensions: true,\n        } as ParsedArguments,\n      );\n    });\n  });\n  describe('new_page', () => {\n    it('create a page', async () => {\n      await withMcpContext(async (response, context) => {\n        assert.strictEqual(\n          context.getPageById(1),\n          context.getSelectedMcpPage(),\n        );\n        await newPage.handler(\n          {params: {url: 'about:blank'}},\n          response,\n          context,\n        );\n        assert.strictEqual(\n          context.getPageById(2),\n          context.getSelectedMcpPage(),\n        );\n        assert.ok(response.includePages);\n      });\n    });\n    it('create a page in the background', async () => {\n      await withMcpContext(async (response, context) => {\n        const originalPage = context.getPageById(1);\n        assert.strictEqual(originalPage, context.getSelectedMcpPage());\n        // Ensure original page has focus\n        await originalPage.pptrPage.bringToFront();\n        assert.strictEqual(\n          await originalPage.pptrPage.evaluate(() => document.hasFocus()),\n          true,\n        );\n        await newPage.handler(\n          {params: {url: 'about:blank', background: true}},\n          response,\n          context,\n        );\n        // New page should be selected but original should retain focus\n        assert.strictEqual(\n          context.getPageById(2),\n          context.getSelectedMcpPage(),\n        );\n        assert.strictEqual(\n          await originalPage.pptrPage.evaluate(() => document.hasFocus()),\n          true,\n        );\n        assert.ok(response.includePages);\n      });\n    });\n  });\n  describe('new_page with isolatedContext', () => {\n    it('creates a page in an isolated context', async () => {\n      await withMcpContext(async (response, context) => {\n        await newPage.handler(\n          {params: {url: 'about:blank', isolatedContext: 'session-a'}},\n          response,\n          context,\n        );\n        const page = context.getSelectedPptrPage();\n        assert.strictEqual(context.getIsolatedContextName(page), 'session-a');\n        assert.ok(response.includePages);\n      });\n    });\n\n    it('reuses the same context for the same isolatedContext name', async () => {\n      await withMcpContext(async (response, context) => {\n        await newPage.handler(\n          {params: {url: 'about:blank', isolatedContext: 'session-a'}},\n          response,\n          context,\n        );\n        const page1 = context.getSelectedPptrPage();\n        await newPage.handler(\n          {params: {url: 'about:blank', isolatedContext: 'session-a'}},\n          response,\n          context,\n        );\n        const page2 = context.getSelectedPptrPage();\n        assert.notStrictEqual(page1, page2);\n        assert.strictEqual(context.getIsolatedContextName(page1), 'session-a');\n        assert.strictEqual(context.getIsolatedContextName(page2), 'session-a');\n        assert.strictEqual(page1.browserContext(), page2.browserContext());\n      });\n    });\n\n    it('creates separate contexts for different isolatedContext names', async () => {\n      await withMcpContext(async (response, context) => {\n        await newPage.handler(\n          {params: {url: 'about:blank', isolatedContext: 'session-a'}},\n          response,\n          context,\n        );\n        const pageA = context.getSelectedPptrPage();\n        await newPage.handler(\n          {params: {url: 'about:blank', isolatedContext: 'session-b'}},\n          response,\n          context,\n        );\n        const pageB = context.getSelectedPptrPage();\n        assert.strictEqual(context.getIsolatedContextName(pageA), 'session-a');\n        assert.strictEqual(context.getIsolatedContextName(pageB), 'session-b');\n        assert.notStrictEqual(pageA.browserContext(), pageB.browserContext());\n      });\n    });\n\n    it('includes isolatedContext in page listing', async () => {\n      await withMcpContext(async (response, context) => {\n        await newPage.handler(\n          {params: {url: 'about:blank', isolatedContext: 'session-a'}},\n          response,\n          context,\n        );\n        const result = await response.handle('new_page', context);\n        const pages = (\n          result.structuredContent as {pages: Array<{isolatedContext?: string}>}\n        ).pages;\n        const isolatedPage = pages.find(p => p.isolatedContext === 'session-a');\n        assert.ok(isolatedPage);\n      });\n    });\n\n    it('does not set isolatedContext for pages in the default context', async () => {\n      await withMcpContext(async (response, context) => {\n        const page = context.getSelectedPptrPage();\n        assert.strictEqual(context.getIsolatedContextName(page), undefined);\n        await newPage.handler(\n          {params: {url: 'about:blank'}},\n          response,\n          context,\n        );\n        assert.strictEqual(\n          context.getIsolatedContextName(context.getSelectedPptrPage()),\n          undefined,\n        );\n      });\n    });\n\n    it('closes an isolated page without errors', async () => {\n      await withMcpContext(async (response, context) => {\n        await newPage.handler(\n          {params: {url: 'about:blank', isolatedContext: 'session-a'}},\n          response,\n          context,\n        );\n        const page = context.getSelectedPptrPage();\n        const pageId = context.getPageId(page)!;\n        assert.ok(!page.isClosed());\n        await closePage.handler({params: {pageId}}, response, context);\n        assert.ok(page.isClosed());\n      });\n    });\n  });\n\n  it('navigate_page targets the pageId page, not the global selection', async () => {\n    await withMcpContext(async (response, context) => {\n      await newPage.handler(\n        {\n          params: {\n            url: 'data:text/html,<h1>Initial</h1>',\n            isolatedContext: 'nav-ctx',\n          },\n        },\n        response,\n        context,\n      );\n      const isolatedPage = context.getSelectedMcpPage();\n\n      // Switch global selection back to the default page.\n      await selectPage.handler({params: {pageId: 1}}, response, context);\n      assert.notStrictEqual(context.getSelectedMcpPage(), isolatedPage);\n\n      // Navigate using page; should target the isolated page.\n      await navigatePage.handler(\n        {\n          params: {\n            url: 'data:text/html,<h1>Navigated</h1>',\n          },\n          page: isolatedPage,\n        },\n        response,\n        context,\n      );\n\n      // Verify the isolated page was navigated.\n      const content = await isolatedPage.pptrPage.evaluate(\n        () => document.querySelector('h1')?.textContent,\n      );\n      assert.strictEqual(content, 'Navigated');\n\n      // Verify the default page was NOT affected.\n      const defaultContent = await context\n        .getSelectedPptrPage()\n        .evaluate(() => document.querySelector('h1')?.textContent);\n      assert.notStrictEqual(defaultContent, 'Navigated');\n    });\n  });\n\n  describe('close_page', () => {\n    it('closes a page', async () => {\n      await withMcpContext(async (response, context) => {\n        const page = await context.newPage();\n        assert.strictEqual(\n          context.getPageById(2),\n          context.getSelectedMcpPage(),\n        );\n        assert.strictEqual(context.getPageById(2), page);\n        await closePage.handler({params: {pageId: 2}}, response, context);\n        assert.ok(page.pptrPage.isClosed());\n        assert.ok(response.includePages);\n      });\n    });\n    it('cannot close the last page', async () => {\n      await withMcpContext(async (response, context) => {\n        const page = context.getSelectedPptrPage();\n        await closePage.handler({params: {pageId: 1}}, response, context);\n        assert.deepStrictEqual(\n          response.responseLines[0],\n          `The last open page cannot be closed. It is fine to keep it open.`,\n        );\n        assert.ok(response.includePages);\n        assert.ok(!page.isClosed());\n      });\n    });\n  });\n  describe('select_page', () => {\n    it('selects a page', async () => {\n      await withMcpContext(async (response, context) => {\n        await context.newPage();\n        assert.strictEqual(\n          context.getPageById(2),\n          context.getSelectedMcpPage(),\n        );\n        await selectPage.handler({params: {pageId: 1}}, response, context);\n        assert.strictEqual(\n          context.getPageById(1),\n          context.getSelectedMcpPage(),\n        );\n        assert.ok(response.includePages);\n      });\n    });\n    it('selects a page and keeps it focused in the background', async () => {\n      await withMcpContext(async (response, context) => {\n        await context.newPage();\n        assert.strictEqual(\n          context.getPageById(2),\n          context.getSelectedMcpPage(),\n        );\n        assert.strictEqual(\n          await context\n            .getPageById(1)\n            .pptrPage.evaluate(() => document.hasFocus()),\n          true,\n        );\n        await selectPage.handler({params: {pageId: 1}}, response, context);\n        assert.strictEqual(\n          context.getPageById(1),\n          context.getSelectedMcpPage(),\n        );\n        assert.strictEqual(\n          await context\n            .getPageById(1)\n            .pptrPage.evaluate(() => document.hasFocus()),\n          true,\n        );\n        assert.ok(response.includePages);\n      });\n    });\n    it('preserves focus across different browser contexts', async () => {\n      await withMcpContext(async (response, context) => {\n        // Create pages in separate isolated contexts.\n        await newPage.handler(\n          {params: {url: 'about:blank', isolatedContext: 'ctx-a'}},\n          response,\n          context,\n        );\n        const pageA = context.getSelectedPptrPage();\n        const pageAId = context.getPageId(pageA)!;\n\n        await newPage.handler(\n          {params: {url: 'about:blank', isolatedContext: 'ctx-b'}},\n          response,\n          context,\n        );\n        const pageB = context.getSelectedPptrPage();\n\n        // Selecting pageB (ctx-b) should not defocus pageA (ctx-a).\n        assert.strictEqual(\n          await pageA.evaluate(() => document.hasFocus()),\n          true,\n        );\n        assert.strictEqual(\n          await pageB.evaluate(() => document.hasFocus()),\n          true,\n        );\n\n        // Switching back to pageA should preserve pageB's focus.\n        await selectPage.handler(\n          {params: {pageId: pageAId}},\n          response,\n          context,\n        );\n        assert.strictEqual(\n          await pageA.evaluate(() => document.hasFocus()),\n          true,\n        );\n        assert.strictEqual(\n          await pageB.evaluate(() => document.hasFocus()),\n          true,\n        );\n      });\n    });\n  });\n  describe('navigate_page', () => {\n    it('navigates to correct page', async () => {\n      await withMcpContext(async (response, context) => {\n        await navigatePage.handler(\n          {\n            params: {url: 'data:text/html,<div>Hello MCP</div>'},\n            page: context.getSelectedMcpPage(),\n          },\n          response,\n          context,\n        );\n        const page = context.getSelectedPptrPage();\n        assert.equal(\n          await page.evaluate(() => document.querySelector('div')?.textContent),\n          'Hello MCP',\n        );\n        assert.ok(response.includePages);\n      });\n    });\n\n    it('throws an error if the page was closed not by the MCP server', async () => {\n      await withMcpContext(async (response, context) => {\n        const page = await context.newPage();\n        assert.strictEqual(\n          context.getPageById(2),\n          context.getSelectedMcpPage(),\n        );\n        assert.strictEqual(context.getPageById(2), page);\n\n        await page.pptrPage.close();\n\n        try {\n          await navigatePage.handler(\n            {\n              params: {url: 'data:text/html,<div>Hello MCP</div>'},\n              page: context.getSelectedMcpPage(),\n            },\n            response,\n            context,\n          );\n          assert.fail('should not reach here');\n        } catch (err) {\n          assert.strictEqual(\n            err.message,\n            'The selected page has been closed. Call list_pages to see open pages.',\n          );\n        }\n      });\n    });\n\n    it('respects the timeout parameter', async () => {\n      await withMcpContext(async (response, context) => {\n        const page = context.getSelectedPptrPage();\n        const stub = sinon.stub(page, 'waitForNavigation').resolves(null);\n\n        try {\n          await navigatePage.handler(\n            {\n              params: {\n                url: 'about:blank',\n                timeout: 12345,\n              },\n              page: context.getSelectedMcpPage(),\n            },\n            response,\n            context,\n          );\n        } finally {\n          stub.restore();\n        }\n\n        assert.strictEqual(\n          stub.firstCall.args[0]?.timeout,\n          12345,\n          'The timeout parameter should be passed to waitForNavigation',\n        );\n      });\n    });\n    it('go back', async () => {\n      await withMcpContext(async (response, context) => {\n        const page = context.getSelectedPptrPage();\n        await page.goto('data:text/html,<div>Hello MCP</div>');\n        await navigatePage.handler(\n          {params: {type: 'back'}, page: context.getSelectedMcpPage()},\n          response,\n          context,\n        );\n\n        assert.equal(\n          await page.evaluate(() => document.location.href),\n          'about:blank',\n        );\n        assert.ok(response.includePages);\n      });\n    });\n    it('go forward', async () => {\n      await withMcpContext(async (response, context) => {\n        const page = context.getSelectedPptrPage();\n        await page.goto('data:text/html,<div>Hello MCP</div>');\n        await page.goBack();\n        await navigatePage.handler(\n          {params: {type: 'forward'}, page: context.getSelectedMcpPage()},\n          response,\n          context,\n        );\n\n        assert.equal(\n          await page.evaluate(() => document.querySelector('div')?.textContent),\n          'Hello MCP',\n        );\n        assert.ok(response.includePages);\n      });\n    });\n    it('reload', async () => {\n      await withMcpContext(async (response, context) => {\n        const page = context.getSelectedPptrPage();\n        await page.goto('data:text/html,<div>Hello MCP</div>');\n        await navigatePage.handler(\n          {params: {type: 'reload'}, page: context.getSelectedMcpPage()},\n          response,\n          context,\n        );\n\n        assert.equal(\n          await page.evaluate(() => document.location.href),\n          'data:text/html,<div>Hello MCP</div>',\n        );\n        assert.ok(response.includePages);\n      });\n    });\n\n    it('reload with accpeting the beforeunload dialog', async () => {\n      await withMcpContext(async (response, context) => {\n        const page = context.getSelectedPptrPage();\n        await page.setContent(\n          html` <script>\n            window.addEventListener('beforeunload', e => {\n              e.preventDefault();\n              e.returnValue = '';\n            });\n          </script>`,\n        );\n\n        await navigatePage.handler(\n          {params: {type: 'reload'}, page: context.getSelectedMcpPage()},\n          response,\n          context,\n        );\n\n        assert.strictEqual(context.getSelectedMcpPage().getDialog(), undefined);\n        assert.ok(response.includePages);\n        assert.strictEqual(\n          response.responseLines.join('\\n'),\n          'Accepted a beforeunload dialog.\\nSuccessfully reloaded the page.',\n        );\n      });\n    });\n\n    it('reload with declining the beforeunload dialog', async () => {\n      await withMcpContext(async (response, context) => {\n        const page = context.getSelectedPptrPage();\n        await page.setContent(\n          html` <script>\n            window.addEventListener('beforeunload', e => {\n              e.preventDefault();\n              e.returnValue = '';\n            });\n          </script>`,\n        );\n\n        await navigatePage.handler(\n          {\n            params: {\n              type: 'reload',\n              handleBeforeUnload: 'decline',\n              timeout: 500,\n            },\n            page: context.getSelectedMcpPage(),\n          },\n          response,\n          context,\n        );\n\n        assert.strictEqual(context.getSelectedMcpPage().getDialog(), undefined);\n        assert.ok(response.includePages);\n        assert.strictEqual(\n          response.responseLines.join('\\n'),\n          'Declined a beforeunload dialog.\\nUnable to reload the selected page: Navigation timeout of 500 ms exceeded.',\n        );\n      });\n    });\n\n    it('go forward with error', async () => {\n      await withMcpContext(async (response, context) => {\n        await navigatePage.handler(\n          {params: {type: 'forward'}, page: context.getSelectedMcpPage()},\n          response,\n          context,\n        );\n\n        assert.ok(\n          response.responseLines\n            .at(0)\n            ?.startsWith('Unable to navigate forward in the selected page:'),\n        );\n        assert.ok(response.includePages);\n      });\n    });\n    it('go back with error', async () => {\n      await withMcpContext(async (response, context) => {\n        await navigatePage.handler(\n          {params: {type: 'back'}, page: context.getSelectedMcpPage()},\n          response,\n          context,\n        );\n\n        assert.ok(\n          response.responseLines\n            .at(0)\n            ?.startsWith('Unable to navigate back in the selected page:'),\n        );\n        assert.ok(response.includePages);\n      });\n    });\n    it('navigates to correct page with initScript', async () => {\n      await withMcpContext(async (response, context) => {\n        await navigatePage.handler(\n          {\n            params: {\n              url: 'data:text/html,<div>Hello MCP</div>',\n              initScript: 'window.initScript = \"completed\"',\n            },\n            page: context.getSelectedMcpPage(),\n          },\n          response,\n          context,\n        );\n        const page = context.getSelectedPptrPage();\n\n        // wait for up to 1s for the global variable to set by the initScript to exist\n        await page.waitForFunction(\"window.initScript==='completed'\", {\n          timeout: 1000,\n        });\n\n        assert.ok(response.includePages);\n      });\n    });\n  });\n  describe('resize', () => {\n    it('resize the page', async () => {\n      await withMcpContext(async (response, context) => {\n        const page = context.getSelectedPptrPage();\n        const resizePromise = page.evaluate(() => {\n          return new Promise(resolve => {\n            window.addEventListener('resize', resolve, {once: true});\n          });\n        });\n        await resizePage.handler(\n          {\n            params: {width: 700, height: 500},\n            page: context.getSelectedMcpPage(),\n          },\n          response,\n          context,\n        );\n        await resizePromise;\n        await page.waitForFunction(\n          () => window.innerWidth === 700 && window.innerHeight === 500,\n        );\n        const dimensions = await page.evaluate(() => {\n          return [window.innerWidth, window.innerHeight];\n        });\n        assert.deepStrictEqual(dimensions, [700, 500]);\n      });\n    });\n\n    it('resize when window state is normal', async () => {\n      await withMcpContext(async (response, context) => {\n        const page = context.getSelectedPptrPage();\n        const browser = page.browser();\n        const windowId = await page.windowId();\n        await browser.setWindowBounds(windowId, {windowState: 'normal'});\n\n        const {windowState} = await browser.getWindowBounds(windowId);\n        assert.strictEqual(windowState, 'normal');\n\n        const resizePromise = page.evaluate(() => {\n          return new Promise(resolve => {\n            window.addEventListener('resize', resolve, {once: true});\n          });\n        });\n        await resizePage.handler(\n          {\n            params: {width: 650, height: 450},\n            page: context.getSelectedMcpPage(),\n          },\n          response,\n          context,\n        );\n        await resizePromise;\n        await page.waitForFunction(\n          () => window.innerWidth === 650 && window.innerHeight === 450,\n        );\n        const dimensions = await page.evaluate(() => {\n          return [window.innerWidth, window.innerHeight];\n        });\n        assert.deepStrictEqual(dimensions, [650, 450]);\n      });\n    });\n\n    it('resize when window state is minimized', async () => {\n      await withMcpContext(async (response, context) => {\n        const page = context.getSelectedPptrPage();\n        const browser = page.browser();\n        const windowId = await page.windowId();\n        await browser.setWindowBounds(windowId, {windowState: 'minimized'});\n\n        const {windowState} = await browser.getWindowBounds(windowId);\n        assert.strictEqual(windowState, 'minimized');\n\n        const resizePromise = page.evaluate(() => {\n          return new Promise(resolve => {\n            window.addEventListener('resize', resolve, {once: true});\n          });\n        });\n        await resizePage.handler(\n          {\n            params: {width: 750, height: 550},\n            page: context.getSelectedMcpPage(),\n          },\n          response,\n          context,\n        );\n        await resizePromise;\n        await page.waitForFunction(\n          () => window.innerWidth === 750 && window.innerHeight === 550,\n        );\n        const dimensions = await page.evaluate(() => {\n          return [window.innerWidth, window.innerHeight];\n        });\n        assert.deepStrictEqual(dimensions, [750, 550]);\n      });\n    });\n\n    it('resize when window state is maximized', async () => {\n      await withMcpContext(async (response, context) => {\n        const page = context.getSelectedPptrPage();\n        const browser = page.browser();\n        const windowId = await page.windowId();\n        await browser.setWindowBounds(windowId, {windowState: 'maximized'});\n\n        const {windowState} = await browser.getWindowBounds(windowId);\n        assert.strictEqual(windowState, 'maximized');\n\n        const resizePromise = page.evaluate(() => {\n          return new Promise(resolve => {\n            window.addEventListener('resize', resolve, {once: true});\n          });\n        });\n        await resizePage.handler(\n          {\n            params: {width: 725, height: 525},\n            page: context.getSelectedMcpPage(),\n          },\n          response,\n          context,\n        );\n        await resizePromise;\n        await page.waitForFunction(\n          () => window.innerWidth === 725 && window.innerHeight === 525,\n        );\n        const dimensions = await page.evaluate(() => {\n          return [window.innerWidth, window.innerHeight];\n        });\n        assert.deepStrictEqual(dimensions, [725, 525]);\n      });\n    });\n\n    it('resize when window state is fullscreen', async () => {\n      await withMcpContext(async (response, context) => {\n        const page = context.getSelectedPptrPage();\n        const browser = page.browser();\n        const windowId = await page.windowId();\n        await browser.setWindowBounds(windowId, {windowState: 'fullscreen'});\n\n        const {windowState} = await browser.getWindowBounds(windowId);\n        assert.strictEqual(windowState, 'fullscreen');\n\n        const resizePromise = page.evaluate(() => {\n          return new Promise(resolve => {\n            window.addEventListener('resize', resolve, {once: true});\n          });\n        });\n        await resizePage.handler(\n          {\n            params: {width: 850, height: 650},\n            page: context.getSelectedMcpPage(),\n          },\n          response,\n          context,\n        );\n        await resizePromise;\n        await page.waitForFunction(\n          () => window.innerWidth === 850 && window.innerHeight === 650,\n        );\n        const dimensions = await page.evaluate(() => {\n          return [window.innerWidth, window.innerHeight];\n        });\n        assert.deepStrictEqual(dimensions, [850, 650]);\n      });\n    });\n  });\n\n  describe('dialogs', () => {\n    it('can accept dialogs', async () => {\n      await withMcpContext(async (response, context) => {\n        const page = context.getSelectedPptrPage();\n        const dialogPromise = new Promise<void>(resolve => {\n          page.on('dialog', () => {\n            resolve();\n          });\n        });\n        page.evaluate(() => {\n          alert('test');\n        });\n        await dialogPromise;\n        await handleDialog.handler(\n          {\n            params: {\n              action: 'accept',\n            },\n            page: context.getSelectedMcpPage(),\n          },\n          response,\n          context,\n        );\n        assert.strictEqual(context.getSelectedMcpPage().getDialog(), undefined);\n        assert.strictEqual(\n          response.responseLines[0],\n          'Successfully accepted the dialog',\n        );\n      });\n    });\n    it('can dismiss dialogs', async () => {\n      await withMcpContext(async (response, context) => {\n        const page = context.getSelectedPptrPage();\n        const dialogPromise = new Promise<void>(resolve => {\n          page.on('dialog', () => {\n            resolve();\n          });\n        });\n        page.evaluate(() => {\n          alert('test');\n        });\n        await dialogPromise;\n        await handleDialog.handler(\n          {\n            params: {\n              action: 'dismiss',\n            },\n            page: context.getSelectedMcpPage(),\n          },\n          response,\n          context,\n        );\n        assert.strictEqual(context.getSelectedMcpPage().getDialog(), undefined);\n        assert.strictEqual(\n          response.responseLines[0],\n          'Successfully dismissed the dialog',\n        );\n      });\n    });\n    it('can dismiss already dismissed dialog dialogs', async () => {\n      await withMcpContext(async (response, context) => {\n        const page = context.getSelectedPptrPage();\n        const dialogPromise = new Promise<Dialog>(resolve => {\n          page.on('dialog', dialog => {\n            resolve(dialog);\n          });\n        });\n        page.evaluate(() => {\n          alert('test');\n        });\n        const dialog = await dialogPromise;\n        await dialog.dismiss();\n        await handleDialog.handler(\n          {\n            params: {\n              action: 'dismiss',\n            },\n            page: context.getSelectedMcpPage(),\n          },\n          response,\n          context,\n        );\n        assert.strictEqual(context.getSelectedMcpPage().getDialog(), undefined);\n        assert.strictEqual(\n          response.responseLines[0],\n          'Successfully dismissed the dialog',\n        );\n      });\n    });\n    it('can handle a dialog on a non-selected page via pageId', async () => {\n      await withMcpContext(async (response, context) => {\n        const page1 = context.getSelectedMcpPage();\n        await context.newPage(); // page2 is now selected\n\n        const dialogPromise = new Promise<void>(resolve => {\n          page1.pptrPage.once('dialog', () => {\n            resolve();\n          });\n        });\n        page1.pptrPage.evaluate(() => {\n          alert('test');\n        });\n        await dialogPromise;\n\n        // page1 is not selected, but its dialog should be accessible via page.\n        await handleDialog.handler(\n          {\n            params: {\n              action: 'accept',\n            },\n            page: page1,\n          },\n          response,\n          context,\n        );\n        assert.strictEqual(page1.getDialog(), undefined);\n        assert.strictEqual(\n          response.responseLines[0],\n          'Successfully accepted the dialog',\n        );\n      });\n    });\n    it('tracks dialogs independently per page', async () => {\n      await withMcpContext(async (response, context) => {\n        const page1 = context.getSelectedMcpPage();\n        await context.newPage();\n        const page2 = context.getSelectedMcpPage();\n\n        // Trigger dialog on page1.\n        const dialog1Promise = new Promise<void>(resolve => {\n          page1.pptrPage.once('dialog', () => {\n            resolve();\n          });\n        });\n        page1.pptrPage.evaluate(() => {\n          alert('dialog1');\n        });\n        await dialog1Promise;\n\n        // Trigger dialog on page2.\n        const dialog2Promise = new Promise<void>(resolve => {\n          page2.pptrPage.once('dialog', () => {\n            resolve();\n          });\n        });\n        page2.pptrPage.evaluate(() => {\n          alert('dialog2');\n        });\n        await dialog2Promise;\n\n        // Both dialogs should be tracked.\n        assert.ok(page1.getDialog());\n        assert.ok(page2.getDialog());\n\n        // Handle page1's dialog; page2's should remain.\n        await handleDialog.handler(\n          {params: {action: 'accept'}, page: page1},\n          response,\n          context,\n        );\n        assert.strictEqual(page1.getDialog(), undefined);\n        assert.ok(page2.getDialog());\n\n        // Handle page2's dialog.\n        await handleDialog.handler(\n          {params: {action: 'dismiss'}, page: page2},\n          response,\n          context,\n        );\n        assert.strictEqual(page2.getDialog(), undefined);\n      });\n    });\n  });\n\n  describe('get_tab_id', () => {\n    it('returns the tab id', async () => {\n      await withMcpContext(async (response, context) => {\n        const page = context.getSelectedPptrPage();\n        // @ts-expect-error _tabId is internal.\n        assert.ok(typeof page._tabId === 'string');\n        // @ts-expect-error _tabId is internal.\n        page._tabId = 'test-tab-id';\n        await getTabId.handler(\n          {params: {pageId: 1}, page: context.getSelectedMcpPage()},\n          response,\n          context,\n        );\n        const result = await response.handle('get_tab_id', context);\n        // @ts-expect-error _tabId is internal.\n        assert.strictEqual(result.structuredContent.tabId, 'test-tab-id');\n        assert.deepStrictEqual(response.responseLines, []);\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "tests/tools/performance.test.js.snapshot",
    "content": "exports[`performance > performance_analyze_insight > returns the information on the insight 1`] = `\n## Insight Title: LCP breakdown\n\n## Insight Summary:\nThis insight is used to analyze the time spent that contributed to the final LCP time and identify which of the 4 phases (or 2 if there was no LCP resource) are contributing most to the delay in rendering the LCP element.\n\n## Detailed analysis:\nThe Largest Contentful Paint (LCP) time for this navigation was 129 ms.\nThe LCP element is an image fetched from https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/4i7JstVZvgTFk9dxCe4a.svg (eventKey: s-1314, ts: 122411037986).\n## LCP resource network request: https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/4i7JstVZvgTFk9dxCe4a.svg\neventKey: s-1314\nTimings:\n- Queued at: 41 ms\n- Request sent at: 47 ms\n- Download complete at: 56 ms\n- Main thread processing completed at: 58 ms\nDurations:\n- Download time: 0.3 ms\n- Main thread processing time: 2 ms\n- Total duration: 17 ms\nRedirects: no redirects\nStatus code: 200\nMIME Type: image/svg+xml\nProtocol: unknown\nPriority: VeryHigh\nRender blocking: No\nFrom a service worker: No\nInitiators (root request to the request that directly loaded this one): none\n\n\nWe can break this time down into the 4 phases that combine to make the LCP time:\n\n- Time to first byte: 8 ms (6.1% of total LCP time)\n- Resource load delay: 33 ms (25.7% of total LCP time)\n- Resource load duration: 15 ms (11.4% of total LCP time)\n- Element render delay: 73 ms (56.8% of total LCP time)\n\n## Estimated savings: none\n\n## External resources:\n- https://developer.chrome.com/docs/performance/insights/lcp-breakdown\n- https://web.dev/articles/lcp\n- https://web.dev/articles/optimize-lcp\n`;\n\nexports[`performance > performance_stop_trace > returns an error message if parsing the trace buffer fails 1`] = `\nThe performance trace has been stopped.\nThere was an unexpected error parsing the trace:\nNo buffer was provided.\n`;\n\nexports[`performance > performance_stop_trace > returns the high level summary of the performance trace 1`] = `\nThe performance trace has been stopped.\n## Summary of Performance trace findings:\nURL: https://web.dev/\nTrace bounds: {min: 122410994891, max: 122416385853}\nCPU throttling: none\nNetwork throttling: none\n\n# Available insight sets\n\nThe following is a list of insight sets. An insight set covers a specific part of the trace, split by navigations. The insights within each insight set are specific to that part of the trace. Be sure to consider the insight set id and bounds when calling functions. If no specific insight set or navigation is mentioned, assume the user is referring to the first one.\n\n## insight set id: NAVIGATION_0\n\nURL: https://web.dev/\nBounds: {min: 122410996889, max: 122416385853}\nMetrics (lab / observed):\n  - LCP: 129 ms, event: (eventKey: r-6063, ts: 122411126100), nodeId: 7\n  - LCP breakdown:\n    - TTFB: 8 ms, bounds: {min: 122410996889, max: 122411004828}\n    - Load delay: 33 ms, bounds: {min: 122411004828, max: 122411037986}\n    - Load duration: 15 ms, bounds: {min: 122411037986, max: 122411052690}\n    - Render delay: 73 ms, bounds: {min: 122411052690, max: 122411126100}\n  - CLS: 0.00\nMetrics (field / real users):\n  - LCP: 2595 ms (scope: url)\n  - LCP breakdown:\n    - TTFB: 1273 ms (scope: url)\n    - Load delay: 86 ms (scope: url)\n    - Load duration: 451 ms (scope: url)\n    - Render delay: 786 ms (scope: url)\n  - INP: 140 ms (scope: url)\n  - CLS: 0.06 (scope: url)\n  - The above data is from CrUX–Chrome User Experience Report. It's how the page performs for real users.\n  - The values shown above are the p75 measure of all real Chrome users\n  - The scope indicates if the data came from the entire origin, or a specific url\n  - Lab metrics describe how this specific page load performed, while field metrics are an aggregation of results from real-world users. Best practice is to prioritize metrics that are bad in field data. Lab metrics may be better or worse than fields metrics depending on the developer's machine, network, or the actions performed while tracing.\nAvailable insights:\n  - insight name: LCPBreakdown\n    description: Each [subpart has specific improvement strategies](https://developer.chrome.com/docs/performance/insights/lcp-breakdown). Ideally, most of the LCP time should be spent on loading the resources, not within delays.\n    relevant trace bounds: {min: 122410996889, max: 122411126100}\n    example question: Help me optimize my LCP score\n    example question: Which LCP phase was most problematic?\n    example question: What can I do to reduce the LCP time for this page load?\n  - insight name: LCPDiscovery\n    description: [Optimize LCP](https://developer.chrome.com/docs/performance/insights/lcp-discovery) by making the LCP image discoverable from the HTML immediately, and avoiding lazy-loading\n    relevant trace bounds: {min: 122411004828, max: 122411055039}\n    example question: Suggest fixes to reduce my LCP\n    example question: What can I do to reduce my LCP discovery time?\n    example question: Why is LCP discovery time important?\n  - insight name: RenderBlocking\n    description: Requests are blocking the page's initial render, which may delay LCP. [Deferring or inlining](https://developer.chrome.com/docs/performance/insights/render-blocking) can move these network requests out of the critical path.\n    relevant trace bounds: {min: 122411037528, max: 122411053852}\n    example question: Show me the most impactful render blocking requests that I should focus on\n    example question: How can I reduce the number of render blocking requests?\n  - insight name: DocumentLatency\n    description: Your first network request is the most important. [Reduce its latency](https://developer.chrome.com/docs/performance/insights/document-latency) by avoiding redirects, ensuring a fast server response, and enabling text compression.\n    relevant trace bounds: {min: 122410998910, max: 122411043781}\n    estimated metric savings: FCP 0 ms, LCP 0 ms\n    estimated wasted bytes: 77.1 kB\n    example question: How do I decrease the initial loading time of my page?\n    example question: Did anything slow down the request for this document?\n  - insight name: ThirdParties\n    description: 3rd party code can significantly impact load performance. [Reduce and defer loading of 3rd party code](https://developer.chrome.com/docs/performance/insights/third-parties) to prioritize your page's content.\n    relevant trace bounds: {min: 122411037881, max: 122416229595}\n    example question: Which third parties are having the largest impact on my page performance?\n\n## Details on call tree & network request formats:\nInformation on performance traces may contain main thread activity represented as call frames and network requests.\n\nEach call frame is presented in the following format:\n\n'id;eventKey;name;duration;selfTime;urlIndex;childRange;[line];[column];[S]'\n\nKey definitions:\n\n* id: A unique numerical identifier for the call frame. Never mention this id in the output to the user.\n* eventKey: String that uniquely identifies this event in the flame chart.\n* name: A concise string describing the call frame (e.g., 'Evaluate Script', 'render', 'fetchData').\n* duration: The total execution time of the call frame, including its children.\n* selfTime: The time spent directly within the call frame, excluding its children's execution.\n* urlIndex: Index referencing the \"All URLs\" list. Empty if no specific script URL is associated.\n* childRange: Specifies the direct children of this node using their IDs. If empty ('' or 'S' at the end), the node has no children. If a single number (e.g., '4'), the node has one child with that ID. If in the format 'firstId-lastId' (e.g., '4-5'), it indicates a consecutive range of child IDs from 'firstId' to 'lastId', inclusive.\n* line: An optional field for a call frame's line number. This is where the function is defined.\n* column: An optional field for a call frame's column number. This is where the function is defined.\n* S: _Optional_. The letter 'S' terminates the line if that call frame was selected by the user.\n\nExample Call Tree:\n\n1;r-123;main;500;100;0;1;;\n2;r-124;update;200;50;;3;0;1;\n3;p-49575-15428179-2834-374;animate;150;20;0;4-5;0;1;S\n4;p-49575-15428179-3505-1162;calculatePosition;80;80;0;1;;\n5;p-49575-15428179-5391-2767;applyStyles;50;50;0;1;;\n\n\nNetwork requests are formatted like this:\n\\`urlIndex;eventKey;queuedTime;requestSentTime;downloadCompleteTime;processingCompleteTime;totalDuration;downloadDuration;mainThreadProcessingDuration;statusCode;mimeType;priority;initialPriority;finalPriority;renderBlocking;protocol;fromServiceWorker;initiators;redirects:[[redirectUrlIndex|startTime|duration]];responseHeaders:[header1Value|header2Value|...]\\`\n\n- \\`urlIndex\\`: Numerical index for the request's URL, referencing the \"All URLs\" list.\n- \\`eventKey\\`: String that uniquely identifies this request's trace event.\nTimings (all in milliseconds, relative to navigation start):\n- \\`queuedTime\\`: When the request was queued.\n- \\`requestSentTime\\`: When the request was sent.\n- \\`downloadCompleteTime\\`: When the download completed.\n- \\`processingCompleteTime\\`: When main thread processing finished.\nDurations (all in milliseconds):\n- \\`totalDuration\\`: Total time from the request being queued until its main thread processing completed.\n- \\`downloadDuration\\`: Time spent actively downloading the resource.\n- \\`mainThreadProcessingDuration\\`: Time spent on the main thread after the download completed.\n- \\`statusCode\\`: The HTTP status code of the response (e.g., 200, 404).\n- \\`mimeType\\`: The MIME type of the resource (e.g., \"text/html\", \"application/javascript\").\n- \\`priority\\`: The final network request priority (e.g., \"VeryHigh\", \"Low\").\n- \\`initialPriority\\`: The initial network request priority.\n- \\`finalPriority\\`: The final network request priority (redundant if \\`priority\\` is always final, but kept for clarity if \\`initialPriority\\` and \\`priority\\` differ).\n- \\`renderBlocking\\`: 't' if the request was render-blocking, 'f' otherwise.\n- \\`protocol\\`: The network protocol used (e.g., \"h2\", \"http/1.1\").\n- \\`fromServiceWorker\\`: 't' if the request was served from a service worker, 'f' otherwise.\n- \\`initiators\\`: A list (separated by ,) of URL indices for the initiator chain of this request. Listed in order starting from the root request to the request that directly loaded this one. This represents the network dependencies necessary to load this request. If there is no initiator, this is empty.\n- \\`redirects\\`: A comma-separated list of redirects, enclosed in square brackets. Each redirect is formatted as\n\\`[redirectUrlIndex|startTime|duration]\\`, where: \\`redirectUrlIndex\\`: Numerical index for the redirect's URL. \\`startTime\\`: The start time of the redirect in milliseconds, relative to navigation start. \\`duration\\`: The duration of the redirect in milliseconds.\n- \\`responseHeaders\\`: A list (separated by '|') of values for specific, pre-defined response headers, enclosed in square brackets.\nThe order of headers corresponds to an internal fixed list. If a header is not present, its value will be empty.\n\n`;\n"
  },
  {
    "path": "tests/tools/performance.test.ts",
    "content": "/**\n * @license\n * Copyright 2025 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport assert from 'node:assert';\nimport {describe, it, afterEach, beforeEach} from 'node:test';\nimport zlib from 'node:zlib';\n\nimport sinon from 'sinon';\n\nimport {\n  analyzeInsight,\n  startTrace,\n  stopTrace,\n} from '../../src/tools/performance.js';\nimport type {TraceResult} from '../../src/trace-processing/parse.js';\nimport {\n  parseRawTraceBuffer,\n  traceResultIsSuccess,\n} from '../../src/trace-processing/parse.js';\nimport {loadTraceAsBuffer} from '../trace-processing/fixtures/load.js';\nimport {withMcpContext} from '../utils.js';\n\ndescribe('performance', () => {\n  afterEach(() => {\n    sinon.restore();\n  });\n\n  beforeEach(() => {\n    sinon.stub(globalThis, 'fetch').callsFake(async url => {\n      const cruxEndpoint =\n        'https://chromeuxreport.googleapis.com/v1/records:queryRecord';\n      if (url.toString().startsWith(cruxEndpoint)) {\n        return new Response(JSON.stringify(cruxResponseFixture()), {\n          status: 200,\n          headers: {'Content-Type': 'application/json'},\n        });\n      }\n      throw new Error(`Unexpected fetch to ${url}`);\n    });\n  });\n\n  describe('performance_start_trace', () => {\n    it('starts a trace recording', async () => {\n      await withMcpContext(async (response, context) => {\n        context.setIsRunningPerformanceTrace(false);\n        const selectedPage = context.getSelectedPptrPage();\n        const startTracingStub = sinon.stub(selectedPage.tracing, 'start');\n        await startTrace.handler(\n          {\n            params: {reload: true, autoStop: false},\n            page: context.getSelectedMcpPage(),\n          },\n          response,\n          context,\n        );\n        sinon.assert.calledOnce(startTracingStub);\n        assert.ok(context.isRunningPerformanceTrace());\n        assert.ok(\n          response.responseLines\n            .join('\\n')\n            .match(/The performance trace is being recorded/),\n        );\n      });\n    });\n\n    it('can navigate to about:blank and record a page reload', async () => {\n      await withMcpContext(async (response, context) => {\n        const selectedPage = context.getSelectedPptrPage();\n        sinon.stub(selectedPage, 'url').callsFake(() => 'https://www.test.com');\n        const gotoStub = sinon.stub(selectedPage, 'goto');\n        const startTracingStub = sinon.stub(selectedPage.tracing, 'start');\n        await startTrace.handler(\n          {\n            params: {reload: true, autoStop: false},\n            page: context.getSelectedMcpPage(),\n          },\n          response,\n          context,\n        );\n        sinon.assert.calledOnce(startTracingStub);\n        sinon.assert.calledWithExactly(gotoStub, 'about:blank', {\n          waitUntil: ['networkidle0'],\n        });\n        sinon.assert.calledWithExactly(gotoStub, 'https://www.test.com', {\n          waitUntil: ['load'],\n        });\n        assert.ok(context.isRunningPerformanceTrace());\n        assert.ok(\n          response.responseLines\n            .join('\\n')\n            .match(/The performance trace is being recorded/),\n        );\n      });\n    });\n\n    it('can autostop and store a recording', async () => {\n      const rawData = loadTraceAsBuffer('basic-trace.json.gz');\n\n      await withMcpContext(async (response, context) => {\n        const selectedPage = context.getSelectedPptrPage();\n        sinon.stub(selectedPage, 'url').callsFake(() => 'https://www.test.com');\n        sinon.stub(selectedPage, 'goto').callsFake(() => Promise.resolve(null));\n        const startTracingStub = sinon.stub(selectedPage.tracing, 'start');\n        const stopTracingStub = sinon\n          .stub(selectedPage.tracing, 'stop')\n          .callsFake(() => {\n            return Promise.resolve(rawData);\n          });\n\n        const clock = sinon.useFakeTimers();\n        const handlerPromise = startTrace.handler(\n          {\n            params: {reload: true, autoStop: true},\n            page: context.getSelectedMcpPage(),\n          },\n          response,\n          context,\n        );\n        // In the handler we wait 5 seconds after the page load event (which is\n        // what DevTools does), hence we now fake-progress time to allow\n        // the handler to complete. We allow extra time because the Trace\n        // Engine also uses some timers to yield updates and we need those to\n        // execute.\n        await clock.tickAsync(6_000);\n        await handlerPromise;\n        clock.restore();\n\n        sinon.assert.calledOnce(startTracingStub);\n        sinon.assert.calledOnce(stopTracingStub);\n        assert.strictEqual(\n          context.isRunningPerformanceTrace(),\n          false,\n          'Tracing was stopped',\n        );\n        assert.strictEqual(context.recordedTraces().length, 1);\n        assert.ok(\n          response.responseLines\n            .join('\\n')\n            .match(/The performance trace has been stopped/),\n        );\n      });\n    });\n\n    it('errors if a recording is already active', async () => {\n      await withMcpContext(async (response, context) => {\n        context.setIsRunningPerformanceTrace(true);\n        const selectedPage = context.getSelectedPptrPage();\n        const startTracingStub = sinon.stub(selectedPage.tracing, 'start');\n        await startTrace.handler(\n          {\n            params: {reload: true, autoStop: false},\n            page: context.getSelectedMcpPage(),\n          },\n          response,\n          context,\n        );\n        sinon.assert.notCalled(startTracingStub);\n        assert.ok(\n          response.responseLines\n            .join('\\n')\n            .match(/a performance trace is already running/),\n        );\n      });\n    });\n\n    it('supports filePath', async () => {\n      const rawData = loadTraceAsBuffer('basic-trace.json.gz');\n      // rawData is the decompressed buffer (based on loadTraceAsBuffer implementation).\n      // We want to simulate saving it as a .gz file, so the tool should compress it.\n      const expectedCompressedData = zlib.gzipSync(rawData);\n\n      await withMcpContext(async (response, context) => {\n        const filePath = 'test-trace.json.gz';\n        const selectedPage = context.getSelectedPptrPage();\n        sinon.stub(selectedPage, 'url').callsFake(() => 'https://www.test.com');\n        sinon.stub(selectedPage, 'goto').callsFake(() => Promise.resolve(null));\n        sinon.stub(selectedPage.tracing, 'start');\n        sinon.stub(selectedPage.tracing, 'stop').resolves(rawData);\n        const saveFileStub = sinon\n          .stub(context, 'saveFile')\n          .resolves({filename: filePath});\n\n        const handlerPromise = startTrace.handler(\n          {\n            params: {reload: true, autoStop: true, filePath},\n            page: context.getSelectedMcpPage(),\n          },\n          response,\n          context,\n        );\n        // In the handler we wait 5 seconds after the page load event (which is\n        // what DevTools does), hence we now fake-progress time to allow\n        // the handler to complete. We allow extra time because the Trace\n        // Engine also uses some timers to yield updates and we need those to\n        // execute.\n        await handlerPromise;\n\n        assert.ok(\n          response.responseLines.includes(\n            `The raw trace data was saved to ${filePath}.`,\n          ),\n        );\n        sinon.assert.calledOnce(saveFileStub);\n        const [savedData, savedPath] = saveFileStub.firstCall.args;\n        assert.strictEqual(savedPath, filePath);\n        // Compare the saved data with expected compressed data\n        // We can't compare buffers directly with strictEqual easily if they are different instances, but deepStrictEqual works for Buffers.\n        assert.deepStrictEqual(savedData, expectedCompressedData);\n      });\n    });\n  });\n\n  describe('performance_analyze_insight', () => {\n    async function parseTrace(fileName: string): Promise<TraceResult> {\n      const rawData = loadTraceAsBuffer(fileName);\n      const result = await parseRawTraceBuffer(rawData);\n      if (!traceResultIsSuccess(result)) {\n        assert.fail(`Unexpected trace parse error: ${result.error}`);\n      }\n      return result;\n    }\n\n    it('returns the information on the insight', async () => {\n      const trace = await parseTrace('web-dev-with-commit.json.gz');\n      await withMcpContext(async (response, context) => {\n        context.storeTraceRecording(trace);\n        context.setIsRunningPerformanceTrace(false);\n\n        await analyzeInsight.handler(\n          {\n            params: {\n              insightSetId: 'NAVIGATION_0',\n              insightName: 'LCPBreakdown',\n            },\n            page: context.getSelectedMcpPage(),\n          },\n          response,\n          context,\n        );\n\n        assert.ok(response.attachedTracedInsight);\n      });\n    });\n\n    it('returns an error if no trace has been recorded', async () => {\n      await withMcpContext(async (response, context) => {\n        await analyzeInsight.handler(\n          {\n            params: {\n              insightSetId: '8463DF94CD61B265B664E7F768183DE3',\n              insightName: 'LCPBreakdown',\n            },\n            page: context.getSelectedMcpPage(),\n          },\n          response,\n          context,\n        );\n        assert.ok(\n          response.responseLines\n            .join('\\n')\n            .match(\n              /No recorded traces found. Record a performance trace so you have Insights to analyze./,\n            ),\n        );\n      });\n    });\n  });\n\n  describe('performance_stop_trace', () => {\n    it('does nothing if the trace is not running and does not error', async () => {\n      await withMcpContext(async (response, context) => {\n        context.setIsRunningPerformanceTrace(false);\n        const selectedPage = context.getSelectedPptrPage();\n        const stopTracingStub = sinon.stub(selectedPage.tracing, 'stop');\n        await stopTrace.handler(\n          {params: {}, page: context.getSelectedMcpPage()},\n          response,\n          context,\n        );\n        sinon.assert.notCalled(stopTracingStub);\n        assert.strictEqual(context.isRunningPerformanceTrace(), false);\n      });\n    });\n\n    it('will stop the trace and return trace info when a trace is running', async () => {\n      const rawData = loadTraceAsBuffer('basic-trace.json.gz');\n      await withMcpContext(async (response, context) => {\n        context.setIsRunningPerformanceTrace(true);\n        const selectedPage = context.getSelectedPptrPage();\n        const stopTracingStub = sinon\n          .stub(selectedPage.tracing, 'stop')\n          .callsFake(async () => {\n            return rawData;\n          });\n        await stopTrace.handler(\n          {params: {}, page: context.getSelectedMcpPage()},\n          response,\n          context,\n        );\n        assert.ok(\n          response.responseLines.includes(\n            'The performance trace has been stopped.',\n          ),\n        );\n        assert.strictEqual(context.recordedTraces().length, 1);\n        sinon.assert.calledOnce(stopTracingStub);\n      });\n    });\n\n    it('throws an error if parsing the trace buffer fails', async () => {\n      await withMcpContext(async (response, context) => {\n        context.setIsRunningPerformanceTrace(true);\n        const selectedPage = context.getSelectedPptrPage();\n        sinon\n          .stub(selectedPage.tracing, 'stop')\n          .returns(Promise.resolve(undefined));\n\n        await assert.rejects(\n          stopTrace.handler(\n            {params: {}, page: context.getSelectedMcpPage()},\n            response,\n            context,\n          ),\n          /There was an unexpected error parsing the trace/,\n        );\n      });\n    });\n\n    it('supports filePath', async () => {\n      const rawData = loadTraceAsBuffer('basic-trace.json.gz');\n      await withMcpContext(async (response, context) => {\n        const filePath = 'test-trace.json';\n        context.setIsRunningPerformanceTrace(true);\n        const selectedPage = context.getSelectedPptrPage();\n        const stopTracingStub = sinon\n          .stub(selectedPage.tracing, 'stop')\n          .resolves(rawData);\n        const saveFileStub = sinon\n          .stub(context, 'saveFile')\n          .resolves({filename: filePath});\n\n        await stopTrace.handler(\n          {params: {filePath}, page: context.getSelectedMcpPage()},\n          response,\n          context,\n        );\n\n        sinon.assert.calledOnce(stopTracingStub);\n        sinon.assert.calledOnce(saveFileStub);\n        sinon.assert.calledWith(saveFileStub, rawData, filePath);\n        assert.ok(\n          response.responseLines.includes(\n            `The raw trace data was saved to ${filePath}.`,\n          ),\n        );\n      });\n    });\n\n    it('does not fetch CrUX data if performanceCrux is false', async () => {\n      const rawData = loadTraceAsBuffer('basic-trace.json.gz');\n      await withMcpContext(\n        async (response, context) => {\n          context.setIsRunningPerformanceTrace(true);\n          const selectedPage = context.getSelectedPptrPage();\n          sinon.stub(selectedPage.tracing, 'stop').resolves(rawData);\n\n          await stopTrace.handler(\n            {params: {}, page: context.getSelectedMcpPage()},\n            response,\n            context,\n          );\n\n          const cruxEndpoint =\n            'https://chromeuxreport.googleapis.com/v1/records:queryRecord';\n          const cruxCall = (globalThis.fetch as sinon.SinonStub)\n            .getCalls()\n            .find(call => call.args[0].toString().startsWith(cruxEndpoint));\n          assert.strictEqual(\n            cruxCall,\n            undefined,\n            'CrUX fetch should not have been called',\n          );\n        },\n        {performanceCrux: false},\n      );\n    });\n  });\n});\n\nfunction cruxResponseFixture() {\n  // Ideally we could use `mockResponse` from 'chrome-devtools-frontend/front_end/models/crux-manager/CrUXManager.test.ts'\n  // But test files are not published in the cdtf npm package.\n  return {\n    record: {\n      key: {\n        url: 'https://web.dev/',\n      },\n      metrics: {\n        form_factors: {\n          fractions: {desktop: 0.5056, phone: 0.4796, tablet: 0.0148},\n        },\n        largest_contentful_paint: {\n          histogram: [\n            {start: 0, end: 2500, density: 0.7309},\n            {start: 2500, end: 4000, density: 0.163},\n            {start: 4000, density: 0.1061},\n          ],\n          percentiles: {p75: 2595},\n        },\n        largest_contentful_paint_image_element_render_delay: {\n          percentiles: {p75: 786},\n        },\n        largest_contentful_paint_image_resource_load_delay: {\n          percentiles: {p75: 86},\n        },\n        largest_contentful_paint_image_time_to_first_byte: {\n          percentiles: {p75: 1273},\n        },\n        cumulative_layout_shift: {\n          histogram: [\n            {start: '0.00', end: '0.10', density: 0.8665},\n            {start: '0.10', end: '0.25', density: 0.0716},\n            {start: '0.25', density: 0.0619},\n          ],\n          percentiles: {p75: '0.06'},\n        },\n        interaction_to_next_paint: {\n          histogram: [\n            {start: 0, end: 200, density: 0.8414},\n            {start: 200, end: 500, density: 0.1081},\n            {start: 500, density: 0.0505},\n          ],\n          percentiles: {p75: 140},\n        },\n        largest_contentful_paint_image_resource_load_duration: {\n          percentiles: {p75: 451},\n        },\n        round_trip_time: {\n          histogram: [\n            {start: 0, end: 75, density: 0.3663},\n            {start: 75, end: 275, density: 0.5089},\n            {start: 275, density: 0.1248},\n          ],\n          percentiles: {p75: 178},\n        },\n        first_contentful_paint: {\n          histogram: [\n            {start: 0, end: 1800, density: 0.5899},\n            {start: 1800, end: 3000, density: 0.2439},\n            {start: 3000, density: 0.1662},\n          ],\n          percentiles: {p75: 2425},\n        },\n      },\n      collectionPeriod: {\n        firstDate: {year: 2025, month: 12, day: 8},\n        lastDate: {year: 2026, month: 1, day: 4},\n      },\n    },\n  };\n}\n"
  },
  {
    "path": "tests/tools/screencast.test.ts",
    "content": "/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport assert from 'node:assert';\nimport {describe, it, afterEach} from 'node:test';\n\nimport sinon from 'sinon';\n\nimport {startScreencast, stopScreencast} from '../../src/tools/screencast.js';\nimport {withMcpContext} from '../utils.js';\n\nfunction createMockRecorder() {\n  return {\n    stop: sinon.stub().resolves(),\n  };\n}\n\ndescribe('screencast', () => {\n  afterEach(() => {\n    sinon.restore();\n  });\n\n  describe('screencast_start', () => {\n    it('starts a screencast recording with filePath', async () => {\n      await withMcpContext(async (response, context) => {\n        const mockRecorder = createMockRecorder();\n        const selectedPage = context.getSelectedPptrPage();\n        const screencastStub = sinon\n          .stub(selectedPage, 'screencast')\n          .resolves(mockRecorder as never);\n\n        await startScreencast.handler(\n          {\n            params: {path: '/tmp/test-recording.mp4'},\n            page: context.getSelectedMcpPage(),\n          },\n          response,\n          context,\n        );\n\n        sinon.assert.calledOnce(screencastStub);\n        const callArgs = screencastStub.firstCall.args[0];\n        assert.ok(callArgs);\n        assert.ok(callArgs.path?.endsWith('test-recording.mp4'));\n\n        assert.ok(context.getScreenRecorder() !== null);\n        assert.ok(\n          response.responseLines\n            .join('\\n')\n            .includes('Screencast recording started'),\n        );\n      });\n    });\n\n    it('starts a screencast recording with temp file when no filePath', async () => {\n      await withMcpContext(async (response, context) => {\n        const mockRecorder = createMockRecorder();\n        const selectedPage = context.getSelectedPptrPage();\n        const screencastStub = sinon\n          .stub(selectedPage, 'screencast')\n          .resolves(mockRecorder as never);\n\n        await startScreencast.handler(\n          {params: {}, page: context.getSelectedMcpPage()},\n          response,\n          context,\n        );\n\n        sinon.assert.calledOnce(screencastStub);\n        const callArgs = screencastStub.firstCall.args[0];\n        assert.ok(callArgs);\n        assert.ok(callArgs.path?.endsWith('.mp4'));\n        assert.ok(context.getScreenRecorder() !== null);\n      });\n    });\n\n    it('errors if a recording is already active', async () => {\n      await withMcpContext(async (response, context) => {\n        const mockRecorder = createMockRecorder();\n        context.setScreenRecorder({\n          recorder: mockRecorder as never,\n          filePath: '/tmp/existing.mp4',\n        });\n\n        const selectedPage = context.getSelectedPptrPage();\n        const screencastStub = sinon.stub(selectedPage, 'screencast');\n\n        await startScreencast.handler(\n          {params: {}, page: context.getSelectedMcpPage()},\n          response,\n          context,\n        );\n\n        sinon.assert.notCalled(screencastStub);\n        assert.ok(\n          response.responseLines\n            .join('\\n')\n            .includes('a screencast recording is already in progress'),\n        );\n      });\n    });\n\n    it('provides a clear error when ffmpeg is not found', async () => {\n      await withMcpContext(async (response, context) => {\n        const selectedPage = context.getSelectedPptrPage();\n        const error = new Error('spawn ffmpeg ENOENT');\n        sinon.stub(selectedPage, 'screencast').rejects(error);\n\n        await assert.rejects(\n          startScreencast.handler(\n            {\n              params: {path: '/tmp/test.mp4'},\n              page: context.getSelectedMcpPage(),\n            },\n            response,\n            context,\n          ),\n          /ffmpeg is required for screencast recording/,\n        );\n\n        assert.strictEqual(context.getScreenRecorder(), null);\n      });\n    });\n  });\n\n  describe('screencast_stop', () => {\n    it('does nothing if no recording is active', async () => {\n      await withMcpContext(async (response, context) => {\n        assert.strictEqual(context.getScreenRecorder(), null);\n        await stopScreencast.handler(\n          {params: {}, page: context.getSelectedMcpPage()},\n          response,\n          context,\n        );\n        assert.strictEqual(response.responseLines.length, 0);\n      });\n    });\n\n    it('stops an active recording and reports the file path', async () => {\n      await withMcpContext(async (response, context) => {\n        const mockRecorder = createMockRecorder();\n        const filePath = '/tmp/test-recording.mp4';\n        context.setScreenRecorder({\n          recorder: mockRecorder as never,\n          filePath,\n        });\n\n        await stopScreencast.handler(\n          {params: {}, page: context.getSelectedMcpPage()},\n          response,\n          context,\n        );\n\n        sinon.assert.calledOnce(mockRecorder.stop);\n        assert.strictEqual(context.getScreenRecorder(), null);\n        assert.ok(\n          response.responseLines\n            .join('\\n')\n            .includes('stopped and saved to /tmp/test-recording.mp4'),\n        );\n      });\n    });\n\n    it('clears the recorder even if stop() throws', async () => {\n      await withMcpContext(async (response, context) => {\n        const mockRecorder = createMockRecorder();\n        mockRecorder.stop.rejects(new Error('ffmpeg process error'));\n        context.setScreenRecorder({\n          recorder: mockRecorder as never,\n          filePath: '/tmp/test.mp4',\n        });\n\n        await assert.rejects(\n          stopScreencast.handler(\n            {params: {}, page: context.getSelectedMcpPage()},\n            response,\n            context,\n          ),\n          /ffmpeg process error/,\n        );\n\n        assert.strictEqual(context.getScreenRecorder(), null);\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "tests/tools/screenshot.test.ts",
    "content": "/**\n * @license\n * Copyright 2025 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport assert from 'node:assert';\nimport {rm, stat, mkdir, chmod, writeFile} from 'node:fs/promises';\nimport {tmpdir} from 'node:os';\nimport {join} from 'node:path';\nimport {describe, it} from 'node:test';\n\nimport {screenshot} from '../../src/tools/screenshot.js';\nimport {screenshots} from '../snapshot.js';\nimport {html, withMcpContext} from '../utils.js';\n\ndescribe('screenshot', () => {\n  describe('browser_take_screenshot', () => {\n    it('with default options', async () => {\n      await withMcpContext(async (response, context) => {\n        const fixture = screenshots.basic;\n        const page = context.getSelectedPptrPage();\n        await page.setContent(fixture.html);\n        await screenshot.handler(\n          {params: {format: 'png'}, page: context.getSelectedMcpPage()},\n          response,\n          context,\n        );\n\n        assert.equal(response.images.length, 1);\n        assert.equal(response.images[0].mimeType, 'image/png');\n        assert.equal(\n          response.responseLines.at(0),\n          \"Took a screenshot of the current page's viewport.\",\n        );\n      });\n    });\n    it('ignores quality', async () => {\n      await withMcpContext(async (response, context) => {\n        const fixture = screenshots.basic;\n        const page = context.getSelectedPptrPage();\n        await page.setContent(fixture.html);\n        await screenshot.handler(\n          {\n            params: {format: 'png', quality: 0},\n            page: context.getSelectedMcpPage(),\n          },\n          response,\n          context,\n        );\n\n        assert.equal(response.images.length, 1);\n        assert.equal(response.images[0].mimeType, 'image/png');\n        assert.equal(\n          response.responseLines.at(0),\n          \"Took a screenshot of the current page's viewport.\",\n        );\n      });\n    });\n    it('with jpeg', async () => {\n      await withMcpContext(async (response, context) => {\n        await screenshot.handler(\n          {params: {format: 'jpeg'}, page: context.getSelectedMcpPage()},\n          response,\n          context,\n        );\n\n        assert.equal(response.images.length, 1);\n        assert.equal(response.images[0].mimeType, 'image/jpeg');\n        assert.equal(\n          response.responseLines.at(0),\n          \"Took a screenshot of the current page's viewport.\",\n        );\n      });\n    });\n    it('with webp', async () => {\n      await withMcpContext(async (response, context) => {\n        await screenshot.handler(\n          {params: {format: 'webp'}, page: context.getSelectedMcpPage()},\n          response,\n          context,\n        );\n\n        assert.equal(response.images.length, 1);\n        assert.equal(response.images[0].mimeType, 'image/webp');\n        assert.equal(\n          response.responseLines.at(0),\n          \"Took a screenshot of the current page's viewport.\",\n        );\n      });\n    });\n    it('with full page', async () => {\n      await withMcpContext(async (response, context) => {\n        const fixture = screenshots.viewportOverflow;\n        const page = context.getSelectedPptrPage();\n        await page.setContent(fixture.html);\n        await screenshot.handler(\n          {\n            params: {format: 'png', fullPage: true},\n            page: context.getSelectedMcpPage(),\n          },\n          response,\n          context,\n        );\n\n        assert.equal(response.images.length, 1);\n        assert.equal(response.images[0].mimeType, 'image/png');\n        assert.equal(\n          response.responseLines.at(0),\n          'Took a screenshot of the full current page.',\n        );\n      });\n    });\n\n    it('with full page resulting in a large screenshot', async () => {\n      await withMcpContext(async (response, context) => {\n        const page = context.getSelectedPptrPage();\n\n        await page.setContent(\n          html`${`<div style=\"color:blue;\">test</div>`.repeat(6500)}\n            <div\n              id=\"red\"\n              style=\"color:blue;\"\n              >test</div\n            > `,\n        );\n        await page.evaluate(() => {\n          const el = document.querySelector('#red');\n          return el?.scrollIntoViewIfNeeded();\n        });\n\n        await screenshot.handler(\n          {\n            params: {format: 'png', fullPage: true},\n            page: context.getSelectedMcpPage(),\n          },\n          response,\n          context,\n        );\n\n        assert.equal(response.images.length, 0);\n        assert.equal(\n          response.responseLines.at(0),\n          'Took a screenshot of the full current page.',\n        );\n        assert.ok(\n          response.responseLines.at(1)?.match(/Saved screenshot to.*\\.png/),\n        );\n      });\n    });\n\n    it('with element uid', async () => {\n      await withMcpContext(async (response, context) => {\n        const fixture = screenshots.button;\n\n        const page = context.getSelectedPptrPage();\n        await page.setContent(fixture.html);\n        await context.createTextSnapshot(context.getSelectedMcpPage());\n        await screenshot.handler(\n          {\n            params: {\n              format: 'png',\n              uid: '1_1',\n            },\n            page: context.getSelectedMcpPage(),\n          },\n          response,\n          context,\n        );\n\n        assert.equal(response.images.length, 1);\n        assert.equal(response.images[0].mimeType, 'image/png');\n        assert.equal(\n          response.responseLines.at(0),\n          'Took a screenshot of node with uid \"1_1\".',\n        );\n      });\n    });\n\n    it('with filePath', async () => {\n      await withMcpContext(async (response, context) => {\n        const filePath = join(tmpdir(), 'test-screenshot.png');\n        try {\n          const fixture = screenshots.basic;\n          const page = context.getSelectedPptrPage();\n          await page.setContent(fixture.html);\n          await screenshot.handler(\n            {\n              params: {format: 'png', filePath},\n              page: context.getSelectedMcpPage(),\n            },\n            response,\n            context,\n          );\n\n          assert.equal(response.images.length, 0);\n          assert.equal(\n            response.responseLines.at(0),\n            \"Took a screenshot of the current page's viewport.\",\n          );\n          assert.equal(\n            response.responseLines.at(1),\n            `Saved screenshot to ${filePath}.`,\n          );\n\n          const stats = await stat(filePath);\n          assert.ok(stats.isFile());\n          assert.ok(stats.size > 0);\n        } finally {\n          await rm(filePath, {force: true});\n        }\n      });\n    });\n\n    it('with unwritable filePath', async () => {\n      if (process.platform === 'win32') {\n        const filePath = join(\n          tmpdir(),\n          'readonly-file-for-screenshot-test.png',\n        );\n        // Create the file and make it read-only.\n        await writeFile(filePath, '');\n        await chmod(filePath, 0o400);\n\n        try {\n          await withMcpContext(async (response, context) => {\n            const fixture = screenshots.basic;\n            const page = context.getSelectedPptrPage();\n            await page.setContent(fixture.html);\n            await assert.rejects(\n              screenshot.handler(\n                {\n                  params: {format: 'png', filePath},\n                  page: context.getSelectedMcpPage(),\n                },\n                response,\n                context,\n              ),\n            );\n          });\n        } finally {\n          // Make the file writable again so it can be deleted.\n          await chmod(filePath, 0o600);\n          await rm(filePath, {force: true});\n        }\n      } else {\n        const dir = join(tmpdir(), 'readonly-dir-for-screenshot-test');\n        await mkdir(dir, {recursive: true});\n        await chmod(dir, 0o500);\n        const filePath = join(dir, 'test-screenshot.png');\n\n        try {\n          await withMcpContext(async (response, context) => {\n            const fixture = screenshots.basic;\n            const page = context.getSelectedPptrPage();\n            await page.setContent(fixture.html);\n            await assert.rejects(\n              screenshot.handler(\n                {\n                  params: {format: 'png', filePath},\n                  page: context.getSelectedMcpPage(),\n                },\n                response,\n                context,\n              ),\n            );\n          });\n        } finally {\n          await chmod(dir, 0o700);\n          await rm(dir, {recursive: true, force: true});\n        }\n      }\n    });\n\n    it('with malformed filePath', async () => {\n      await withMcpContext(async (response, context) => {\n        // Use a platform-specific invalid character.\n        // On Windows, characters like '<', '>', ':', '\"', '/', '\\', '|', '?', '*' are invalid.\n        // On POSIX, the null byte is invalid.\n        const invalidChar = process.platform === 'win32' ? '>' : '\\0';\n        const filePath = `malformed${invalidChar}path.png`;\n        const fixture = screenshots.basic;\n        const page = context.getSelectedPptrPage();\n        await page.setContent(fixture.html);\n        await assert.rejects(\n          screenshot.handler(\n            {\n              params: {format: 'png', filePath},\n              page: context.getSelectedMcpPage(),\n            },\n            response,\n            context,\n          ),\n        );\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "tests/tools/script.test.ts",
    "content": "/**\n * @license\n * Copyright 2025 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport assert from 'node:assert';\nimport path from 'node:path';\nimport {describe, it} from 'node:test';\n\nimport type {ParsedArguments} from '../../src/bin/chrome-devtools-mcp-cli-options.js';\nimport {installExtension} from '../../src/tools/extensions.js';\nimport {evaluateScript} from '../../src/tools/script.js';\nimport {serverHooks} from '../server.js';\nimport {extractExtensionId, html, withMcpContext} from '../utils.js';\n\nconst EXTENSION_PATH = path.join(\n  import.meta.dirname,\n  '../../../tests/tools/fixtures/extension-sw',\n);\n\ndescribe('script', () => {\n  const server = serverHooks();\n\n  describe('browser_evaluate_script', () => {\n    it('evaluates', async () => {\n      await withMcpContext(async (response, context) => {\n        await evaluateScript().handler(\n          {\n            params: {function: String(() => 2 * 5)},\n          },\n          response,\n          context,\n        );\n        const lineEvaluation = response.responseLines.at(2)!;\n        assert.strictEqual(JSON.parse(lineEvaluation), 10);\n      });\n    });\n    it('runs in selected page', async () => {\n      await withMcpContext(async (response, context) => {\n        await evaluateScript().handler(\n          {\n            params: {function: String(() => document.title)},\n          },\n          response,\n          context,\n        );\n\n        let lineEvaluation = response.responseLines.at(2)!;\n        assert.strictEqual(JSON.parse(lineEvaluation), '');\n\n        const page = await context.newPage();\n        await page.pptrPage.setContent(`\n          <head>\n            <title>New Page</title>\n          </head>\n        `);\n\n        response.resetResponseLineForTesting();\n        await evaluateScript().handler(\n          {\n            params: {function: String(() => document.title)},\n          },\n          response,\n          context,\n        );\n\n        lineEvaluation = response.responseLines.at(2)!;\n        assert.strictEqual(JSON.parse(lineEvaluation), 'New Page');\n      });\n    });\n\n    it('work for complex objects', async () => {\n      await withMcpContext(async (response, context) => {\n        const page = context.getSelectedPptrPage();\n\n        await page.setContent(html`<script src=\"./scripts.js\"></script> `);\n\n        await evaluateScript().handler(\n          {\n            params: {\n              function: String(() => {\n                const scripts = Array.from(\n                  document.head.querySelectorAll('script'),\n                ).map(s => ({src: s.src, async: s.async, defer: s.defer}));\n\n                return {scripts};\n              }),\n            },\n          },\n          response,\n          context,\n        );\n        const lineEvaluation = response.responseLines.at(2)!;\n        assert.deepEqual(JSON.parse(lineEvaluation), {\n          scripts: [],\n        });\n      });\n    });\n\n    it('work for async functions', async () => {\n      await withMcpContext(async (response, context) => {\n        const page = context.getSelectedPptrPage();\n\n        await page.setContent(html`<script src=\"./scripts.js\"></script> `);\n\n        await evaluateScript().handler(\n          {\n            params: {\n              function: String(async () => {\n                await new Promise(res => setTimeout(res, 0));\n                return 'Works';\n              }),\n            },\n          },\n          response,\n          context,\n        );\n        const lineEvaluation = response.responseLines.at(2)!;\n        assert.strictEqual(JSON.parse(lineEvaluation), 'Works');\n      });\n    });\n\n    it('work with one argument', async () => {\n      await withMcpContext(async (response, context) => {\n        const page = context.getSelectedPptrPage();\n\n        await page.setContent(html`<button id=\"test\">test</button>`);\n\n        await context.createTextSnapshot(context.getSelectedMcpPage());\n\n        await evaluateScript().handler(\n          {\n            params: {\n              function: String(async (el: Element) => {\n                return el.id;\n              }),\n              args: ['1_1'],\n            },\n          },\n          response,\n          context,\n        );\n        const lineEvaluation = response.responseLines.at(2)!;\n        assert.strictEqual(JSON.parse(lineEvaluation), 'test');\n      });\n    });\n\n    it('work with multiple args', async () => {\n      await withMcpContext(async (response, context) => {\n        const page = context.getSelectedPptrPage();\n\n        await page.setContent(html`<button id=\"test\">test</button>`);\n\n        await context.createTextSnapshot(context.getSelectedMcpPage());\n\n        await evaluateScript().handler(\n          {\n            params: {\n              function: String((container: Element, child: Element) => {\n                return container.contains(child);\n              }),\n              args: ['1_0', '1_1'],\n            },\n          },\n          response,\n          context,\n        );\n        const lineEvaluation = response.responseLines.at(2)!;\n        assert.strictEqual(JSON.parse(lineEvaluation), true);\n      });\n    });\n\n    it('work for elements inside iframes', async () => {\n      server.addHtmlRoute(\n        '/iframe',\n        html`<main><button>I am iframe button</button></main>`,\n      );\n      server.addHtmlRoute('/main', html`<iframe src=\"/iframe\"></iframe>`);\n\n      await withMcpContext(async (response, context) => {\n        const page = context.getSelectedPptrPage();\n        await page.goto(server.getRoute('/main'));\n        await context.createTextSnapshot(context.getSelectedMcpPage());\n        await evaluateScript().handler(\n          {\n            params: {\n              function: String((element: Element) => {\n                return element.textContent;\n              }),\n              args: ['1_3'],\n            },\n          },\n          response,\n          context,\n        );\n        const lineEvaluation = response.responseLines.at(2)!;\n        assert.strictEqual(JSON.parse(lineEvaluation), 'I am iframe button');\n      });\n    });\n    it('evaluates inside extension service worker', async () => {\n      await withMcpContext(\n        async (response, context) => {\n          await installExtension.handler(\n            {params: {path: EXTENSION_PATH}},\n            response,\n            context,\n          );\n\n          const extensionId = extractExtensionId(response);\n          const swTarget = await context.browser.waitForTarget(\n            t => t.type() === 'service_worker' && t.url().includes(extensionId),\n          );\n\n          await context.createExtensionServiceWorkersSnapshot();\n          const swList = context.getExtensionServiceWorkers();\n          const sw = swList.find(s => s.target === swTarget);\n\n          if (!sw) {\n            assert.fail('Service worker not found in context list');\n          }\n\n          const swId = context.getExtensionServiceWorkerId(sw);\n\n          response.resetResponseLineForTesting();\n          await evaluateScript({\n            categoryExtensions: true,\n          } as ParsedArguments).handler(\n            {\n              params: {\n                function: String(() => {\n                  return 'chrome' in globalThis ? 'has-chrome' : 'no-chrome';\n                }),\n                serviceWorkerId: swId,\n              },\n            },\n            response,\n            context,\n          );\n\n          const lineEvaluation = response.responseLines.at(2)!;\n          assert.strictEqual(JSON.parse(lineEvaluation), 'has-chrome');\n        },\n        {},\n        {categoryExtensions: true} as ParsedArguments,\n      );\n    });\n\n    it('throws error when both pageId and serviceWorkerId are provided', async () => {\n      await withMcpContext(\n        async (response, context) => {\n          await assert.rejects(\n            evaluateScript({\n              categoryExtensions: true,\n            } as ParsedArguments).handler(\n              {\n                params: {\n                  function: String(() => 'test'),\n                  serviceWorkerId: 'example_service_worker',\n                  pageId: '1',\n                },\n              },\n              response,\n              context,\n            ),\n            {\n              message: 'specify either a pageId or a serviceWorkerId.',\n            },\n          );\n        },\n        {},\n        {categoryExtensions: true} as ParsedArguments,\n      );\n    });\n\n    it('throws error when args are provided with serviceWorkerId', async () => {\n      await withMcpContext(\n        async (response, context) => {\n          await assert.rejects(\n            evaluateScript({\n              categoryExtensions: true,\n            } as ParsedArguments).handler(\n              {\n                params: {\n                  function: String(() => 'test'),\n                  serviceWorkerId: 'example_service_worker',\n                  args: ['1_1'],\n                },\n              },\n              response,\n              context,\n            ),\n            {\n              message:\n                'args (element uids) cannot be used when evaluating in a service worker.',\n            },\n          );\n        },\n        {},\n        {categoryExtensions: true} as ParsedArguments,\n      );\n    });\n  });\n});\n"
  },
  {
    "path": "tests/tools/slim/tools.test.js.snapshot",
    "content": "exports[`slim > evaluates 1`] = `\n10\n`;\n\nexports[`slim > handles errors 1`] = `\ntest error\n`;\n\nexports[`slim > navigates to correct page 1`] = `\nNavigated to data:text/html,<div>Hello MCP</div>.\n`;\n"
  },
  {
    "path": "tests/tools/slim/tools.test.ts",
    "content": "/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport assert from 'node:assert';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport {describe, it} from 'node:test';\n\nimport {evaluate, navigate, screenshot} from '../../../src/tools/slim/tools.js';\nimport {screenshots} from '../../snapshot.js';\nimport {withMcpContext} from '../../utils.js';\n\ndescribe('slim', () => {\n  it('evaluates', async t => {\n    await withMcpContext(async (response, context) => {\n      await evaluate.handler(\n        {\n          params: {\n            script: `2 * 5`,\n          },\n          page: context.getSelectedMcpPage(),\n        },\n        response,\n        context,\n      );\n      t.assert.snapshot?.(response.responseLines.join('\\n'));\n    });\n  });\n\n  it('handles errors', async t => {\n    await withMcpContext(async (response, context) => {\n      await evaluate.handler(\n        {\n          params: {\n            script: `throw new Error('test error')`,\n          },\n          page: context.getSelectedMcpPage(),\n        },\n        response,\n        context,\n      );\n      t.assert.snapshot?.(response.responseLines.join('\\n'));\n    });\n  });\n\n  it('navigates to correct page', async t => {\n    await withMcpContext(async (response, context) => {\n      await navigate.handler(\n        {\n          params: {url: 'data:text/html,<div>Hello MCP</div>'},\n          page: context.getSelectedMcpPage(),\n        },\n        response,\n        context,\n      );\n      const page = context.getSelectedPptrPage();\n      assert.equal(\n        await page.evaluate(() => document.querySelector('div')?.textContent),\n        'Hello MCP',\n      );\n      assert(!response.includePages);\n      t.assert.snapshot?.(response.responseLines.join('\\n'));\n    });\n  });\n\n  it('with default options', async () => {\n    await withMcpContext(async (response, context) => {\n      const fixture = screenshots.basic;\n      const page = context.getSelectedPptrPage();\n      await page.setContent(fixture.html);\n      await screenshot.handler(\n        {params: {format: 'png'}, page: context.getSelectedMcpPage()},\n        response,\n        context,\n      );\n      assert(path.isAbsolute(response.responseLines.at(0)!));\n      assert(fs.existsSync(response.responseLines.at(0)!));\n    });\n  });\n});\n"
  },
  {
    "path": "tests/tools/snapshot.test.ts",
    "content": "/**\n * @license\n * Copyright 2025 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport assert from 'node:assert';\nimport {describe, it} from 'node:test';\n\nimport {takeSnapshot, waitFor} from '../../src/tools/snapshot.js';\nimport {html, withMcpContext} from '../utils.js';\n\ndescribe('snapshot', () => {\n  describe('browser_snapshot', () => {\n    it('includes a snapshot', async () => {\n      await withMcpContext(async (response, context) => {\n        await takeSnapshot.handler(\n          {params: {}, page: context.getSelectedMcpPage()},\n          response,\n          context,\n        );\n        assert.ok(response.includeSnapshot);\n      });\n    });\n  });\n  describe('browser_wait_for', () => {\n    it('should work', async () => {\n      await withMcpContext(async (response, context) => {\n        const page = context.getSelectedPptrPage();\n\n        await page.setContent(\n          html`<main><span>Hello</span><span> </span><div>World</div></main>`,\n        );\n        await waitFor.handler(\n          {\n            params: {\n              text: ['Hello'],\n            },\n            page: context.getSelectedMcpPage(),\n          },\n          response,\n          context,\n        );\n\n        assert.equal(\n          response.responseLines[0],\n          'Element matching one of [\"Hello\"] found.',\n        );\n        assert.ok(response.includeSnapshot);\n      });\n    });\n\n    it('should work with any-match array', async () => {\n      await withMcpContext(async (response, context) => {\n        const page = context.getSelectedPptrPage();\n\n        await page.setContent(\n          html`<main><span>Status</span><div>Error</div></main>`,\n        );\n        await waitFor.handler(\n          {\n            params: {\n              text: ['Complete', 'Error'],\n            },\n            page: context.getSelectedMcpPage(),\n          },\n          response,\n          context,\n        );\n\n        assert.equal(\n          response.responseLines[0],\n          'Element matching one of [\"Complete\",\"Error\"] found.',\n        );\n        assert.ok(response.includeSnapshot);\n      });\n    });\n\n    it('should work with any-match array when element shows up later', async () => {\n      await withMcpContext(async (response, context) => {\n        const page = context.getSelectedPptrPage();\n\n        const handlePromise = waitFor.handler(\n          {\n            params: {\n              text: ['Complete', 'Error'],\n            },\n            page: context.getSelectedMcpPage(),\n          },\n          response,\n          context,\n        );\n\n        await page.setContent(\n          html`<main\n            ><span>Hello</span><span> </span><div>Complete</div></main\n          >`,\n        );\n\n        await handlePromise;\n\n        assert.equal(\n          response.responseLines[0],\n          'Element matching one of [\"Complete\",\"Error\"] found.',\n        );\n        assert.ok(response.includeSnapshot);\n      });\n    });\n\n    it('should work with element that show up later', async () => {\n      await withMcpContext(async (response, context) => {\n        const page = context.getSelectedPptrPage();\n\n        const handlePromise = waitFor.handler(\n          {\n            params: {\n              text: ['Hello World'],\n            },\n            page: context.getSelectedMcpPage(),\n          },\n          response,\n          context,\n        );\n\n        await page.setContent(\n          html`<main><span>Hello</span><span> </span><div>World</div></main>`,\n        );\n\n        await handlePromise;\n\n        assert.equal(\n          response.responseLines[0],\n          'Element matching one of [\"Hello World\"] found.',\n        );\n        assert.ok(response.includeSnapshot);\n      });\n    });\n    it('should work with aria elements', async () => {\n      await withMcpContext(async (response, context) => {\n        const page = context.getSelectedPptrPage();\n\n        await page.setContent(\n          html`<main><h1>Header</h1><div>Text</div></main>`,\n        );\n\n        await waitFor.handler(\n          {\n            params: {\n              text: ['Header'],\n            },\n            page: context.getSelectedMcpPage(),\n          },\n          response,\n          context,\n        );\n\n        assert.equal(\n          response.responseLines[0],\n          'Element matching one of [\"Header\"] found.',\n        );\n        assert.ok(response.includeSnapshot);\n      });\n    });\n\n    it('should work with iframe content', async () => {\n      await withMcpContext(async (response, context) => {\n        const page = context.getSelectedPptrPage();\n\n        await page.setContent(\n          html`<h1>Top level</h1>\n            <iframe srcdoc=\"<p>Hello iframe</p>\"></iframe>`,\n        );\n\n        await waitFor.handler(\n          {\n            params: {\n              text: ['Hello iframe'],\n            },\n            page: context.getSelectedMcpPage(),\n          },\n          response,\n          context,\n        );\n\n        assert.equal(\n          response.responseLines[0],\n          'Element matching one of [\"Hello iframe\"] found.',\n        );\n        assert.ok(response.includeSnapshot);\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "tests/trace-processing/fixtures/load.ts",
    "content": "/**\n * @license\n * Copyright 2025 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport zlib from 'node:zlib';\n\n/**\n * Reads a gzipped JSON file, decompresses it, parses the JSON,\n * and returns a Uint8Array buffer of the parsed data.\n * @param filePath The path to the .json.gz file.\n * @returns A Uint8Array containing the stringified JSON data.\n */\nexport function loadTraceAsBuffer(filePath: string): Uint8Array {\n  try {\n    const compressedData = fs.readFileSync(\n      path.join(\n        import.meta.dirname,\n        // Get back up to the root directory as fixtures aren't moved ito the build/ dir.\n        '..',\n        '..',\n        '..',\n        '..',\n        'tests',\n        'trace-processing',\n        'fixtures',\n        filePath,\n      ),\n    );\n    const decompressedData = zlib.gunzipSync(compressedData);\n    const jsonString = decompressedData.toString('utf-8');\n    const jsonObject = JSON.parse(jsonString);\n    const finalBuffer = Buffer.from(JSON.stringify(jsonObject));\n    const uint8Array = new Uint8Array(finalBuffer);\n    return uint8Array;\n  } catch (error) {\n    console.error('Error parsing the file:', error);\n    throw error;\n  }\n}\n"
  },
  {
    "path": "tests/trace-processing/parse.test.js.snapshot",
    "content": "exports[`Trace parsing > can format results of a trace 1`] = `\n## Summary of Performance trace findings:\nURL: https://web.dev/\nTrace bounds: {min: 122410994891, max: 122416385853}\nCPU throttling: none\nNetwork throttling: none\n\n# Available insight sets\n\nThe following is a list of insight sets. An insight set covers a specific part of the trace, split by navigations. The insights within each insight set are specific to that part of the trace. Be sure to consider the insight set id and bounds when calling functions. If no specific insight set or navigation is mentioned, assume the user is referring to the first one.\n\n## insight set id: NAVIGATION_0\n\nURL: https://web.dev/\nBounds: {min: 122410996889, max: 122416385853}\nMetrics (lab / observed):\n  - LCP: 129 ms, event: (eventKey: r-6063, ts: 122411126100), nodeId: 7\n  - LCP breakdown:\n    - TTFB: 8 ms, bounds: {min: 122410996889, max: 122411004828}\n    - Load delay: 33 ms, bounds: {min: 122411004828, max: 122411037986}\n    - Load duration: 15 ms, bounds: {min: 122411037986, max: 122411052690}\n    - Render delay: 73 ms, bounds: {min: 122411052690, max: 122411126100}\n  - CLS: 0.00\nMetrics (field / real users): n/a – no data for this page in CrUX\nAvailable insights:\n  - insight name: LCPBreakdown\n    description: Each [subpart has specific improvement strategies](https://developer.chrome.com/docs/performance/insights/lcp-breakdown). Ideally, most of the LCP time should be spent on loading the resources, not within delays.\n    relevant trace bounds: {min: 122410996889, max: 122411126100}\n    example question: Help me optimize my LCP score\n    example question: Which LCP phase was most problematic?\n    example question: What can I do to reduce the LCP time for this page load?\n  - insight name: LCPDiscovery\n    description: [Optimize LCP](https://developer.chrome.com/docs/performance/insights/lcp-discovery) by making the LCP image discoverable from the HTML immediately, and avoiding lazy-loading\n    relevant trace bounds: {min: 122411004828, max: 122411055039}\n    example question: Suggest fixes to reduce my LCP\n    example question: What can I do to reduce my LCP discovery time?\n    example question: Why is LCP discovery time important?\n  - insight name: RenderBlocking\n    description: Requests are blocking the page's initial render, which may delay LCP. [Deferring or inlining](https://developer.chrome.com/docs/performance/insights/render-blocking) can move these network requests out of the critical path.\n    relevant trace bounds: {min: 122411037528, max: 122411053852}\n    example question: Show me the most impactful render-blocking requests that I should focus on\n    example question: How can I reduce the number of render-blocking requests?\n  - insight name: DocumentLatency\n    description: Your first network request is the most important. [Reduce its latency](https://developer.chrome.com/docs/performance/insights/document-latency) by avoiding redirects, ensuring a fast server response, and enabling text compression.\n    relevant trace bounds: {min: 122410998910, max: 122411043781}\n    estimated metric savings: FCP 0 ms, LCP 0 ms\n    estimated wasted bytes: 77.1 kB\n    example question: How do I decrease the initial loading time of my page?\n    example question: Did anything slow down the request for this document?\n  - insight name: ThirdParties\n    description: 3rd party code can significantly impact load performance. [Reduce and defer loading of 3rd party code](https://developer.chrome.com/docs/performance/insights/third-parties) to prioritize your page's content.\n    relevant trace bounds: {min: 122411037881, max: 122416229595}\n    example question: Which third parties are having the largest impact on my page performance?\n  - insight name: CharacterSet\n    description: A character encoding declaration is required. It can be done with a meta charset tag in the first 1024 bytes of the HTML or in the Content-Type HTTP response header. [Learn more about declaring the character encoding](https://developer.chrome.com/docs/insights/charset/).\n    relevant trace bounds: {min: 122410998910, max: 122411043781}\n    example question: How do I declare a character encoding for my page?\n\n## Details on call tree & network request formats:\nInformation on performance traces may contain main thread activity represented as call frames and network requests.\n\nEach call frame is presented in the following format:\n\n'id;eventKey;name;duration;selfTime;urlIndex;childRange;[line];[column];[S]'\n\nKey definitions:\n\n* id: A unique numerical identifier for the call frame. Never mention this id in the output to the user.\n* eventKey: String that uniquely identifies this event in the flame chart.\n* name: A concise string describing the call frame (e.g., 'Evaluate Script', 'render', 'fetchData').\n* duration: The total execution time of the call frame, including its children.\n* selfTime: The time spent directly within the call frame, excluding its children's execution.\n* urlIndex: Index referencing the \"All URLs\" list. Empty if no specific script URL is associated.\n* childRange: Specifies the direct children of this node using their IDs. If empty ('' or 'S' at the end), the node has no children. If a single number (e.g., '4'), the node has one child with that ID. If in the format 'firstId-lastId' (e.g., '4-5'), it indicates a consecutive range of child IDs from 'firstId' to 'lastId', inclusive.\n* line: An optional field for a call frame's line number. This is where the function is defined.\n* column: An optional field for a call frame's column number. This is where the function is defined.\n* S: _Optional_. The letter 'S' terminates the line if that call frame was selected by the user.\n\nExample Call Tree:\n\n1;r-123;main;500;100;0;1;;\n2;r-124;update;200;50;;3;0;1;\n3;p-49575-15428179-2834-374;animate;150;20;0;4-5;0;1;S\n4;p-49575-15428179-3505-1162;calculatePosition;80;80;0;1;;\n5;p-49575-15428179-5391-2767;applyStyles;50;50;0;1;;\n\n\nNetwork requests are formatted like this:\n\\`urlIndex;eventKey;queuedTime;requestSentTime;downloadCompleteTime;processingCompleteTime;totalDuration;downloadDuration;mainThreadProcessingDuration;statusCode;mimeType;priority;initialPriority;finalPriority;renderBlocking;protocol;fromServiceWorker;initiators;redirects:[[redirectUrlIndex|startTime|duration]];responseHeaders:[header1Value|header2Value|...]\\`\n\n- \\`urlIndex\\`: Numerical index for the request's URL, referencing the \"All URLs\" list.\n- \\`eventKey\\`: String that uniquely identifies this request's trace event.\nTimings (all in milliseconds, relative to navigation start):\n- \\`queuedTime\\`: When the request was queued.\n- \\`requestSentTime\\`: When the request was sent.\n- \\`downloadCompleteTime\\`: When the download completed.\n- \\`processingCompleteTime\\`: When main thread processing finished.\nDurations (all in milliseconds):\n- \\`totalDuration\\`: Total time from the request being queued until its main thread processing completed.\n- \\`downloadDuration\\`: Time spent actively downloading the resource.\n- \\`mainThreadProcessingDuration\\`: Time spent on the main thread after the download completed.\n- \\`statusCode\\`: The HTTP status code of the response (e.g., 200, 404).\n- \\`mimeType\\`: The MIME type of the resource (e.g., \"text/html\", \"application/javascript\").\n- \\`priority\\`: The final network request priority (e.g., \"VeryHigh\", \"Low\").\n- \\`initialPriority\\`: The initial network request priority.\n- \\`finalPriority\\`: The final network request priority (redundant if \\`priority\\` is always final, but kept for clarity if \\`initialPriority\\` and \\`priority\\` differ).\n- \\`renderBlocking\\`: 't' if the request was render-blocking, 'f' otherwise.\n- \\`protocol\\`: The network protocol used (e.g., \"h2\", \"http/1.1\").\n- \\`fromServiceWorker\\`: 't' if the request was served from a service worker, 'f' otherwise.\n- \\`initiators\\`: A list (separated by ,) of URL indices for the initiator chain of this request. Listed in order starting from the root request to the request that directly loaded this one. This represents the network dependencies necessary to load this request. If there is no initiator, this is empty.\n- \\`redirects\\`: A comma-separated list of redirects, enclosed in square brackets. Each redirect is formatted as\n\\`[redirectUrlIndex|startTime|duration]\\`, where: \\`redirectUrlIndex\\`: Numerical index for the redirect's URL. \\`startTime\\`: The start time of the redirect in milliseconds, relative to navigation start. \\`duration\\`: The duration of the redirect in milliseconds.\n- \\`responseHeaders\\`: A list (separated by '|') of values for specific, pre-defined response headers, enclosed in square brackets.\nThe order of headers corresponds to an internal fixed list. If a header is not present, its value will be empty.\n\n`;\n"
  },
  {
    "path": "tests/trace-processing/parse.test.ts",
    "content": "/**\n * @license\n * Copyright 2025 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport assert from 'node:assert';\nimport {describe, it} from 'node:test';\n\nimport {\n  getTraceSummary,\n  parseRawTraceBuffer,\n} from '../../src/trace-processing/parse.js';\n\nimport '../../src/DevtoolsUtils.js';\n\nimport {loadTraceAsBuffer} from './fixtures/load.js';\n\ndescribe('Trace parsing', async () => {\n  it('can parse a Uint8Array from Tracing.stop())', async () => {\n    const rawData = loadTraceAsBuffer('basic-trace.json.gz');\n    const result = await parseRawTraceBuffer(rawData);\n    if ('error' in result) {\n      assert.fail(`Unexpected parse failure: ${result.error}`);\n    }\n    assert.ok(result?.parsedTrace);\n    assert.ok(result?.insights);\n  });\n\n  it('can format results of a trace', async t => {\n    const rawData = loadTraceAsBuffer('web-dev-with-commit.json.gz');\n    const result = await parseRawTraceBuffer(rawData);\n    if ('error' in result) {\n      assert.fail(`Unexpected parse failure: ${result.error}`);\n    }\n    assert.ok(result?.parsedTrace);\n    assert.ok(result?.insights);\n\n    const output = getTraceSummary(result);\n    t.assert.snapshot?.(output);\n  });\n\n  it('will return a message if there is an error', async () => {\n    const result = await parseRawTraceBuffer(undefined);\n    assert.deepEqual(result, {\n      error: 'No buffer was provided.',\n    });\n  });\n});\n"
  },
  {
    "path": "tests/utils.ts",
    "content": "/**\n * @license\n * Copyright 2025 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport assert from 'node:assert';\n\nimport type {CallToolResult} from '@modelcontextprotocol/sdk/types.js';\nimport logger from 'debug';\nimport type {Browser} from 'puppeteer';\nimport puppeteer, {Locator} from 'puppeteer';\nimport type {\n  Frame,\n  HTTPRequest,\n  HTTPResponse,\n  LaunchOptions,\n  Page,\n} from 'puppeteer-core';\nimport sinon from 'sinon';\n\nimport type {ParsedArguments} from '../src/bin/chrome-devtools-mcp-cli-options.js';\nimport {McpContext} from '../src/McpContext.js';\nimport {McpResponse} from '../src/McpResponse.js';\nimport {stableIdSymbol} from '../src/PageCollector.js';\nimport {DevTools} from '../src/third_party/index.js';\n\nexport function getTextContent(\n  content: CallToolResult['content'][number],\n): string {\n  if (content.type === 'text') {\n    return content.text;\n  }\n  throw new Error(`Expected text content but got ${content.type}`);\n}\n\nexport function getImageContent(content: CallToolResult['content'][number]): {\n  data: string;\n  mimeType: string;\n} {\n  if (content.type === 'image') {\n    return {data: content.data, mimeType: content.mimeType};\n  }\n  throw new Error(`Expected image content but got ${content.type}`);\n}\n\nexport function extractExtensionId(response: McpResponse) {\n  const responseLine = response.responseLines[0];\n  assert.ok(responseLine, 'Response should not be empty');\n  const match = responseLine.match(/Extension installed\\. Id: (.+)/);\n  const extensionId = match ? match[1] : null;\n  assert.ok(extensionId, 'Response should contain a valid key');\n  return extensionId;\n}\n\nconst browsers = new Map<string, Browser>();\nlet context: McpContext | undefined;\n\nexport async function withBrowser(\n  cb: (browser: Browser, page: Page) => Promise<void>,\n  options: {\n    debug?: boolean;\n    autoOpenDevTools?: boolean;\n    executablePath?: string;\n  } = {},\n) {\n  const launchOptions: LaunchOptions = {\n    executablePath:\n      options.executablePath ?? process.env.PUPPETEER_EXECUTABLE_PATH,\n    headless: !options.debug,\n    defaultViewport: null,\n    devtools: options.autoOpenDevTools ?? false,\n    pipe: true,\n    handleDevToolsAsPage: true,\n    args: ['--screen-info={3840x2160}'],\n    enableExtensions: true,\n  };\n  const key = JSON.stringify(launchOptions);\n\n  let browser = browsers.get(key);\n  if (!browser) {\n    browser = await puppeteer.launch(launchOptions);\n    browsers.set(key, browser);\n  }\n  const newPage = await browser.newPage();\n  // Close other pages.\n  await Promise.all(\n    (await browser.pages()).map(async page => {\n      if (page !== newPage) {\n        await page.close();\n      }\n    }),\n  );\n\n  await cb(browser, newPage);\n}\n\nexport async function withMcpContext(\n  cb: (response: McpResponse, context: McpContext) => Promise<void>,\n  options: {\n    debug?: boolean;\n    autoOpenDevTools?: boolean;\n    performanceCrux?: boolean;\n    executablePath?: string;\n  } = {},\n  args: ParsedArguments = {} as ParsedArguments,\n) {\n  await withBrowser(async browser => {\n    const response = new McpResponse(args);\n    if (context) {\n      context.dispose();\n    }\n    context = await McpContext.from(\n      browser,\n      logger('test'),\n      {\n        experimentalDevToolsDebugging: false,\n        performanceCrux: options.performanceCrux ?? true,\n      },\n      Locator,\n    );\n\n    response.setPage(context.getSelectedMcpPage());\n\n    await cb(response, context);\n  }, options);\n}\n\nexport function getMockRequest(\n  options: {\n    url?: string;\n    method?: string;\n    response?: HTTPResponse;\n    failure?: HTTPRequest['failure'];\n    resourceType?: string;\n    hasPostData?: boolean;\n    postData?: string;\n    fetchPostData?: Promise<string>;\n    stableId?: number;\n    navigationRequest?: boolean;\n    frame?: Frame;\n    redirectChain?: HTTPRequest[];\n  } = {},\n): HTTPRequest {\n  return {\n    url() {\n      return options.url ?? 'http://example.com';\n    },\n    method() {\n      return options.method ?? 'GET';\n    },\n    fetchPostData() {\n      return options.fetchPostData ?? Promise.reject();\n    },\n    hasPostData() {\n      return options.hasPostData ?? false;\n    },\n    postData() {\n      return options.postData;\n    },\n    response() {\n      return options.response ?? null;\n    },\n    failure() {\n      return options.failure?.() ?? null;\n    },\n    resourceType() {\n      return options.resourceType ?? 'document';\n    },\n    headers(): Record<string, string> {\n      return {\n        'content-size': '10',\n      };\n    },\n    redirectChain(): HTTPRequest[] {\n      return options.redirectChain ?? [];\n    },\n    isNavigationRequest() {\n      return options.navigationRequest ?? false;\n    },\n    frame() {\n      return options.frame ?? ({} as Frame);\n    },\n    [stableIdSymbol]: options.stableId ?? 1,\n  } as unknown as HTTPRequest;\n}\n\nexport function getMockResponse(\n  options: {\n    status?: number;\n  } = {},\n): HTTPResponse {\n  return {\n    status() {\n      return options.status ?? 200;\n    },\n    headers(): Record<string, string> {\n      return {};\n    },\n  } as HTTPResponse;\n}\n\nexport function html(\n  strings: TemplateStringsArray,\n  ...values: unknown[]\n): string {\n  const bodyContent = strings.reduce((acc, str, i) => {\n    return acc + str + (values[i] || '');\n  }, '');\n\n  return `<!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>My test page</title>\n  </head>\n  <body>\n    ${bodyContent}\n  </body>\n</html>`;\n}\n\nexport function stabilizeStructuredContent(content: unknown): unknown {\n  if (typeof content === 'string') {\n    return stabilizeResponseOutput(content);\n  }\n  if (Array.isArray(content)) {\n    return content.map(item => stabilizeStructuredContent(item));\n  }\n  if (typeof content === 'object' && content !== null) {\n    const result: Record<string, unknown> = {};\n    for (const [key, value] of Object.entries(content)) {\n      if (key === 'snapshotFilePath' && typeof value === 'string') {\n        result[key] = '<file>';\n      } else {\n        result[key] = stabilizeStructuredContent(value);\n      }\n    }\n    return result;\n  }\n  return content;\n}\n\nexport function stabilizeResponseOutput(text: unknown) {\n  if (typeof text !== 'string') {\n    throw new Error('Input must be string');\n  }\n  let output = text;\n  const dateRegEx = /.{3}, \\d{2} .{3} \\d{4} \\d{2}:\\d{2}:\\d{2} [A-Z]{3}/g;\n  output = output.replaceAll(dateRegEx, '<long date>');\n\n  const localhostRegEx = /localhost:\\d{5}/g;\n  output = output.replaceAll(localhostRegEx, 'localhost:<port>');\n\n  const userAgentRegEx = /user-agent:.*\\n/g;\n  output = output.replaceAll(userAgentRegEx, 'user-agent:<user-agent>\\n');\n\n  const chUaRegEx = /sec-ch-ua:\"Chromium\";v=\"\\d{3}\"/g;\n  output = output.replaceAll(chUaRegEx, 'sec-ch-ua:\"Chromium\";v=\"<version>\"');\n\n  // sec-ch-ua-platform:\"Linux\"\n  const chUaPlatformRegEx = /sec-ch-ua-platform:\"[a-zA-Z]*\"/g;\n  output = output.replaceAll(chUaPlatformRegEx, 'sec-ch-ua-platform:\"<os>\"');\n\n  const savedSnapshot = /Saved snapshot to (.*)/g;\n  output = output.replaceAll(savedSnapshot, 'Saved snapshot to <file>');\n\n  const acceptLanguageRegEx = /accept-language:.*\\n/g;\n  output = output.replaceAll(acceptLanguageRegEx, 'accept-language:<lang>\\n');\n\n  return output;\n}\n\nexport function getMockAggregatedIssue(): sinon.SinonStubbedInstance<DevTools.AggregatedIssue> {\n  const mockAggregatedIssue = sinon.createStubInstance(\n    DevTools.AggregatedIssue,\n  );\n  mockAggregatedIssue.getAllIssues.returns([]);\n  return mockAggregatedIssue;\n}\n\nexport function mockListener() {\n  const listeners: Record<string, Array<(data: unknown) => void>> = {};\n  return {\n    on(eventName: string, listener: (data: unknown) => void) {\n      if (listeners[eventName]) {\n        listeners[eventName].push(listener);\n      } else {\n        listeners[eventName] = [listener];\n      }\n    },\n    off(_eventName: string, _listener: (data: unknown) => void) {\n      // no-op\n    },\n    emit(eventName: string, data: unknown) {\n      for (const listener of listeners[eventName] ?? []) {\n        listener(data);\n      }\n    },\n  };\n}\n\nexport function getMockPage(): Page {\n  const mainFrame = {} as Frame;\n  const cdpSession = {\n    ...mockListener(),\n    send: () => {\n      // no-op\n    },\n    target: () => ({_targetId: '<mock target ID>'}),\n  };\n  return {\n    mainFrame() {\n      return mainFrame;\n    },\n    ...mockListener(),\n    // @ts-expect-error internal API.\n    _client() {\n      return cdpSession;\n    },\n  } satisfies Page;\n}\n\nexport function getMockBrowser(): Browser {\n  const pages = [getMockPage()];\n  return {\n    pages() {\n      return Promise.resolve(pages);\n    },\n    ...mockListener(),\n  } as Browser;\n}\n"
  },
  {
    "path": "tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"target\": \"es2023\",\n    \"lib\": [\n      \"ES2023\",\n      \"DOM\",\n      \"ES2024.Promise\",\n      \"ESNext.Iterator\",\n      \"ESNext.Collection\"\n    ],\n    \"module\": \"esnext\",\n    \"moduleResolution\": \"bundler\",\n    \"outDir\": \"./build\",\n    \"rootDir\": \".\",\n    \"strict\": true,\n    \"esModuleInterop\": true,\n    \"skipLibCheck\": true,\n    \"forceConsistentCasingInFileNames\": true,\n    \"noImplicitReturns\": true,\n    \"noImplicitOverride\": true,\n    \"noFallthroughCasesInSwitch\": true,\n    \"incremental\": true,\n    \"allowJs\": true,\n    \"useUnknownInCatchVariables\": false\n  },\n  \"include\": [\n    \"src/**/*.ts\",\n    \"tests/**/*.ts\",\n    \"node_modules/chrome-devtools-frontend/front_end/core/common\",\n    \"node_modules/chrome-devtools-frontend/front_end/core/host\",\n    \"node_modules/chrome-devtools-frontend/front_end/core/i18n\",\n    \"node_modules/chrome-devtools-frontend/front_end/core/platform\",\n    \"node_modules/chrome-devtools-frontend/front_end/core/protocol_client\",\n    \"node_modules/chrome-devtools-frontend/front_end/core/root\",\n    \"node_modules/chrome-devtools-frontend/front_end/core/sdk\",\n    \"node_modules/chrome-devtools-frontend/front_end/entrypoints/formatter_worker\",\n    \"node_modules/chrome-devtools-frontend/front_end/foundation/foundation.ts\",\n    \"node_modules/chrome-devtools-frontend/front_end/foundation/Universe.ts\",\n    \"node_modules/chrome-devtools-frontend/front_end/generated\",\n    \"node_modules/chrome-devtools-frontend/front_end/legacy/legacy-defs.d.ts\",\n    \"node_modules/chrome-devtools-frontend/front_end/models/annotations\",\n    \"node_modules/chrome-devtools-frontend/front_end/models/ai_assistance/data_formatters/NetworkRequestFormatter.ts\",\n    \"node_modules/chrome-devtools-frontend/front_end/models/ai_assistance/data_formatters/PerformanceInsightFormatter.ts\",\n    \"node_modules/chrome-devtools-frontend/front_end/models/ai_assistance/data_formatters/PerformanceTraceFormatter.ts\",\n    \"node_modules/chrome-devtools-frontend/front_end/models/ai_assistance/data_formatters/UnitFormatters.ts\",\n    \"node_modules/chrome-devtools-frontend/front_end/models/ai_assistance/performance\",\n    \"node_modules/chrome-devtools-frontend/front_end/models/greendev\",\n    \"node_modules/chrome-devtools-frontend/front_end/models/bindings\",\n    \"node_modules/chrome-devtools-frontend/front_end/models/cpu_profile\",\n    \"node_modules/chrome-devtools-frontend/front_end/models/crux-manager\",\n    \"node_modules/chrome-devtools-frontend/front_end/models/emulation\",\n    \"node_modules/chrome-devtools-frontend/front_end/models/formatter\",\n    \"node_modules/chrome-devtools-frontend/front_end/models/geometry\",\n    \"node_modules/chrome-devtools-frontend/front_end/models/issues_manager\",\n    \"node_modules/chrome-devtools-frontend/front_end/models/logs\",\n    \"node_modules/chrome-devtools-frontend/front_end/models/network_time_calculator\",\n    \"node_modules/chrome-devtools-frontend/front_end/models/source_map_scopes\",\n    \"node_modules/chrome-devtools-frontend/front_end/models/stack_trace\",\n    \"node_modules/chrome-devtools-frontend/front_end/models/text_utils\",\n    \"node_modules/chrome-devtools-frontend/front_end/models/trace_source_maps_resolver\",\n    \"node_modules/chrome-devtools-frontend/front_end/models/trace\",\n    \"node_modules/chrome-devtools-frontend/front_end/models/workspace\",\n    \"node_modules/chrome-devtools-frontend/front_end/panels/issues/IssueAggregator.ts\",\n    \"node_modules/chrome-devtools-frontend/front_end/third_party/acorn\",\n    \"node_modules/chrome-devtools-frontend/front_end/third_party/codemirror\",\n    \"node_modules/chrome-devtools-frontend/front_end/third_party/i18n\",\n    \"node_modules/chrome-devtools-frontend/front_end/third_party/intl-messageformat\",\n    \"node_modules/chrome-devtools-frontend/front_end/third_party/legacy-javascript\",\n    \"node_modules/chrome-devtools-frontend/front_end/third_party/marked\",\n    \"node_modules/chrome-devtools-frontend/front_end/third_party/source-map-scopes-codec\",\n    \"node_modules/chrome-devtools-frontend/front_end/third_party/third-party-web\",\n    \"node_modules/chrome-devtools-frontend/mcp\"\n  ],\n  \"exclude\": [\"node_modules/chrome-devtools-frontend/**/*.test.ts\"],\n  \"files\": [\n    \"node_modules/chrome-devtools-frontend/front_end/third_party/acorn/package/dist/acorn.mjs\"\n  ]\n}\n"
  }
]